【问题标题】:SAS: Creating dummy variables from categorical variableSAS:从分类变量创建虚拟变量
【发布时间】:2016-07-15 12:24:22
【问题描述】:

我想转如下长数据集:

data test;
input Id Injury $;
datalines;
1         Ankle
1         Shoulder 
2         Ankle
2         Head
3         Head
3         Shoulder
;
run;

进入一个看起来像这样的宽数据集:

ID  Ankle Shoulder Head
1   1     1        0
2   1     0        1
3   0     1        1'

这个答案似乎最相关,但在 proc freq 阶段失败了(我的真实数据集大约有 100 万条记录,并且有大约 30 种伤害类型): Creating dummy variables from multiple strings in the same row

其他帮助:https://communities.sas.com/t5/SAS-Statistical-Procedures/Possible-to-create-dummy-variables-with-proc-transpose/td-p/235140

感谢您的帮助!

【问题讨论】:

  • 一百万条长格式记录对于 SAS 来说应该是微不足道的。你能解释一下它是如何“倒下”的吗?

标签: sas


【解决方案1】:

这是一个基本的方法,即使有几百万条记录也应该很容易工作。 首先对数据进行排序,然后添加计数以创建 1 变量。接下来,您使用PROC TRANSPOSE 将数据从长翻转到宽。然后用 0 填充缺失值。这是一种完全动态的方法,无论您拥有多少不同的伤害类型或每人有多少记录都无关紧要。还有其他方法可能代码更短,但我认为这很简单,易于理解并在需要时进行修改。

data test;
input Id Injury $;
datalines;
1         Ankle
1         Shoulder 
2         Ankle
2         Head
3         Head
3         Shoulder
;
run;

proc sort data=test;
by id injury;
run;

data test2;
set test;
count=1;
run;

proc transpose data=test2 out=want prefix=Injury_;
by id;
var count;
id injury;
idlabel injury;
run;

data want;
set want;
array inj(*) injury_:;

do i=1 to dim(inj);
    if inj(i)=. then inj(i) = 0;
end;

drop _name_ i;
run;

【讨论】:

  • 这个答案很完美,很简单!
【解决方案2】:

这是一个只涉及两个步骤的解决方案...只需确保您的数据首先按 id 排序(伤害列不需要排序)。

首先,创建一个包含伤害列表的宏变量

proc sql noprint;  
  select distinct injury  
    into :injuries separated by " "  
    from have  
    order by injury;  
quit;  

那么,让RETAIN 施展魔法吧——无需换位!

data want(drop=i injury);
  set have;
  by id;

  format &injuries 1.;
  retain &injuries;
  array injuries(*) &injuries;

  if first.id then do i = 1 to dim(injuries);
    injuries(i) = 0;
  end;

  do i = 1 to dim(injuries); 
    if injury = scan("&injuries",i) then injuries(i) = 1;
  end;

  if last.id then output;
run;

编辑

根据 OP 在 cmets 中提出的问题,以下是我们如何使用代码和标签来表示伤害。它可以直接在最后一个数据步骤中使用label 语句完成,但为了尽量减少硬编码,我假设标签被输入到 sas 数据集中。

1 - 定义标签:

data myLabels;
  infile datalines dlm="|" truncover;
  informat injury $12. labl $24.;
  input injury labl;
  datalines;
S460|Acute meniscal tear, medial
S520|Head trauma
;

2 - 向现有 proc sql 步骤添加新查询以准备标签分配。

proc sql noprint;  

  /* Existing query */
  select distinct injury  
    into :injuries separated by " "  
    from have  
    order by injury;

  /* New query */
  select catx("=",injury,quote(trim(labl)))
    into :labls separated by " "
    from myLabels;
quit;

3 - 然后,在data want 步骤的末尾,添加一个label 语句。

data want(drop=i injury);
  set have;
  by id;

  /* ...same as before... */

  * Add labels;
  label &labls;
run;

应该这样做!

【讨论】:

  • 而不是第二个 do 循环考虑使用临时数组,然后使用 WHICHC 函数。您可以在第一个 SQL 步骤中使用引用函数来获取引用列表。还有……如果伤处有空隙,比如断臂怎么办?
  • 在第一步和第二步中将injury 替换为prxchange("s/[', ]/_/", -1, strip(injury)) 应该可以解决变量名问题。我真的不明白你的意思:使用whichc 和其他数组...
  • 有没有一种方法可以使用这种方法轻松地将标签分配给列?我可能会使用伤害代码,比如“S460”。并为变量“急性半月板撕裂,内侧”分配一个标签。这很容易使用带有 'idlabel' 的 proc transpose 方法完成。
猜你喜欢
  • 2013-04-14
  • 2017-10-23
  • 1970-01-01
  • 2011-03-24
  • 2020-05-13
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 2015-08-17
相关资源
最近更新 更多