Warm tip: This article is reproduced from serverfault.com, please click

Unable to apply a SAS macro to a column

发布于 2020-12-01 07:59:04

I want to apply a macro I have written to each individual row in 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;

When I run this code I get a difference between the two columns even when the MPG values are <20 when according to the code I want the sum of the columns if the value in the MPG column is < 20.

I know I could use If conditions using the columns but I want try to use macros to do this.

Please help me apply my macro on the columns.

Thanks in advance.

Questioner
cordelia
Viewed
0
Richard 2020-12-01 18:42:14

You most likely do not need to macro code yet.

Macro writes SAS source code before run-time, it does not evaluate data step expressions at runtime.

Learn to write DATA Step code before attempting to abstract it to macro.

DATA Step

This might contain source code statements (the if/then/else) that you want macro to generate

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

How would this be abstracted ? Determine which components of the if/then/else would be reused in a different context or with different variables. If you can't determine re-use, don't code a macro.

Consider abstraction #1 (as pseudo-code) that is to generate a complete statement

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

or abstraction #2 that is to generate source code for an expression

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

But why hardcode 20 into the macro ? Why not make that a parameter as well ? If you go that route the abstraction is too much and is templating actual language elements that should be used in a non-macro way. (One might suppose in a purely functional language such as LISP there is no abstraction too much)

Abstraction #1 as macro

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

Abstraction #2 as macro

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