宏变量在DATA Step中具有不同的值。为什么呢?

时间:2016-10-04 01:42:31

标签: sas sas-macro

我有理由使用重复过程处理给定数据集的不同变量。为了解决这个问题,我编写了一个宏,其输入将是感兴趣的特定变量。然后宏将只处理该变量。然而,事实证明,其中一个变量需要稍微不同地处理。我的快速解决方法是应用条件;如果变量是异常,则执行与其他变量不同的操作。问题解决了吧?否。

我发现宏变量的值会根据是否在数据步骤中使用而改变。

请考虑,

data example;
  length dataset_var1 $ 6 dataset_var2 $ 6;
  input dataset_var1 $ dataset_var2;
  datalines;
  value1 value2
  value3 value4
  ;
run;

宏及其调用:

%macro NoQuotes(macro_var);
  %put &macro_var. ;

  data _null;
    set example;

    put &macro_var. ;

    if &macro_var. = 'dataset_var1' then do; 
        put "The IF evaluated";
      end;
    else do;
        put "The ELSE evaluated";
      end;
  run;

  %put &macro_var. ;
%mend;

%NoQuotes(dataset_var1);

这将生成以下日志条目:

dataset_var1

value1
The ELSE evaluated
value3
The ELSE evaluated
NOTE: There were 2 observations read from the data set WORK.EXAMPLE.
NOTE: The data set WORK._NULL has 2 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.00 seconds


dataset_var1

注意macro_var的值如何根据它是否在DATA步骤内而改变。在DATA步骤中,macro_var采用dataset_var1的值,即value1value3,而不是像您期望的那样保留名称dataset_var1。一旦超出DATA步骤,macro_var的值就会神奇地返回到正确的值。

根据同事的建议,我将宏变量的名称放在条件语句中的引号中。这使得条件符合预期。

%macro WithQuotes(macro_var);
  %put &macro_var. ;

  data _null_;
    set example;

    put &macro_var. ;

    if "&macro_var." = 'dataset_var1' then do; 
        put "The IF evaluated";
      end;
    else do;
        put "The ELSE evaluated";
      end;
  run;

  %put &macro_var. ;
%mend;

%WithQuotes(dataset_var1);

这将生成以下日志条目:

dataset_var1

value1
The IF evaluated
value3
The IF evaluated
NOTE: There were 2 observations read from the data set WORK.EXAMPLE.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


dataset_var1

虽然条件现在按预期执行,但我们再次看到宏变量采用value1value3的值。

宏变量的行为似乎与我所知道的关于BASIC,C ++,Java,C#,VBA,Python,Lisp和R中变量概念的所有内容相反。

有人可以向我解释发生了什么事吗?我已经阅读了大部分Macro Language Reference,但我不知道在哪里可以找到这种行为的解释。

3 个答案:

答案 0 :(得分:4)

简短回答: 尝试使用宏%IF语句而不是数据步骤语言IF语句。

答案很长: 宏语言是预处理器,它处理文本以生成代码。通常,宏语言不了解SAS数据集或数据集中的变量。 DATA步骤语言处理数据集和数据集变量。宏语言看起来类似于DATA步骤语言,但它们具有完全不同的用途,并且是两种不同的语言。

考虑:

87   options mprint;
88
89   %macro ShowValue(var);
90     data _null_;
91       set sashelp.class (obs=3);
92
93       %put The macro variable VAR has the value: &VAR;
94       put "The dataset variable &VAR has the value: " &VAR;
95
96     run;
97
98   %mend;
99
100  %ShowValue(var=height)
MPRINT(SHOWVALUE):   data _null_;
MPRINT(SHOWVALUE):   set sashelp.class (obs=3);
The macro variable VAR has the value: height
MPRINT(SHOWVALUE):   put "The dataset variable height has the value: " height;
MPRINT(SHOWVALUE):   run;

The dataset variable height has the value: 69
The dataset variable height has the value: 56.5
The dataset variable height has the value: 65.3
NOTE: There were 3 observations read from the data set SASHELP.CLASS.

宏语言具有%PUT语句,数据步语言具有PUT语句。上面,%PUT语句的目的是显示名为VAR的宏变量(参数)的值。用户已将值传递给height。上面PUT语句的目的是显示用户命名的数据步变量的值。由于用户已传递值height,因此列出了该数据集变量的值(对于所有三个已处理的记录)。名为VAR的宏变量的值始终为height。名为height的数据集变量对于不同的记录具有不同的值。请注意,%PUT语句只执行一次,即使它是在数据步骤循环内部。这是因为在执行(甚至编译)任何数据步骤代码之前执行宏语句。 PUT语句是数据步骤代码,因此它为数据步骤处理的每个记录编译和执行一次。 PUT语句需要引用,以便它可以区分文本文字和数据步骤变量的名称。 %PUT语句(实际上是整个宏语言)不需要引号,因为宏变量由&引用。

如果要根据宏变量的值进行条件评估以确定宏应该生成哪个数据步骤,可以使用宏%IF语句,例如:

102  %macro ShowValue(var);
103    data _null_;
104      set sashelp.class (obs=3);
105
106      %if &var=height %then %do;
107        &var=&var * 2.54; *convert height from inches to cm;
108      %end;
109
110      %put The macro variable VAR has the value: &VAR;
111      put "The dataset variable &VAR has the value: " &VAR;
112
113    run;
114
115  %mend;
116
117  %ShowValue(var=height)
MPRINT(SHOWVALUE):   data _null_;
MPRINT(SHOWVALUE):   set sashelp.class (obs=3);
MPRINT(SHOWVALUE):   height=height * 2.54;
MPRINT(SHOWVALUE):   *convert height from inches to cm;
The macro variable VAR has the value: height
MPRINT(SHOWVALUE):   put "The dataset variable height has the value: " height;
MPRINT(SHOWVALUE):   run;

The dataset variable height has the value: 175.26
The dataset variable height has the value: 143.51
The dataset variable height has the value: 165.862
NOTE: There were 3 observations read from the data set SASHELP.CLASS.

118  %ShowValue(var=weight)
MPRINT(SHOWVALUE):   data _null_;
MPRINT(SHOWVALUE):   set sashelp.class (obs=3);
The macro variable VAR has the value: weight
MPRINT(SHOWVALUE):   put "The dataset variable weight has the value: " weight;
MPRINT(SHOWVALUE):   run;

The dataset variable weight has the value: 112.5
The dataset variable weight has the value: 84
The dataset variable weight has the value: 98
NOTE: There were 3 observations read from the data set SASHELP.CLASS.

宏%IF语句解析宏变量,并将该宏变量的已解析值与文本字符串height进行比较。请注意,%IF语句中不需要(或想要)引号。由于宏语言用于文本处理,因此它不使用引号来指示文本值。

简而言之,使用宏%IF语句根据宏变量中存储的文本值做出决策,以控制宏语言生成哪些数据步骤代码,并使用数据步骤IF语句根据数据步骤变量的值,用于控制执行哪些数据步骤代码。 (可以使用宏变量甚至宏来生成IF语句中引用的数据步变量的名称。)

了解%PUT与PUT,%IF与IF,%DO与DO等之间的差异是学习使用宏语言的关键步骤。

答案 1 :(得分:2)

宏语言生成代码。简单来说,它可以替换文本。

因此,您的第一个宏调用会创建以下代码

%put dataset_var1 ;

data _null;
set example;

put dataset_var1 ;

if dataset_var1 = 'dataset_var1' then do; 
    put "The IF evaluated";
  end;
else do;
    put "The ELSE evaluated";
  end;
run;

%put dataset_var1 ;

因为变量存在于数据集上,所以它引用变量值,您所看到的输出就是我所期望的。

当您添加引号时,您不再引用该变量,您将创建一个与您的IF条件中的值匹配的文本字符串。

这是字符串到字符串的比较:

 if "dataset_var1" = 'dataset_var1' then do;

这引用了一个变量dataset_var1,它包含两个值,value1 / value3。

if dataset_var1 = 'dataset_var1' then do; 

如果您使用OPTIONS MPRINT SYMBOLGEN;,您将看到SAS在每个步骤中解析变量以及逻辑如何评估。

答案 2 :(得分:2)

  

宏变量采用value1和value3

的值

否:宏变量是一串字符dataset_var1。宏变量不会改变。宏变量与数据步骤中具有相同名称的变量不同。每次SAS宏处理器看到&dataset_var1时,它都会用字符串dataset_var1替换它。 SAS宏处理器通过字符串替换生成代码,而不是评估代码。

提示:如果您打开options mprint;,则可以看到宏处理器生成的代码。

%put &macro_var;&macro_var替换为字符串dataset_var1,并将字符串dataset_var1放入日志中,就像您编写了%put dataset_var1;

一样

在数据步骤中,宏处理器重写以下语句:

put &macro_var;变为put dataset_var1;

put(不是%put)将数据集变量的写入日志,因此将变量dataset_var1的值设置为登录。这个变量是'value1'或'value3'。

if "&macro_var." = 'dataset_var1'变为if dataset_var1 = 'dataset_var1'它没有将&macro_var与'dataset_var1`进行比较,而是将第一行的'value1'='dataset_var1'与'value3'='dataset_var1进行比较”。这两行都是假的。

最终%put &macro_var;与第一个相同,因为&macro_var未发生变化。

  

宏变量的行为似乎与一切相反   我从BASIC,C ++,Java中了解变量的概念,   C#,VBA,Python,Lisp和R.

那是因为SAS宏变量不是SAS变量! SAS宏更像C pre-processor statements,而不是C代码。 SAS宏变量类似于编译器#define指令。根据我的经验,它们是SAS程序中最常见的混淆和错误原因之一,应该尽可能地消除它!