Функции конкатенации, обернутые %SYSFUNC (), выдают ошибку при обнаружении круглых скобок

#function #loops #macros #sas

#функция #циклы #макросы #sas

Вопрос:

Мне нужно написать макропрограмму, чтобы сгенерировать список для вычисления скользящего среднего, где мне понадобятся несколько строк, которые будут построены следующим образом:

 var1_ma_past_1=mean(var1, lag1(var1), lag2(var1), lag3(var1), lag4(var1), lag5(var1));
var1_ma_past_2=mean(lag1(var1), lag2(var1), lag3(var1), lag4(var1), lag5(var1), lag6(var1));
var1_ma_past_3=mean(lag2(var1), lag3(var1), lag4(var1), lag5(var1), lag6(var1), lag7(var1));
[...]
var2_ma_past_1=mean(var2, lag1(var2), lag2(var2), lag3(var2), lag4(var2), lag5(var2));
  

мой пример программы

 %macro test ;
    %do i = 1 %to 5;
    %let lnamp;i = ;
        %do j = 1 %to 5;
            %let dml = %str(,);
            %let pos = %str(lagamp;i(varamp;j));
            %let lnamp;j = %sysfunc(catx(amp;dml, amp;amp;lnamp;j, amp;pos));
        %end;
    %end;
    /* example output */
    %put amp;ln1;
%mend test;
%test
  

amp;j однако начальные и конечные значения планируется заменить параметрами.

вывод желателен для amp;ln1

 lag1(var1),lag2(var1),lag3(var1),lag4(var1),lag5(var1)
  

но для amp;ln2 amp;ln3 etc это не так ( lag1(varn) отсутствует)

 lag2(var4),lag3(var4),lag4(var4),lag5(var4)
lag2(var3),lag3(var3),lag4(var3),lag5(var3)
  

Кроме того, я получил вывод журнала наводнения, в котором говорится, ERROR: Required operator not found in expression: что из-за круглых скобок внутри cats() , которые находятся внутри %sysfunc() , примером макроса для репликации этого является

 %macro test2;
    %let x=meow;
    %put %sysfunc(cats(x,lag()));
%mend;
%test2
  

Я пытался замаскировать круглые скобки с помощью %str , %superq , %bquote но ничего не сработало.

Я хотел бы узнать

  1. причина неправильного вывода для amp;ln2 , amp;ln3 и так далее
  2. причина ERROR: Required operator not found in expression: и как это исправить (или обходной путь, или даже для подавления ошибки, если она не критична)

Заранее спасибо.

Комментарии:

1. У вас есть лицензия SAS ETS? Если это так, PROC EXPAND может выполнить многие из них более простым способом. Вы можете проверить свои лицензии с помощью proc product_status;run;

2. @Reeza У меня было опасение, что PROC EXPAND также будут включены пропущенные значения для вычисления скользящего среднего, чего я не хочу. У меня также было ощущение, что каждая из них PROC EXPAND будет выводить набор данных, в этом случае эффективность значительно ниже, хотя я на самом деле не проверял это лично.

3. Ни одна из этих проблем не верна. Вы можете выполнить несколько вычислений за один вызов.

Ответ №1:

Нет необходимости использовать функции CAT … () в коде макроса.

В коде макроса для объединения значений вы просто разворачиваете их рядом друг с другом. Также похоже, что ваша логика путает счетчики I и J.

 %macro test ;
%do i = 1 %to 5;
  %let list = ;
  %let dlm = ;
  %do j = 1 %to 5;
    %let list = amp;list.amp;dlm.lagamp;j(varamp;i) ;
    %let dlm = ,;
  %end;
  %put amp;=i amp;=list;
%end;
%mend test;
%test
  

Результаты:

 I=1 LIST=lag1(var1),lag2(var1),lag3(var1),lag4(var1),lag5(var1)
I=2 LIST=lag1(var2),lag2(var2),lag3(var2),lag4(var2),lag5(var2)
I=3 LIST=lag1(var3),lag2(var3),lag3(var3),lag4(var3),lag5(var3)
I=4 LIST=lag1(var4),lag2(var4),lag3(var4),lag4(var4),lag5(var4)
I=5 LIST=lag1(var5),lag2(var5),lag3(var5),lag4(var5),lag5(var5)
  

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

 %macro lags(varname,first,last);
%local lag dlm;
%do lag= amp;first %to amp;last ;
  %if (amp;lag > 0) %then %*;amp;dlm.lagamp;lag(amp;varname);
  %else %*;amp;dlm.amp;varname;
  %let dlm=,;
%end;
%mend lags;

%put var1_ma_past_1=mean(%lags(var1,0,5));
%put var1_ma_past_2=mean(%lags(var1,1,6));
%put var1_ma_past_3=mean(%lags(var1,2,7));
%put var2_ma_past_1=mean(%lags(var2,0,5));
  

Почему вы получаете эти сообщения об ошибках:

%sysfunc() Макрофункции необходимо попытаться выяснить, является ли каждый аргумент символьным или числовым для функции типа CATX() , которая может работать с любым типом ввода. Вот почему () в значениях аргумента это сбивает с толку, поскольку похоже, что вы пытаетесь передать числовое выражение.

 18    %put %sysfunc(catx(|,a(b),b));
ERROR: Required operator not found in expression: a(b)
a(b)|B
19    %put %sysfunc(catx(|,(1 2),b));
3|B
  

Вы могли бы принудительно заключить значения в кавычки, а затем удалить их позже (если ваши значения на самом деле не содержат кавычек).

 %let left=A(b);
%let right=b;
%let intermediate=%sysfunc(catx(|,"amp;left","amp;right"));
%let want=%sysfunc(compress(amp;intermediate,%str(%"));
%put amp;=want;
  

Комментарии:

1. Не могли бы вы, пожалуйста, разъяснить использование %*; ? Похоже, что пробелы устранены, но официальная документация для %amp;; не объясняет, как это работает.

2. %*; Это просто действительно короткий комментарий. Это комментарий к макросу. В отличие от комментария к блоку, /**/ или комментария к оператору, *; . Что это делает, так это устраняет пробел перед текстом, который генерирует макрос.

3. Вау, я не знал, что %*; это действительно имеет функциональное применение. Я всегда думал, что это просто худший вариант из различных способов комментирования…

4. Вы можете использовать комментарии к макрокомандам в определениях макросов, и они не будут печататься, когда включена опция MPRINT, в то время как будут печататься комментарии в обычном стиле инструкции.. Таким образом, вы можете использовать комментарии к макрокомандам, чтобы помочь программисту понять код, и использовать комментарии в стиле обычной инструкции, чтобы помочь пользователю понять журнал.