2

我在数据步骤中调用宏并将宏变量分配给数据步骤变量,如下所示。

宏的输入来自具有大约 500 条记录的输入数据集。

%macro test(inp_var);
  %global macro_var;
  --- using inp_var variable here---
  %if --some condition-- %then call symput('macro_var',-- some value--);
%mend;

data output;
  set input;
  %test(inp_var);
  new_data_step_var = symget('macro_var');
run;

但它显示指向变量new_data_step_var - ERROR 180-322: Statement is not valid or it is used out of proper order的错误消息。

4

4 回答 4

4

没有 SAS 宏实际上在“内部”数据步骤中执行。宏语言处理器和数据步编译器作为共享代码输入流的两个不同子系统。他们在“吃”大量 SAS 代码时相互交接。在原始程序的情况下,SAS 中的语言处理器看到“数据”语句并移交给数据步编译器。检测到嵌入的 %test 宏调用,代码输入流首先交给宏处理器!宏处理器扩展 %test 宏内部的所有代码和宏逻辑,然后将整个代码流交回 SAS 数据步编译器进行编译。

所以 %test 将在数据步骤甚至编译之前运行完成。

如果您希望在数据步骤中创建自己的子例程,请尝试 proc fcmp。否则,只需按照建议在数据步骤中实现条件逻辑。

于 2013-09-02T14:19:27.543 回答
2

使用 datastep if/then 重写它,而不是使用宏 if/then,并且不要创建宏变量,只需使用 datastep 变量。

%宏测试(var);
  调用缺失(tempvar);
  if --some condition-- then tempvar = --some value-- ;
%修复;

数据输出;
  设置输入;
  %TEST(inp_var) ;
  新变量 = 临时变量;
  删除 tempvar ;
跑 ;
于 2013-09-02T09:47:08.907 回答
1

您不能在使用 call symput 设置宏变量的同一数据步骤中使用宏变量。您的 call symput 语句的结果仅在数据步骤之后可用。

所以在处理 symget 语句时,宏变量还不存在。另外,这似乎毫无意义,为什么不使用保留语句来保存您想要的值呢?

例如:

data output;
    set input;
    retain new_data_step_var;
    if --some condition -- then new_data_step_var = --some value--;
run;
于 2013-09-02T07:38:28.417 回答
1

包含 proc 或数据步骤的宏在数据步骤内不可执行。宏不是函数或子程序;它们是文本,就像您输入它一样(只是通过循环和条件节省了一些时间)。因此,您的宏的内容需要是可以在数据步骤中执行的文本:

%macro mymacro(numiters);
*this macro would be easier to do in an array, but it is an example;
%local t;
%do t = 1 to &numiters.;
x&t. = mean(y&t.,z&t.);
%end;
%mend mymacro;

data output;
set input;
%mymacro(5);
run;

在这种情况下,不将值存储在宏变量中会更容易(并且在风格上更正确)。只需将结果包含在数据步骤变量中,并在需要时将该变量的名称作为参数之一传递。

还有一些函数样式的宏,它们实际上将一个值返回给数据步骤(或者在这种情况下,返回等同于一个值的文本)。它们可以用在等号的右边。

%macro xtothey(in,power);
%local t;
&in.
%do t = 1 to &power-1;
*&in.
%end;
;
%mend myfunctionmacro;

data output;
set input;
y = %xtothey(x,4);
run;

这实际上在 PROC FCMP(编译函数和子例程)中更容易完成,但有时宏对此更好(或者您可能不太了解 FCMP)。

最后,一些宏需要它们自己的过程或数据步骤。在这些情况下,除非您使用某些 FCMP 元素,例如 DOSUBL,否则您需要将值存储在某个地方,无论是在数据集还是宏中。在这些情况下,您必须在需要值的数据步之前运行宏 - 但您只能获得一个(或有限数量的)返回值。除非你达到一些极端的长度,否则你不会每行得到一个,这通常可以在不使用宏变量的情况下做得更好。我认为下面的形式不好,因为你几乎总是可以在不使用宏变量的情况下做得更好——但如果你需要,这就是你会这样做的方式。带有 DOSUBL 的 FCMP 可能是更好的选择。

%macro findmode(dset,var,outvar);
proc means data=&dset;
var &var.;
output out=_tempset mode(&var.)=&var._mode;
run;
data _null_;
set _tempset;
call symputx("&outvar.",&var._mode);
run;
%mend findmode;

%findmode(sashelp.class,weight,wtmode);
data output;
set input;
mode=&wtmode;
run;
于 2013-09-02T13:04:29.337 回答