我有两张桌子:
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;
答案 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:这里我们做了滞后。我不喜欢使用lag
,retain
在同一事情上做得更好,但效果很好。
注意6:此if in_b
与您的if last
类似。这仅识别b
中的记录 - 如果只有一个记录,那么它只会发生一次。
注7:这是替换缺失的。 COALESCE
\ COALESCEC
也可以用于此目的(但在某些情况下,如果您不确定变量类型,则可能需要使用此方法)。没有理由检查if not missing
,除非您以某种方式使用特殊的遗漏 - 用.
替换.
没有任何害处。