【问题标题】:Invoking a macro in data step and assigning its value to a variable在数据步骤中调用宏并将其值分配给变量
【发布时间】:2021-12-19 10:48:18
【问题描述】:

我希望在我的数据步骤中调用一个宏来确定我正在创建的新变量应该接收什么值。

我知道我不一定需要一个宏,我可以在数据步骤中包含代码。问题是我正在处理的问题非常复杂,并且有超过 5 个类似的 if-else 语句。然而,本质上唯一改变的是宏函数内部的内容。

因此需要宏。下面是代码和错误日志。 我相信问题不应该出在宏中,我已经对其进行了测试并且它成功地工作了。但是,由于某种原因,在引用变量和局部宏变量的数据步骤中调用它时不会。

我读到这是因为应该使用 %sysfunc 或 %execute call 之类的东西,但我不能将 sysfunc 与自定义宏一起使用,并且 execute call 也不起作用,或者至少我无法做到工作,因为我想将该宏的值分配给临时局部变量。

I.E.类似 %let temp = execute call(CalculatePayment(args)) 但这不起作用。

%let preliminary_1 = 288;
%let preliminary_2 = 115;
%let preliminary_3 = 58;

data __temp__;
set sashelp.cars;
run;


%macro CalculatePayment(initialPayment, paymentLimit);

    %let temp = %sysfunc(min(&initialPayment,&paymentLimit));
    %let candidate = %eval(&temp. - 27);

    %if( &candidate >= 0) %then %let rValue =  &temp;
    %else %let rValue = 0;
    &rValue
%mend;


data _temp_;
set __temp__;
if weight <= 100 then do; 
    preliminary = 0;
end;

else if (find(Model,"2")) then do;
    %let fstCase = %CalculatePayment(weight,&preliminary_1);
    %let seCase = %CalculatePayment(weight,&preliminary_1);
    preliminary = %eval(&fstCase. + &seCase.);
end;
/*
else if (find(Model,"g") & find(Model,"1")) then do;
    %let fstCase = %CalculatePayment(weight,&preliminary_1);
    %let seCase = %CalculatePayment(0.2 * weight,&preliminary_2);
    %let thirCase = %CalculatePayment(0.8 * weight,&preliminary_3);
    preliminary = %eval(&fstCase. + &seCase. + &thirCase.);
end;
*MORE SIMILAR IF-STATEMENTS BELOW with the values to the macro changing;
*/
else do; preliminary = 0; 
end;

run;

注意这里是错误日志的小sn-p。我没有把它完全放在这里,因为你可以通过运行代码来重现相同的日志。

错误日志:

54          %let fstCase = %CalculatePayment(weight,&preliminary_1);
ERROR: Argument 1 to function MIN referenced by the %SYSFUNC or %QSYSFUNC macro function is not a number.
ERROR: Invalid arguments detected in %SYSCALL, %SYSFUNC, or %QSYSFUNC argument list.  Execution of %SYSCALL statement or %SYSFUNC 
       or %QSYSFUNC function reference is terminated.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: 
       . - 27 
ERROR: The macro CALCULATEPAYMENT will stop executing.
55          %let seCase = %CalculatePayment(weight,&preliminary_1);
ERROR: Argument 1 to function MIN referenced by the %SYSFUNC or %QSYSFUNC macro function is not a number.
ERROR: Invalid arguments detected in %SYSCALL, %SYSFUNC, or %QSYSFUNC argument list.  Execution of %SYSCALL statement or %SYSFUNC 
       or %QSYSFUNC function reference is terminated.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: 
       . - 27 
ERROR: The macro CALCULATEPAYMENT will stop executing.
56          preliminary = %eval(&fstCase. + &seCase.);
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: 
       + 
56          preliminary = %eval(&fstCase. + &seCase.);
                                                     _
                                                     22
ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string, a numeric constant, a datetime constant, 
              a missing value, INPUT, PUT.  
    

【问题讨论】:

  • PROC FCMP 允许您创建用户定义的函数,这是不是宏的选项?

标签: sas sas-macro


【解决方案1】:

你的方法有两个问题。

首先是宏处理器在将代码发送到 SAS 本身进行编译和运行之前完成其工作。数据步骤中间的 %LET 语句将在数据步骤甚至编译之前执行。在那里插入 %LET 语句只会让程序员感到困惑。

其次是涉及数据的计算应该使用SAS代码,而不是宏代码。

您可以使用宏代码来帮助您生成运行所需的 SAS 代码。

看起来你正在尝试做这样的事情。

首先创建一个宏来生成将在数据步骤中工作的语句。

%macro CalculatePayment(initialPayment, paymentLimit, varname);
    temp = min(&initialPayment,&paymentLimit);
    if (temp - 27) >= 0 then &varname = temp;
    else &varname = 0 ;
    drop temp;
%mend;

现在您可以在数据步骤中调用该宏,生成的语句将成为数据步骤的一部分。

%let preliminary_1 = 288;
%let preliminary_2 = 115;
%let preliminary_3 = 58;
options mprint;
data _temp_;
  set sashelp.cars ;
  if weight <= 100 then preliminary = 0;
  else if (find(Model,"2")) then do;
    %CalculatePayment(weight,&preliminary_1,fstCase)
    %CalculatePayment(weight,&preliminary_1,seCase)
    preliminary = fstCase + seCase;
  end;
  else preliminary = 0; 
run;

MPRINT 选项将显示您的宏为您生成的 SAS 代码。

1082  options mprint;
1083  data _temp_;
1084    set sashelp.cars ;
1085    if weight <= 100 then preliminary = 0;
1086    else if (find(Model,"2")) then do;
1087      %CalculatePayment(weight,&preliminary_1,fstCase)
MPRINT(CALCULATEPAYMENT):   temp = min(weight,288);
MPRINT(CALCULATEPAYMENT):   if (temp - 27) >= 0 then fstCase = temp;
MPRINT(CALCULATEPAYMENT):   else fstCase = 0 ;
MPRINT(CALCULATEPAYMENT):   drop temp;
1088      %CalculatePayment(weight,&preliminary_1,seCase)
MPRINT(CALCULATEPAYMENT):   temp = min(weight,288);
MPRINT(CALCULATEPAYMENT):   if (temp - 27) >= 0 then seCase = temp;
MPRINT(CALCULATEPAYMENT):   else seCase = 0 ;
MPRINT(CALCULATEPAYMENT):   drop temp;
1089      preliminary = fstCase + seCase;
1090    end;
1091    else preliminary = 0;
1092  run;

【讨论】:

    猜你喜欢
    • 2013-09-05
    • 2016-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2023-02-09
    相关资源
    最近更新 更多