我有一个SAS表,它有一个数字变量age
。我需要根据age
的值构造新变量。新变量应具有以下逻辑:
所以我使用宏编写了这段代码以避免重复:
%macro intervalle_age(var,var1,var2);
if (&var=>&var1) and (&var<=&var2);
then return 1;
else return 0;
%mend;
然后我调用宏来获取每个新变量的值:
age0=%intervalle_age(age,0,25);
age25=%intervalle_age(age,26,40);
age25=%intervalle_age(age,41,65);
age25=%intervalle_age(age,65,771);
但这不起作用!
我该如何解决呢? 提前谢谢!
答案 0 :(得分:1)
我同意尼古拉的观点,你应该退后一步,完全避开宏观。您发布的示例代码似乎不正确,您有四个不同年龄段的条件仅分配给两个变量。
在SAS中,逻辑评估解析为1表示true,0表示false。此外,数值变量可用于具有非零,非缺失值的逻辑表达式,否则为true和false。
因此,用于分配年龄范围标志变量的代码序列将是:
age0 = 0 < age <= 25 ;
age25 = 25 < age <= 40 ;
age40 = 40 < age <= 65 ;
age65 = 65 < age <= 71 ;
age71 = 71 < age ;
屏蔽宏代码背后的简单易读的SAS语句可能会导致维护问题并降低未来的理解。但是,如果您的用例是构建这些类型的代码块的许多集合,那么基于断点的宏可以提高可读性和理解。
data have; age = 22; bmi = 20; run;
options mprint;
* easier to understand and not prone to copy paste issues or typos;
data want;
set have;
%make_flag_variables (var=age, breakpoints=0 25 40 65 71)
%make_flag_variables (var=bmi, breakpoints=0 18.5 25 30)
run;
取决于此宏
%macro make_flag_variables (var=, breakpoints=);
%local I BREAKPOINT SUFFIX_LOW RANGE_LOW SUFFIX_HIGH RANGE_HIGH;
%let I = 1;
%do %while (%length(%scan(&breakpoints,&I,%str( ))));
%let BREAKPOINT = %scan(&breakpoints,&I,%str( ));
%let SUFFIX_LOW = &SUFFIX_HIGH;
%let SUFFIX_HIGH = %sysfunc(TRANSLATE(&BREAKPOINT,_,.));
%let RANGE_LOW = &RANGE_HIGH;
%let RANGE_HIGH = &BREAKPOINT;
%if &I > 1 %then %do;
&VAR.&SUFFIX_LOW = &RANGE_LOW < &VAR <= &RANGE_HIGH; /* data step source code emitted here */
%end;
%let I = %eval ( &I + 1 );
%end;
%mend;
日志片段显示宏执行的代码生成
92 data want;
93 set have;
94
95 %make_flag_variables (var=age, breakpoints=0 25 40 65 71)
MPRINT(MAKE_FLAG_VARIABLES): age0 = 0 < age <= 25;
MPRINT(MAKE_FLAG_VARIABLES): age25 = 25 < age <= 40;
MPRINT(MAKE_FLAG_VARIABLES): age40 = 40 < age <= 65;
MPRINT(MAKE_FLAG_VARIABLES): age65 = 65 < age <= 71;
96 %make_flag_variables (var=bmi, breakpoints=0 18.5 25 30)
MPRINT(MAKE_FLAG_VARIABLES): bmi0 = 0 < bmi <= 18.5;
MPRINT(MAKE_FLAG_VARIABLES): bmi18_5 = 18.5 < bmi <= 25;
MPRINT(MAKE_FLAG_VARIABLES): bmi25 = 25 < bmi <= 30;
97 run;
答案 1 :(得分:0)
return
在SAS宏中没有任何特殊含义。这些宏被称为&#34;生成&#34;代码,即宏调用被处理宏处理器&#34;理解的东西后剩下的文本替换。 (基本上,涉及以&
或%
开头的代币(单词)。
在你的情况下,宏处理器只是扩展宏变量(其余的只是文本,宏处理器保持不变),导致:
age0=if (age=>0) and (age<=25);
then return 1;
else return 0;
age25=/*and so on*/
理解how the macro processor and regular execution interact很重要(基本上,所有宏扩展必须在给定的DATA或PROC步骤开始执行之前完成)。
要完成这项工作,您需要生成完整的if
语句,包括对输出var的赋值:
%macro calc_age_interval(outvar, inputvar, lbound, ubound);
if (&inputvar=>&lbound) and (&inputvar<=&ubound) then do;
&outvar = 1;
end; else do;
&outvar = 0;
end;
%mend calc_age_interval;
%calc_age_interval(outvar=age0, inputvar=age, lbound=0, ubound=25);
或者让它生成一个表达式,在执行时将其计算为0或1(通过将结果直接赋值给变量(无论如何,布尔表达式的结果为1或0),或使用{{3要更明确):
%macro calc_age_interval(inputvar, lbound, ubound);
ifn((&inputvar=>&lbound) and (&inputvar<=&ubound), 1, 0)
%mend;
age0 = %calc_age_interval(age, 0, 25); /* expands to age0=ifn(..., 1, 0); */
退一步,在这种情况下,我根本不会为宏而烦恼。您可以使用IFN()
或将所有输出变量重置为0,然后执行if-elseif
:
if age < 0 then age_missing_or_negative = 1;
else if age <= 25 then age0 = 1;
else if age <= 40 then age25 = 1;
...