2015-10-05 51 views
0

我对SAS非常陌生,并试图学习最佳做法。我试图编写一个简单的宏来挑选特定数据集中缺少值的任何给定字段。我们的想法是遍历每条记录(行),并让do(for)循环充当if语句中的OR。我的问题是SAS宏不通过整个数据集

  1. 我的理解是宏观 - 曾称,应该在我的数据集的每一行来执行,但在这种情况下,它似乎只进行一次执行它(也就是只做循环似乎执行一次而不是100次)。
  2. 有没有更好的方法来做到这一点?

    /* 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; 
    

回答

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; 

这是如此简单的包装成宏可能是浪费时间。

+0

你能用数字开始一个宏变量吗? – Reeza

+0

Reeza - 号你为什么问? – Tom

+0

我以为iiVarName是在数据块内部,SAS会将​​它解释为数据集中的一个变量。也就是说,我没有检查“iiVarName”==“,而是数据集中”iiVarName“名称下的记录为空或不是。但是阶梯显然不是真的。 – adjfac

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也将自动排除casewise失踪大多数统计特效或者它需要在默认情况下,所以你可能不需要这个数据。

+0

感谢您的反馈!我实际上想要输出任何缺少数据的行(以确定它们是什么)。我想我的主要问题是,在我的原代码中,如果我用%%替换%if语句%put%else%(即,以任一方式打印),我希望能看到100次输出,因为我有100在我的数据行。但事实是,当我这样做时,我只能看到%打印输出一次 - 你知道为什么(或者我做错了什么)? – adjfac

+0

@adjfac简而言之,SAS执行宏语句并在执行任何数据步骤代码之前计算出您生成的数据步骤代码*。它不会为数据步骤的每次迭代再次运行宏语句 - 仅由宏语句生成的数据步骤代码。 – user667489