SAS 宏没有遍历整个数据集
SAS Macro not going through the entire dataset
我是 SAS 的新手,正在努力学习做事的最佳实践。我尝试编写一个简单的宏来挑选特定数据集中具有缺失值的任何给定字段。这个想法是遍历每个记录(行)并让 do(for) 循环充当 if 语句中的 OR。我的问题是
- 我的理解是宏一旦被调用,就应该为我数据集中的每一行执行,但在这种情况下,它似乎只执行一次(也就是说,do 循环似乎只执行一次而不是 100 次)。
有更好的方法吗?
/* 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;
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 也会自动排除大多数统计过程中的个案缺失数据或默认情况下需要的数据,因此您可能不需要这个。
这里的问题是不理解宏代码的作用。宏代码最常见的用途是生成 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
.
因此,如果您的目标是只保留 none 所列字段缺失的记录,那么只需使用 CMISS() 函数即可。例如,此程序会将输入数据集分为好数据集和坏数据集。
data good bad ;
set have ;
if 0=cmiss(of fieldA fieldB) then output good;
else output bad;
run;
如此简单,将它包装成一个宏可能是在浪费时间。
我是 SAS 的新手,正在努力学习做事的最佳实践。我尝试编写一个简单的宏来挑选特定数据集中具有缺失值的任何给定字段。这个想法是遍历每个记录(行)并让 do(for) 循环充当 if 语句中的 OR。我的问题是
- 我的理解是宏一旦被调用,就应该为我数据集中的每一行执行,但在这种情况下,它似乎只执行一次(也就是说,do 循环似乎只执行一次而不是 100 次)。
有更好的方法吗?
/* 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;
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 也会自动排除大多数统计过程中的个案缺失数据或默认情况下需要的数据,因此您可能不需要这个。
这里的问题是不理解宏代码的作用。宏代码最常见的用途是生成 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
.
因此,如果您的目标是只保留 none 所列字段缺失的记录,那么只需使用 CMISS() 函数即可。例如,此程序会将输入数据集分为好数据集和坏数据集。
data good bad ;
set have ;
if 0=cmiss(of fieldA fieldB) then output good;
else output bad;
run;
如此简单,将它包装成一个宏可能是在浪费时间。