我有名为_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个)。
有什么方法可以做到这一点吗? 谢谢!
答案 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)