欢迎光临散文网 会员登陆 & 注册

不开玩笑,你可能真对 subsetting if 有误解

2021-08-29 12:26 作者:陆震同学  | 我要投稿

不是我是标题党,你可能真的对 subsetting if 有误解。

quiz

现有四行数据,如下:

想实现:根据第一列 name 决定是否读取后两列内容,只读取 name 为 ruth 的行数据,如何操作?

厘清思路

如果这四行数据是来自于 SAS dataset,自然,我们可以直接使用 where、if。二者差别也很明显,where 作用于数据被读入 PDV 之前,提前对数据集进行筛选,SAS 无需读入全部输入数据集观测进入 PDV,从而更为有效地控制读取效率,if 则对 PDV 中数据筛选,无法提前控制。说点题外的,由此引发了,若 variable 为 data step 后续创建,where 中无法引用该变量,而 if 可以。

而这里的 quiz 要求,此四行数据来自 external file that contains raw data。

PDV 黑盒子? 这篇文章里,我们提到,若存在 input statement,SAS compiler 会创建 input buffer 及 PDV,相信大家都还没忘记。

明确的一点是:当存在 input 时,where 无法作用于 external raw input data 进行观测的筛选,但是,if 仍然可以对 PDV 中数据筛选。牢记这一点,可以避免一些错误。

ok,第一个障碍解决了。既然是这样,那我这么写你看对不对?

data want;
   infile datalines;
   input employee_name $ @;
   if employee_name= "ruth" then input age 7-8 idnum 10-11;
   datalines;
ruth  39 11
Jose  32 22
Sue   30 33
John  40 44
   ;
run;
proc print; run;

逻辑上似乎没啥问题,quiz 只要求 ruth 那一行,为什么结果是这样?

结果显示得很直接了,上面的 if 只控制了 age 和 idnum 的读取与否,并未实现行观测的筛选,这一点要特别注意!要想实现根据 employee_name 筛选行观测,怎么办,用下面的:

data want;
   infile datalines;
   input employee_name $ @;
   if employee_name= "ruth";
   input age 7-8 idnum 10-11;
   datalines;
ruth  39 11
Jose  32 22
Sue   30 33
John  40 44
   ;
run;
proc print; run;

大家都看出来了,其实这里的 if 是个 subsetting if statement。我这里要重点强调下 subsetting if 的逻辑:若 if 后条件为真,继续处理该行观测,否则,停止处理该行观测且该行观测不会被写入输出数据集,并直接返回 data step 开始处进行下一次循环。

结合上面 code。若 employee_name 不是 ruth,后续的一切 statement 都不会被执行,且该行观测不被入选,SAS 直接跳转到下一行数据的循环处理之中;只有 ruth 那行数据满足条件,进行后续的操作。因而满足 quiz 的要求。

讲到这你以为就结束了么??

细节

我们看各种 SAS instructions,总会被提示:subsetting if 相当于 if condition then output,不要告诉我你不是这么理解的。

这种等价是不是真的完全成立呢?如果你认为成立,那么问题来了:按照 output 的规则,output 之后生成或改变的变量值不会被写入输出数据集,也就是说,最终输出数据集中,age 和 idnum 根本就不会有值,应该都是缺失值!因为 compile phase 虽然创建了包含 input 中变量的 PDV,但 execution phase 时,第二个 input 是在 subsetting if 之后完成给变量 age 和 idnum 赋值。

但是,你看:

data want;
   infile datalines;
   input employee_name $ @;
   if employee_name= "ruth";
   input age 7-8 idnum 10-11;
   idnum= 1000;
   datalines;
ruth  39 11
Jose  32 22
Sue   30 33
John  40 44
   ;
run;
proc print; run;

不仅和 output 的规则相背,甚至 idnum 还完成了第二次赋值。

所以,要提醒大家,subsetting if 相当于 if condition then output 只是一种效果的类比,并非是真正意义上的等价。这就是我刚才为什么要重点强调 subsetting if 的逻辑的原因了。你在理解 subsetting if 的时候,要做的不仅仅是理解它的效果,更要理解它背后的原理,其实它是决定 data step 是否终止掉当次循环并跳转入下一次,而非直接 output,它所实现的输出功能其实还是 data step 本身所隐含的 implicit output 所实现的。


不开玩笑,你可能真对 subsetting if 有误解的评论 (共 条)

分享到微博请遵守国家法律