根据特定条件使用sas表创建新变量

时间:2018-01-23 12:16:03

标签: sas sas-macro

我有一个SAS表,它有一个数字变量age。我需要根据age的值构造新变量。新变量应具有以下逻辑:

  • 如果0 <=年龄<= 25,则age0 = 1,否则age0 = 0
  • 如果26 <=年龄<= 40然后年龄25 = 1,则年龄25 = 0 //这里年龄25与年龄0不同!!

所以我使用宏编写了这段代码以避免重复:

%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);

但这不起作用!

我该如何解决呢? 提前谢谢!

2 个答案:

答案 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;
...