试图仅为特定变量(条件)保留非缺失值(如果有)

时间:2014-11-19 17:49:50

标签: sas

我的数据是这样的

testA       testB       testC
XYZ          1          
XYZ          2           ABC
XYZ          3
XYZ          4           BCA
XYZ          5
ZYX          2
ZYX          3           LMN
ZYX          4
ZYX          5
YZX          1
YZX          2

对于每个唯一值(first.testA),我想获取testB的最小值的缺失值testB.But,如果没有非缺失值。我只想让它有第一行对于那个组合。换句话说,我希望我的最终结果看起来像这样

XYZ          2           ABC
ZYX          3           LMN
YZX          1

我确实得到了我想要的使用datastep和宏编程,但它非常紊乱和乏味,因为我有很多变量我想做这个。我想知道是否有更简单的方法

dataset test001;

 proc sort data=test001;    by testA testB testC;    run;
 proc sort data=test001 nodupkey ;  by testA;  run;

data test002;
set test001;
if missing(testC) then output missing001;  
run;

data test003;  
merge test001    
  missing001;  
by testA;  
run;  

proc sort data=test001;  by testA testB testC;  run;  
proc sort data=test001 nodupkey ;  by testA;  run;  

1 个答案:

答案 0 :(得分:0)

在这里,你需要的是有效的两次数据传递:一个用于识别id-groups(testA组),它们有一个有用的testC行,另一个用于获取那些没有&#的第一行39;吨

在数据步骤中,有两种方法可以立即呈现给我。如果您对此更加满意,PROC SQL也可以轻松实现这一目标。

最简单的方法是创建一个从未拥有testC记录的记录的数据集,然后将其合并回主数据集。这看起来与你正在做的很接近,但这种方式要快一点。

proc sort data=have;
  by testa testb;
run;

data have_notestC;
  set have;
  by testA;
  if first.testA then testCcount = 0;        *for each testA group reinitialize the counter;
  if not missing(testC) then testCcount+1;   *if you see a testC then update counter;
  if last.testA and testCcount=0 then output;*if counter=0 then you never hit testC;
run;

data want;
  merge have have_notestC(in=_ntc);
  by testA;
  if first.testA then testCcount=0;            *reinitialize counter;
  if _ntc and first.testA then output;         *if it was a _ntc record then it has no testC;
  else if _ntc then delete;                    *if not first.testA and _ntc then uninteresting;
  else if testCcount = 0 and not missing(testC) then do;
    testCcount+1;                              *if testCcount=0 and testC is present then you want it;
    output;
  end;
                                               *otherwise ignore;
run;

更有效但更困难的方法是双DoW循环。它反映了合并解决方案,但是在一个datastep中完成。它的效率更高,因为两次传递数据都是在磁盘读取中完成的,假设您的BY组大小足够小 - 如果值全部在一起,则无需排序即可完成#&# 39;但不一定按字母顺序排列(如您的数据在上面 - YZX在ZYX之后,但每个testA值的所有行都是连续的。)

data want;
  testCcount=0;
  hasOutput=0;
  do _n_ = 1 by 1 until (last.testA);
    set have;
    by testA notsorted;
    if not missing(testC) then testCcount=1;
  end;
  do _n_= 1 by 1 until (last.testA);
    set have;
    by testA notsorted;
    if first.testA and testCcount=0 then output;
    else if testCcount=0 then delete;
    else if hasOutput=0 and not missing(testC) then do;
      output;
      hasOutput=1;
    end;
  end;
run;

如果你有许多你正在使用的变量,这些都不一定能让你很容易处理事情,虽然DoW循环版本可以为多个变量运行(但不容易作为宏运行,因为你需要为您要添加的每个变量在多个位置更改内容。我并不完全清楚如何通过众多变量来实现这一目标'无论如何(因为输出是一个基于行的东西),但它可以根据细节进行调整。