【问题标题】:SAS Macro not going through the entire datasetSAS 宏没有遍历整个数据集
【发布时间】:2015-10-05 20:19:20
【问题描述】:

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

  1. 我的理解是,宏一旦被调用,就应该为我的数据集中的每一行执行一次,但在这种情况下,它似乎只执行一次(也就是说,do 循环似乎只执行一次而不是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;
    

【问题讨论】:

    标签: macros sas


    【解决方案1】:

    这里的问题是不理解宏代码的作用。宏代码最常见的用途是生成 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;
    

    把它包装成一个宏太简单了,可能是浪费时间。

    【讨论】:

    • 可以用数字开头的宏变量吗?
    • Reeza - 不。你为什么这么问?
    • 我认为由于 iiVarName 在数据块内,SAS 会将其解释为数据集中的变量。也就是说,我没有检查“iiVarName”=='',而是数据集中“iiVarName”名称下的记录是否为空。但天梯显然不是真的。
    【解决方案2】:

    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 还会自动从大多数统计过程中或默认情况下排除按案例缺失的数据,因此您可能不需要它。

    【讨论】:

    • 感谢您的反馈!我实际上想输出任何缺少数据的行(以识别它们是什么)。我想我的主要问题是,在我的原始代码中,如果我用 %if %put %else %put 替换 %if 语句(也就是说,打印任何一种方式),我希望看到输出 100 次,因为我有 100我的数据中的行。但事实是,当我这样做时,我只看到 %put 打印输出一次 - 你知道这是为什么(或者我做错了什么)吗?
    • @adjfac 简短的回答是 SAS 执行宏语句并计算出您生成的数据步骤代码在执行任何数据步骤代码之前。它不会为数据步骤的每次迭代再次运行宏语句 - 只有宏语句生成的数据步骤代码。
    猜你喜欢
    • 2017-10-31
    • 2015-03-07
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    • 2019-09-12
    • 2017-05-14
    • 2015-08-19
    • 1970-01-01
    相关资源
    最近更新 更多