2016-10-04 3 views
3

У меня была причина обрабатывать различные переменные данного набора данных с использованием повторяющегося процесса. Чтобы решить эту проблему, я написал макрос, вход которого был бы конкретной интересующей переменной. Затем макрос обработает только эту переменную. Однако оказалось, что одну из переменных нужно обрабатывать несколько иначе. Моим быстрым решением было применить условное; если переменная была исключением, выполните действие, отличное от других переменных. Проблема решена, не так ли? №Макро переменная имеет разное значение в рамках этапа DATA. Зачем?

Я нахожу, что значение макропеременной изменяется в зависимости от того, используется ли оно на шаге данных.

Пожалуйста, обратите внимание,

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, то есть value1 и value3, вместо сохранения имени 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 

Хотя условно в настоящее время выполняет, как и следовало ожидать, мы снова видим, что переменная макрос принимает значения value1 и value3.

Поведение макропеременными кажется, противоречит всему, что я когда-либо знал о понятии переменных из BASIC, C++, Java, C#, VBA, Python, Lisp и R.

Может кто-нибудь пожалуйста объясните мне, что происходит? Я читал большую часть Macro Language Reference, но не знаю, где найти объяснения этого поведения.

ответ

2

макропеременная принимает значения от значению1 и 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 dataset_var1 = 'dataset_var1' Это не по сравнению с &macro_var «dataset_var1`, он сравнивает 'значение1' = '' 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, и их следует покончить с собой, когда это возможно!

+1

Ваш ответ был неплохим до последнего предложения половины ... тот факт, что что-то вводит в заблуждение, не повод покончить с этим, когда это очень ценно. Программирование SAS без _any_ макропеременных или макросов было бы невероятно болезненным ... – Joe

+0

Да, в некоторых случаях это может быть болезненно, сложно и невозможно, чтобы избежать макросов SAS. Тем не менее, это нетипизированный динамический язык, и в сочетании с отсутствием формальной дисциплины программирования, которую вы часто находите в магазинах SAS, это благодатный сад ошибок. – david25272

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 является урегулирование переменных на каждом шаге и как логика оценки.

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

Спасибо @Joe, я немного пересмотрел этот сводный отчет. – Quentin

Смежные вопросы