不开玩笑,你可能真对 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。
在
这篇文章里,我们提到,若存在 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 还完成了第二次赋值。

