【问题标题】:Apply SAS Program to several dataset with macro将 SAS 程序应用于具有宏的多个数据集
【发布时间】:2020-07-11 19:14:43
【问题描述】:

我对 SAS 很陌生,所以我提前道歉。我正在使用 SAS 大学版。

我有来自某一年(1997-2017)的 20 个数据集,所有数据集都包含 30 个变量中捕获的信息。现在,我想将相同的代码应用于所有数据集,但某些代码块仅应用于特定年份的变量。因此,我想使用从 1997 年到 2017 年的宏来执行类似...

LIBNAME IN '/folders/myfolders/fake_data';

%let j= 1997 to 2017; 

    data fake_&j;
     set fake_data;

proc import out= fake_&j datafile = "/folders/myfolders/fake_data/mz_&j.dta" replace

* Year;
year = j;

要访问数据集 fake_1997.dta,创建一个取数据集名称 (1997) 值的年份变量,应用代码(见下文),然后对 mz_1998.dta 执行相同操作,依此类推。

我想应用于所有数据的代码示例是

* Weights;
    if (j GE 1997 AND j LE 2004) then 
      shrf = x; 
    else if (j GE 2005 AND j LE 2017) then
      shrf = y;

非常感谢您!

【问题讨论】:

标签: loops sas sas-macro


【解决方案1】:

一种不涉及嵌套宏的方法是神奇的data nullcall execute。我经常用这个。如果数据集已经是 SAS 格式,这将是最有帮助的。

libname HAVELIB "path-to-sas-datasets";

data _null_;
  set sashelp.vtable(where=(libname="HAVELIB"));
  call execute("%mymacro(HAVELIB." || strip(memname) || ");");
run;

创建一个循环以将一组.dta 文件导入为sas7bdat 同样简单,根据infile pipedir 的输出创建一个数据集并使用call execute 执行类似的循环。

更多信息在这里:

https://www.lexjansen.com/phuse/2014/cc/CC06.pdf

【讨论】:

    【解决方案2】:

    宏代码在某种程度上是编写代码的代码。写作与其说是像“写”、“打印”或“回声”那样的主动过程,倒更像是样板或模板系统。

    “开放代码”中不能存在宏%DO 循环,因此必须在宏定义中对其进行编码。宏被“调用”以使其编写(或生成)代码。您有时可能会看到术语“gencode”表示通过调用宏生成的代码。

    Proc IMPORT 非常适合定期读取一致的数据,或处理第一次探索。 IMPORT 不会进行任何数据转换或允许您在导入期间添加新变量。您将需要第二个步骤,即 DATA 步骤来执行这些操作。

    根据宏的用途命名您的宏。宏内部使用的任何宏变量都应声明为%LOCAL,以防止与全局宏变量发生不必要的交互。

    示例:

    %macro getData(fromYear=, toYear=);
    
      %local year;
    
      %DO year = &fromYear %to &toYear;
    
        * step 1;
        * get initial data set from raw data file;
        * double dot needed because &<NAME>. is a token specifying macro variable resolution;
    
        proc import 
          datafile = "/folders/myfolders/fake_data/mz_&YEAR..dta" /* double dot */
          replace
          out= import_fake_&YEAR.
        ;
    
        * step 2;
    
        data fake_&YEAR;
          set import_fake_&YEAR.;
          year = &YEAR;
    
          %* macro %if codegens a data step statement specific to year;
    
          %if &YEAR GE 1997 AND &YEAR LE 2004 %then %do;
            /* anything that is not consumed by macro processing is emitted as a codegen */
            /* so here the macro is emitting a data step assignment statement */
            shrf = x;   
          %end; 
          %else
          %if &YEAR GE 2005 AND &YEAR LE 2017 %then %o
            shrf = y;
          %end;
          %else %do;
            shrf = 1; * uniform weighting ;
          %end;
        run;
      %END;
    %mend;
    
    %* invoke;
    %getData(fromYear=1997, toYear=2017);
    
    %* this point your might want to combine (stack) all the data sets together
    %* so that other Procs can use the 'all' data and utilize CLASS, BY and WHERE
    %* statements that are so effective in SAS;
    
    data fake_duodecade;
      set fake_1997-fake2017;  %* special data set name list construct;
    run;
    

    在宏定义中指定宏参数以使其更有用和可重用。不要编写宏来重现现有程序的功能。不需要的时候不要写宏。不要对自己无法编写的内容进行基因编码。不要混淆(误解)宏变量的范围,要知道它们与 DATA 步变量的不同之处。

    【讨论】:

    • 嗯。如果你声明一个do变量而不调用%local,如果在宏中使用它会作为宏变量持续存在吗?如果在数据步骤中完成相同的保留?与for相同?
    • SAS 中没有fordo 用于数据步骤代码,%do 用于宏代码。如果您没有将宏变量定义为局部(或全局),那么如果宏变量已经存在,则使用它,如果不存在,则创建一个新变量,它是局部的(在宏中运行时)或全局的(当作为开放代码运行)。
    猜你喜欢
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多