替换缺失SAS

时间:2014-11-11 14:35:29

标签: sql sas

我有两张桌子:

data a;
input a b c;
datalines;
1 2 .
;
run;

data b;
input a b c;
datalines;
1 . 3
;
run;

我想从这些表中得到的结果是用缺少的值替换缺失:

a b c
-----
1 2 3

我怎么能用更少的代码来做呢?

编辑: 我编写了代码并且它有效,但可能有更简单的代码。

%macro x;
%macro dummy; %mend dummy;
    data _null_;
        set x end=Last;
        call symputx("name"||left(_N_),name);
        if Last then call symputx("num",_n_);
    run;

    data c;
        set a b;
    run;

    data c;
        set c;
        %do i=1 %to #
            x&i=lag(&&name&i);
        %end;
        n=_n_;
    run;

    data c1 (drop= n %do i=1 %to # x&i %end;);
        set c (where=(n=2));
        %do i=1 %to #
            if missing(&&name&i) and not missing(x&i) then &&name&i=x&i;
        %end;
    run;
%mend;
%x;

3 个答案:

答案 0 :(得分:3)

如果值一致,即您从未拥有:

1 2 3
1 3 .

和/或很高兴他们被覆盖,然后UPDATE非常适合这个。

data c;
  update a b;
  by a;
run;

UPDATE只会替换具有非缺失值的值,因此.会被3替换,但2不会被.替换。假设a是Gordon假设的ID变量。

您也可以轻松地执行此操作:

data c;
  set a b;
  by a;
  retain b_1 c_1;
  if first.a then do;  *save the first b and c;
    b_1=b;
    c_1=c;
  end;
  else do;             *now fill in missings using COALESCE which only replaces if missing;
    b_1=coalesce(b_1,b);  *use coalescec if this is a char var;
    c_1=coalesce(c_1,c);  *same;
  end;
  if last.a then output;  *output last row;
  drop b c;
  rename
    b_1=b
    c_1=c
  ;
run;

这确保您保留任何特定值的第一个实例,如果它们可能不同(与保留 last 实例的update相反)与具体采用MAX的SQL解决方案不同。如果您只有相同的值,则所有三个都应该给出相同的结果。我希望数据步骤选项应该比SQL选项快一点,因为它们都是一次通过解决方案而不需要匹配(尽管它可能并不重要)。

答案 1 :(得分:1)

使用proc SQL,您可以通过聚合执行此操作:

proc sql;
    select max(a) as a, max(b) as b, max(c) as c
    from (select a, b, c from a union all
          select a, b, c from b
         ) x;

如果我怀疑第一列是匹配这两个表的id,那么你应该这样做:

proc sql;
    select coalesce(a.a, b.a), coalesce(a.b, b.b) as b, coalesce(a.c, b.c) as c
    from a full join
         b
         on a.a = b.a;

答案 2 :(得分:1)

我将在这里发布如何使用一些细节来处理你的方法:我不认为这是最好的方法,但你可以从你拥有的东西开始更轻松地学习,这不是一个可怕的当然接近 - 只是不是最优的。

开始:

%macro x;
%macro dummy; %mend dummy;
    data _null_;
        set x end=Last;
        call symputx("name"||left(_N_),name);
        if Last then call symputx("num",_n_);
    run;

    data c;
        set a b;
    run;

    data c;  *NOTE 1;
        set c;
        %do i=1 %to #
            x&i=lag(&&name&i);  *NOTE 2;
        %end;
        n=_n_;
    run;

    data c1 (drop= n %do i=1 %to # x&i %end;);   *NOTE 3;
        set c (where=(n=2));
        %do i=1 %to #
            if missing(&&name&i) and not missing(x&i) then &&name&i=x&i;
        %end;
    run;
%mend;
%x;

结局:

*You can still do the first datastep to figure out the dimensions of the arrays, 
 if you want, use &num instead of the 3s hardcoded in there (but do not need &name list).;

data c;
  set a(in=in_a) b(in=in_b);
  array x[3] _temporary_;   *NOTE 4;
  array var[3] a b c;
  do i = 1 to dim(x);       *NOTE 5;
    x[i] = lag(vars[i]);
  end;
  if in_b then do;          *NOTE 6;
    do i=1 to dim(x);
      if missing(vars[i]) then vars[i]=x[i];  *NOTE 7;
    end;
    output;
  end;
run;

注意:

注意1:您可以在这里组合两个c datasteps,完全没有区别。通常只有尽可能少的数据步骤,因为它们很慢 - 这与用于内存处理的R或类似物不同,在SAS中你使用磁盘处理,这对于处理200GB数据的能力很好但不是像这样的多个步骤快速 - 所以减少步骤。

注2:这基本上是数组的宏实现。 SAS datastep已经有了一个阵列!使用它。

注3:你不需要这样做。只要你的真实变量都不以drop=n x:开头,x就可以正常工作(如果它们这样做,在所有虚拟变量之前使用_并且它们将是相同的)。 :是'开头'的外卡。

注4:这是x数组的数组实现。我使用temporary,因为这意味着变量将自动为您删除。

注5:这里我们做了滞后。我不喜欢使用lagretain在同一事情上做得更好,但效果很好。

注意6:此if in_b与您的if last类似。这仅识别b中的记录 - 如果只有一个记录,那么它只会发生一次。

注7:这是替换缺失的。 COALESCE \ COALESCEC也可以用于此目的(但在某些情况下,如果您不确定变量类型,则可能需要使用此方法)。没有理由检查if not missing,除非您以某种方式使用特殊的遗漏 - 用.替换.没有任何害处。