首页 > 解决方案 > 无法将 SAS 宏应用于列

问题描述

我想将我编写的宏应用到 SAS 中的每一行

DATA cars1;
INPUT make $ model $ mpg weight price;
CARDS;
AMC Concord 22 2930 4099
AMC Pacer   17 3350 4749
AMC Spirit  22 2640 3799
Buick Century 20 3250 4816
Buick Electra 15 4080 7827
;
RUN; 

%macro calculate1 (var_name, var_value);
%If &var_name < 20 %then
%do;
&var_value + &var_name;
%end;
%else %if &var_name >= 20 %then
%do;
&var_value - &var_name;
%end;
%mend ;

Data cars2; Set cars1;
varnew = %calculate1(mpg, weight);
Run;

当我运行此代码时,即使 MPG 值 <20,根据代码我想要列的总和,如果 MPG 列中的值 < 20,我也会得到两列之间的差异。

我知道我可以使用列使用 If 条件,但我想尝试使用宏来执行此操作。

请帮我在列上应用我的宏。

提前致谢。

标签: sassas-macro

解决方案


您很可能还不需要宏代码。

宏在运行前编写 SAS 源代码,它不会在运行时评估数据步骤表达式。

在尝试将其抽象为宏之前,学习编写 DATA Step 代码。

数据步

可能包含您希望宏生成的源代码语句(if/then/else)

data cars2;
  * calculate;
  if mpg < 20 then varnew = weight + mpg;
  else
  if mpg >= 20 then varnew = weight - mpg;
run;

这将如何抽象?确定 if/then/else 的哪些组件将在不同的上下文中或与不同的变量一起使用。如果您无法确定重用,请不要编写宏。

考虑生成完整语句的抽象 #1(作为伪代码)

  if PARAMETER_2 < 20 then RESULT_VAR = PARAMETER_1 + PARAMETER_2;
  else
  if PARAMETER_2 >= 20 then RESULT_VAR = PARAMETER_1 - PARAMETER_2;

或抽象#2,即为表达式生成源代码

  ifn (PARAMETER_2 < 20, PARAMETER_1 + PARAMETER_2, PARAMETER_1 - PARAMETER_2)

但是为什么要硬编码20到宏中呢?为什么不把它作为参数呢?如果您走那条路线,那么抽象太多了,并且正在模板化应该以非宏观方式使用的实际语言元素。(有人可能会假设在诸如 LISP 之类的纯函数式语言中没有太多抽象)

抽象 #1 作为宏

%macro calculate(result_var, parameter_1, parameter_2);
  /* generate DATA Step source code, using the passed parameters */

  if &PARAMETER_2 < 20 then &RESULT_VAR = &PARAMETER_1 + &PARAMETER_2;
  else
  if &PARAMETER_2 >= 20 then &RESULT_VAR = &PARAMETER_1 - &PARAMETER_2;
%mend;

data cars2;
  %calculate(varnew,weight,mpg);
run;

抽象 #2 作为宏

%macro calculate(parameter_1, parameter_2);
  /* generate source code that is valid as right hand side of assignment */

  ifn (&PARAMETER_2 < 20, &PARAMETER_1 + &PARAMETER_2, &PARAMETER_1 - &PARAMETER_2)
%mend;

data cars2;
  varnew = %calculate(weight,mpg);
run;

推荐阅读