我想知道下面的伪代码是如何工作的?如果有一个有效的例子,我很感激。
data want;
do until (last.var1);
do until (last.var2);
set have;
* other sas statements;
end;
end;
run;
Run Code Online (Sandbox Code Playgroud)
基本上,单个 DoW 循环可让您在每个循环后按可变边界执行特定操作,并且与正常数据步骤的时序略有不同(这可能有用,也可能无用)。所以给定这个集合::
data have;
input x y z;
datalines;
1 1 1
1 1 2
1 2 1
1 2 2
2 1 1
2 1 2
2 2 1
2 2 2
;;;;
run;
Run Code Online (Sandbox Code Playgroud)
这是正常的数据步骤:
data want;
set have;
by x;
if first.x then do;
put "First value of " x=;
end;
put _all_;
if last.x then do;
put "Last value of " x=;
end;
run;
Run Code Online (Sandbox Code Playgroud)
这是 DoW:
data want_dow;
put "First value of " x=;
do _n_ = 1 by 1 until (last.x);
set have;
by x;
put _all_;
end;
put "Last value of " x=;
run;
Run Code Online (Sandbox Code Playgroud)
请注意,它的结果略有不同 - 对于第一次迭代和最后一次迭代,它输出不同的行。那是因为 SAS 在第一种方法中自动为我们做所有这些事情,而 DoW 循环你必须自己做(你必须OUTPUT在那里放一条语句,例如,如果你想要全部 8,你必须测试EOF and如果为真则STOP`)。
但也许这就是你想要的——你想要没有价值,然后你想做点什么。这就是 DoW 循环有用的时候。
嵌套的 DoW 循环是相同的,只是有两个不同的点可以采取行动。请注意,它实际上并没有改变读取行的方式:每次遇到该set语句时,都会从数据集中读取下一行(无论该行是什么)。同样的顺序,只是你有更多的停止点让你编写代码。
data want;
set have;
by x y;
if first.x then do;
put "First value of " x=;
end;
if first.y then do;
put "First value of " y=;
end;
put _all_;
if last.y then do;
put "Last value of " y=;
end;
if last.x then do;
put "Last value of " x=;
end;
run;
data want_dow;
put "First value of " x=;
do _n_ = 1 by 1 until (last.x);
put "First value of " y=;
do _n_ = 1 by 1 until (last.y);
set have;
by x y;
put _all_;
end;
put "Last value of " y=;
end;
put "Last value of " x=;
run;
Run Code Online (Sandbox Code Playgroud)
同样,您在这里有不同之处,因为 DoW 循环“首先”在读取第一行之前采取行动 - 这又可能有帮助,也可能没有帮助,具体取决于您的用例。我不认为我曾经有过这样的用例,但这当然不是不可能的。
这是一个有用的案例,例如,您基本上是PROC MEANS手工制作的。当然,这两种方式都可以做到;有些人会更喜欢每一个。
data want_dow;
do _n_ = 1 by 1 until (last.x);
do _n_ = 1 by 1 until (last.y);
set have;
by x y;
z_sum_y = sum(z_sum_y,z);
z_sum_x = sum(z_sum_x,z);
end;
z_sum = z_sum_y;
output;
call missing(z_sum_y);
end;
call missing(y);
z_sum = z_sum_x;
output;
drop z_sum_y z_sum_x;
run;
data want;
set have;
by x y;
z_sum_y+z;
z_sum_x+z;
if last.y then do;
z_sum = z_sum_y;
output;
z_sum_y=0;
end;
if last.x then do;
z_sum = z_sum_x;
call missing(y);
output;
z_sum_x=0;
end;
drop z_sum_y z_sum_x;
run;
Run Code Online (Sandbox Code Playgroud)
不过,大多数情况下,DoW 循环对 Double DoW 循环最有用,这对于汇总然后在同一数据步迭代中读取汇总值很有用。这是相同的汇总,但允许您查看当前行上的值。如果您想查看差异,请将 have 中的 Z 值更改为其他值(我有意将它们设置为模式中的 1/2,以便更容易检查)。
data want_ddow;
array z_sum_ys[2] _temporary_;
do _n_ = 1 by 1 until (last.x);
do _n_ = 1 by 1 until (last.y);
set have;
by x y;
z_sum_ys[y] = sum(z_sum_ys[y],z);
z_sum_x = sum(z_sum_x,z);
end;
end;
do _n_ = 1 by 1 until (last.x); *do not need nesting here;
set have;
by x y;
z_sum_y = z_sum_ys[y];
output;
end;
call missing(of z_sum_ys[*] z_sum_x);
run;
Run Code Online (Sandbox Code Playgroud)
要在没有 Double DoW 循环的情况下做到这一点,您必须将第一个的结果合并want到have. 这不一定是一个大问题,但它是对数据的第二次传递;Double DoW 循环利用缓冲来避免实际重新执行第二次读入的 I/O。