我想知道下面的伪代码是如何工作的?如果有一个有效的示例,我将不胜感激。
data want;
do until (last.var1);
do until (last.var2);
set have;
* other sas statements;
end;
end;
run;
最佳答案
基本上,单个 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;
这是正常的数据步骤:
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;
这是美国国防部:
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;
请注意,第一次迭代和最后一次迭代的结果略有不同,并且输出不同的行。这是因为 SAS 在第一种方法中自动为我们完成所有这些工作,而 DoW 循环您必须自己完成(您必须在其中放置一个 OUTPUT 语句,例如,如果您想要全部 8 个,则必须测试 EOF 和 STOP`(如果为 true)。
但也许这就是您想要的 - 您希望一开始没有任何值(value),然后您想做点什么。这就是 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;
同样,这里存在差异,因为 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;
不过,大多数情况下,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;
要在没有 Double DoW 循环的情况下执行此操作,您必须将第一个 want
的结果合并回 have
。这不一定是什么大问题,但这是数据的第二次传递; Double DoW 循环利用缓冲来避免实际重新执行第二次读入的 I/O。
关于loops - SAS中嵌套道循环的解释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45615466/