美文网首页
关于proc report过程步运行机制问题——对比data步

关于proc report过程步运行机制问题——对比data步

作者: 生物统计与SAS研究员 | 来源:发表于2021-02-18 09:58 被阅读0次

本文结论是结合相关文档和一些测试得出或者推测出来的,欢迎各位大神指正。

proc report过程步实际上是调用了其他过程步引擎完成的report操作,其中包括了univariate,means来制作各种统计数据,应该也包括了data步的引擎(compute的部分,包括运行机制上),甚至是sql的内容(只是觉得define中的某些地方和sql语句的语法有点像)。

为了方便说话,我们先对一些概念做规定。在处理数据的时候,我们都需要对数据进行聚合处理,sql里的group by语句就是这个作用,当然在data步还可以用retain处理简单的这种需求。根据group by语句中变量的不同,结果也会不同,我们把group by语句中不同变量产生的数据定义为不同的级别

1、对于没有用group by语句的我们称为无级别。无级别的数据就是原始的数据,没有经过任何聚合。

2、对于全表被聚合成一条的,我们称为全表级。比如一个表有两列,一列姓名,一列分数。记录了全年级学生期中总分,我们把这个表变成一个一行的数据,记录的是全年级期中总分的年级平均分。这样的数据就是全表级的聚合。

3、其他使用group by语句进行的聚合都是变量级

一、整体上report的运行机制

整体上report过程步分为3大阶段。

1、评估阶段(Evaluation)——后文称编译阶段

这个阶段内,SAS会读入你的代码并进行评估,然后为后面的步骤做准备,总之非常像data步中的编译阶段,所以后面我也希望称这个阶段为编译阶段

2、设置阶段(Setup Phase)

这个阶段SAS会读入数据集,然后根据编译阶段的分析,把数据集送到相关的univariate过程步或者means过程步中,生成summary数据。在这个阶段,可能会有多种聚合的方式,从而也会有多个数据集生成。全表级,无级别,变量级,甚至多个变量级的数据集可能同时存在。比如生成的表格中你可能需要按班级、性别两个变量聚合,来看各个班的不同性别的平均分(变量级),但同时在每个班级后你还要加一条“这个班级整体的平均分”(变量级)。

这样就相当于 proc report 要同时调用两次过程步,比如:

(1)

proc univariate data=indata noprint;

var mark;

by class sex;

output out=outdata mean=mean;

run;

(2)

proc univariate data=indata noprint;

var mark;

by class;

output out=outdata mean=mean;

run;

所以当这个阶段的时候,proc report过程步实际上是在内存中存储了一个或多个备用的数据集的。这些数据集是生成最终结果的数据源,我们后面将称这些数据集为SP数据集(即Setup Phase)。

3、行报告阶段(Report Row Phase)

在行报告阶段 proc report 会逐行的生成数据集,然后再以生成的数据集为基础生成报告结果。请注意结果是逐行的,而且和data步不同的是,report中的各行是不一样的,因为report在某些情况下需要在列表中插入汇总行(比如break,rbreak,coupute before\after语句)。

所以在生成最终数据集的时候,report过程步会根据各个行的级别,来决定从哪个SP数据集中导入数据,不同的行可能要读取不同级别的SP数据集。

这个过程有点像data步中的set语句,但他和set语句有几点区别:

1、set语句一般情况下只是导入指定的数据集,没有比较复杂的代码指令,不会灵活的根据需要选择读入的数据集。但report过程步的导入,会先确定该行是哪个级别的,选择对应的SP数据集。

2、set语句中变量的顺序是数据集原有顺序或者在代码中变量出现的先后顺序。在report过程步中,是语句column列出变量的顺序。

3、set语句中的变量默认都是“retain”的(这可以从双set语句中验证),report中column列出的变量都会预先置空。

4、set语句不会输出自动变量,诸如 _ERROR_ 这样的变量。但是report过程步会输出自动变量 _BREAK_ ,该变量用来指示该行是用什么变量聚合而成的。

          ( A.)  如果该 行 是report 的主体,换句话说:聚合该 行 的变量是在 define中用group定义的,或者define中没有group,那么 _BREAK_ 为缺失。

        (B) 如果该 行 是那种“总结行”,换句话说:聚合该 行 的变量是在 compute after/before XXX,break after/before XXX,这类的语句中规定的,那么 _BREAK_ 的值为 compute或break中指定的变量名

        (C) 如果该 行 是全表级的,换句话说:代码中含有  rbreak  ,compute after/before (后面不指定变量名),则 _BREAK_ 的值为“_RBREAK_”。

二、与data步的比较

report和data步的部分异同在上面已经做了一点总结,下面我们更深入的分析:

1、程序的执行顺序

在data步中,除了部分语句是在编译阶段或PDV阶段完成后执行的以外,基本上都是逐行的,按照从上到下,从左到右的顺序执行的。

但是在report过程步中,执行的顺序是以变量为单位,按照column语句中排列的变量顺序执行的。在行报告阶段,SAS在逐行进行操作的时候,会先从column语句中最左边的变量开始,确定变量后,去找对应的define的内容(这意味着define的顺序不决定执行顺序),如果是有compute语句,那么会执行compute语句。

但是需要注意的是执行的顺序首先是行,然后是变量,然后是具体的compute语句。这就意味着,compute内中出现的变量,如果在column中的排序位于当前变量的右边,那么在执行compute中语句的时候,处于右边的变量还没有被赋值(因为变量是按column中从左到右顺序执行的)

另外值得一提的是,语句 “compute 变量” 的执行顺序是在语句 “compute after/before” 前面的,不论before和after后面加不加变量都是如此。粗体字意味着两点:

            第一、并非 总结行 只执行 “compute after/before” ,而 普通行 只执行 “compute 变量”。两者并不是各执行各的,而是在总结行两者都会执行。

            第二、执行顺序可能出乎很多人意料。估计会有人认为,before——>compute——>after 这个顺序更合理。但事实是:compute——>before/after。

            第三、因为在某一给定的之中,要不他是before的要不是after的,所以before和after之间是不涉及先后顺序问题的。同样道理,before和after后面是否有变量也不涉及顺序问题。

            第四、break和rbreak语句的作用

所以执行逻辑是:

1、根据编译阶段的结果,确定属于哪类的行。进而决定从哪个数据集导入数据。

2、从目标数据集中导入column列表中第一个变量的值。

3、执行 compute 语句

4、执行 compute before/after 语句(如果有)

5、导入第二个变量,重复2-4步,直到所有变量都导入完成

6、进入下一行的确认,重复第1-5步,直到整个数据集完成。

最后就是,line语句的执行顺序是在所有语句之后。

2、report中的retain变量

在data步中,我们可以用retain语句防止变量在PDV中被清空。在report中也有类似的设计,如果一个变量不出现在column中,那么他就是retain的。

proc report data=sashelp.class;

column sex name,n per;

  define sex/group;

  define per/computed;

compute per;

  if name.n ne . then per=name.n/num;

endcomp;

compute before;

  num=name.n;

endcomp;

run;

上例中,num就是一个retain变量。他不在column中出现,但是在compute中被赋值。所以他不会在任何设置阶段生成的数据集中,因此也不会随着行的变化而变化。这个例子是为了得到不同性别的人数占比,里面有2个“name.n”,他们都是表示数据集里的同一列,但是在执行“compute before”的时候,处理的行是全表级,所以在这一行里“name.n”是所有name的个数。但是在执行“compute per”的时候,处理的是“sex变量级的”(总结行除外),所以在这里name.n的值是相应sex内的人数。之所以要写“ if name.n ne . then per=。。。。”,是因为compute比compute before先执行,此时的num还是缺失,所以会报一个缺失值的note。

3、report中的 first点 与 last点

和data步里的“first.变量”与“last.变量”相类似,report里也有类似的功能就是 “compute before/after 变量”,换句话说

if first.变量 then 语句 

的功能和

compute before 变量;

语句

endcomp;

是一样的。

相关文章

网友评论

      本文标题:关于proc report过程步运行机制问题——对比data步

      本文链接:https://www.haomeiwen.com/subject/nkzyxltx.html