我是SAS的新手,并尝试学习做事的最佳做法。我试着编写一个简单的宏来挑选出特定数据集中缺少值的任何给定字段。我们的想法是遍历每个记录(行)并让do(for)循环在if语句中充当OR。我的问题是
有更好的方法吗?
/* say I have a dataset with fieldA fieldB fieldC fieldD etc. and 100 records, some of which were missing */
%let varList = fieldA fieldB; /* check fieldA and fieldB */
%ReportIncompleteFields(sasdata.myDAta, &varList., work.tempData);
%macro ReportIncompleteFields(inDataName, chkVars, outDataName);
%let numVars = %sysfunc(countw(&chkVars.));
length keepRrd 8;
keepRcd = 0;
data &outDataName.;
set &inDataName.;
%do ii = 1 %to &numVars.;
%let iiVarName = %scan(&chkVars., &ii.);
%if &iiVarName. = '' %then keepRcd=keepRcd+1;
%end;
%if keepRcd=0 %then delete;
run;
%mend ReportIncompleteFields;
答案 0 :(得分:2)
这里的问题是不了解宏代码的作用。宏代码最常见的用途是生成SAS代码。您的宏逻辑不会生成任何SAS代码。
考虑你的第一个宏代码块:
%do ii = 1 %to &numVars.;
%let iiVarName = %scan(&chkVars., &ii.);
%if &iiVarName. = '' %then keepRcd=keepRcd+1;
%end;
值& iiVarName将是宏变量CHKVARS中列出的变量之一的名称。那就是像FieldA这样的字符串。该字符串永远不会等于彼此相邻的两个单引号。所以%THEN子句永远不会生成任何代码。即使您确实将''
作为CHKVARS中的变量名称之一传递,也会生成的代码缺少表示赋值语句结束所需的分号。数字1后面的分号将标记%IF语句的结尾。
第二个%IF语句%if keepRcd=0 %then delete;
也可能永远不会成立,因为字母流keepRcd
永远不会等于数字0
。
因此,如果您的目标是仅保留缺少所列字段的记录,则只需使用CMISS()函数即可。例如,该程序将输入数据集分成GOOD和BAD数据集。
data good bad ;
set have ;
if 0=cmiss(of fieldA fieldB) then output good;
else output bad;
run;
如此简单地将其包装成宏可能是浪费时间。
答案 1 :(得分:1)
SAS数据步骤充当循环,您根本不需要宏逻辑,最多只需要一个数组。查找nmiss / cmiss或missing()函数。关键是要确保你的变量都是相同的类型,或者声明两个数组一个用于数字,一个用于字符数据。这假设所有变量都具有相同的类型。如果该假设不成立,则创建两个参数,一个用于列出字符一个变量,另一个用于数字并扩展逻辑。
%macro ReportIncompleteFields(inDataName, chkVars, outDataName);
data &outDataName.;
set &inDataName.;
array check(*) &chkVars;
if nmiss(of check(*))=0;*keep all variables with no records missing;
run;
%mend ReportIncompleteFields;
我不确定这是为了什么,但SAS也会自动排除大多数统计过程中的案例缺失数据或默认情况下所需的数据,因此您可能不需要这样做。