如何将变量序列(列表)传递给SAS宏

时间:2018-01-12 07:51:09

标签: variables sas sas-macro

我有名为_200701,_200702,...到_201612的变量,每个变量都包含该月的特定数字数据。如果符合条件,我希望从中减去特定金额(变量cap_inc):

console.log("false" && "true") //will print true.

如果我只将一个月作为参数(例如_200909),代码正在工作......但我想把这些变量放在那里。我尝试过像“OF _200701 - _201612”或“OF _20:”这样的组合,但没有任何效果。

我还有另一个宏,使用parmbuff参数,工作在“for each loop”方式,我可以把更多的变量用逗号分隔,例如

%MACRO DeleteExc(var);
DATA Working.Test;
SET Working.Test;
    IF &var. GE cap_inc THEN &var. = SUM(&var., - cap_inc);
    ELSE &var. = &var.;
RUN;
%MEND;

但我仍然无法以一些方便,易于遵循的方式传递所有变量。 (我不想输入所有参数,因为其中有120个)。

有什么方法可以做到这一点吗? 谢谢!

4 个答案:

答案 0 :(得分:1)

首先,如果要将列表传递给宏,请不要使用逗号分隔列表。它只会让调用宏成为一个巨大的痛苦。您将需要使用宏引用来隐藏逗号。或者使用/parmbuff选项覆盖SAS的参数处理,并添加逻辑以自行处理&syspbuff宏变量。使用值中未使用的其他字符作为分隔符。喜欢|或^例如。对于变量名称列表,请使用空格作为分隔符。

%DeleteExc(varlist=_200701 _200702 _200703)

然后你可以在SAS期望变量列表的任何地方使用宏变量。

array in &varlist ;
total = sum(of &varlist);

现在,由于您的列表实际上是MONTHS列表,因此请为您的宏提供开始和结束月份,并让它为您生成列表。

%macro DeleteExc(start,end);
  %local i var ;
  %do i=0 %to %sysfunc(intck(month,&start,&end)) ;
    %let var=_%sysfunc(intnx(month,&start,&i,b),yymmn6);
IF .Z < cap_inc < &var. THEN &var. = &var - cap_inc;
  %end;
%mend;
DATA Working.Test;
  SET Working.Test;
%DeleteExc("01JAN2007"d,"01DEC2016"d);
RUN;

答案 1 :(得分:0)

以下是一些选项 - 或许有一个你还没试过?

data example;
    array months{*} _200701-_200712 _200801-_200812 (24*1);
    array underscores{*} _:;
    _randomvar = 100;
    s1 = sum(of _200701-_200812); /*Generates lots of notes about uninitialised variables but gives correct result*/
    s2 = sum(of _200701--_200812); /*Works only if there are no rogue columns in between month columns*/
    s3 = sum(of months{*}); /* Requires array definition*/
    s4 = sum(of _:); /*Sum any variables with _ prefix - potentially including undesired variables*/

    put (s1-s4)(=);
run;

答案 2 :(得分:0)

双短划线( - )变量名称范围列表可用于指定数组中的变量。通过简单的迭代DO LOOP,您可以对每个变量执行所需的操作。

data want;
  set have;
  array month_named_variables _200701 -- _201612;
  do _index = 1 to dim(month_named_variables); drop _index;

    IF month_named_variables(_index) GE cap_inc THEN 
      month_named_variables(_index) = SUM(month_named_variables(_index), - cap_inc);
    ELSE
      month_named_variables(_index) = month_named_variables(_index);

  end;
run;

如果数据集在名称范围内有额外变量,您仍然可以使用数组和非宏代码:

data want;
  set have;
  array nums _numeric_;

  do _index = 1 to dim(nums); drop _index;

    _vname = vname(nums(_index)); drop _vname;
    if _vname ne: '_' 
      or not (2007 <= input(substr(_vname,2,4), ??4.) <= 2016)
      or not (01   <= input(substr(_vname,6,2), ??2.) <= 12)
      or not length(_vname) = 7 
    then continue;

    IF nums(_index) GE cap_inc THEN 
      nums(_index) = SUM(nums(_index), - cap_inc);
    ELSE
      nums(_index) = nums(_index);

  end;
run;

如果你确实需要使用特定的变量列表并希望在宏中工作,我建议传递对应于变量名的FROM和TO值,并根据命名约定循环该范围:

%macro want(data=, yyyymm_from=, yyyymm_to=, guard=1000, debug=0);
  %local LOWER UPPER YEARMON INDEX NVARS;
  %let LOWER = %sysfunc(inputn(&yyyymm_from,yymmn6.));
  %let UPPER = %sysfunc(inputn(&yyyymm_to,yymmn6.));

  %let INDEX = 1;
  %do YEARMON = &LOWER %to &UPPER;
    %let yyyymm = %sysfunc(putn(&YEARMON, yymmn6.));

    %local ymvar&INDEX;
    %let ymvar&INDEX = _&yyyymm;  %* NAMING CONVENTION;

    %if &debug %then %put NOTE: YMVAR&INDEX=%superq(YMVAR&INDEX);

    %if &INDEX > &GUARD %then %do;
      %put ERROR: Exceeded guard limit of &GUARD variables;
      %return;
    %end;

    %let NVARS = &INDEX;

    %let YEARMON = %sysfunc(INTNX(MONTH,&yearmon,1));  %* NAMING CONVENTION;
    %let YEARMON = %eval(&YEARMON-1); %* back off by one for implicit macro do loop increment of +1;

    %let INDEX = %eval(&INDEX+1);
  %end;

  %do INDEX = 1 %to &NVARS;
    %put NOTE: &=INDEX YMVAR&INDEX=&&&YMVAR&INDEX;
  %end;
%mend;

%want (data=have,  yyyymm_from=200701, yyyymm_to=201612)

答案 3 :(得分:0)

如果我的理解是正确的,你想用月份循环,这是数据变量的被告,你可以设置开始日期和结束日期,然后循环。

%macro month_loop(start,end);
%let start=%sysfunc(inputn(&start,yymmn6.));
%let end=%sysfunc(inputn(&end,yymmn6.));
%let date=&start;
%do %until (%sysfunc(indexw("&date","&end")));
     %let date=%sysfunc(intnx(month,&date,1));
     %let var=_%sysfunc(putn(&date,yymmn6.));
     data want;
        set have;
        IF &var. GE cap_inc THEN &var. = SUM(&var., - cap_inc);
        ELSE &var. = &var.;
     run;
%end;
%mend;
%month_loop(200701,201612)