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

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

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 ln&i = ;
        %do j = 1 %to 5;
            %let dml = %str(,);
            %let pos = %str(lag&i(var&j));
            %let ln&j = %sysfunc(catx(&dml, &&ln&j, &pos));
        %end;
    %end;
    /* example output */
    %put &ln1;
%mend test;
%test

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

результат требуется для &ln1

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

но для &ln2 &ln3 и т. д. это не так (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. причина некорректного вывода для &ln2, &ln3 и т.д.
  2. причина ERROR: Required operator not found in expression: и как исправить (или обходной путь, или вообще подавить ошибку если не критично)

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


person Han Chengyu    schedule 09.03.2019    source источник
comment
У вас есть лицензия SAS ETS? Если это так, PROC EXPAND может сделать многие из них более простым способом. Вы можете проверить свои лицензии с помощью proc product_status;run;   -  person Reeza    schedule 09.03.2019
comment
@Reeza У меня были опасения, что PROC EXPAND также будет включать пропущенные значения для расчета скользящего среднего значения, чего я не хочу. У меня также было ощущение, что каждый PROC EXPAND будет выводить набор данных, в этом случае эффективность резко ниже, хотя я лично не проверял это.   -  person Han Chengyu    schedule 10.03.2019
comment
Ни одно из этих опасений не является правильным. Вы можете выполнять несколько расчетов за один вызов.   -  person Reeza    schedule 10.03.2019


Ответы (1)


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

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

%macro test ;
%do i = 1 %to 5;
  %let list = ;
  %let dlm = ;
  %do j = 1 %to 5;
    %let list = &list.&dlm.lag&j(var&i) ;
    %let dlm = ,;
  %end;
  %put &=i &=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= &first %to &last ;
  %if (&lag > 0) %then %*;&dlm.lag&lag(&varname);
  %else %*;&dlm.&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(|,"&left","&right"));
%let want=%sysfunc(compress(&intermediate,%str(%"));
%put &=want;
person Tom    schedule 09.03.2019
comment
Не могли бы вы уточнить использование %*;? Кажется, пробелы устранены, но официальная документация для %&; не объясняет, как это работает. - person Han Chengyu; 12.03.2019
comment
%*; — это очень короткий комментарий. Это комментарий к макросу. В отличие от блочного комментария /**/ или комментария оператора *;. Что он делает, так это устраняет пробел перед текстом, который генерирует макрос. - person Tom; 12.03.2019
comment
Вау, я не знал, что %*; на самом деле имеет функциональное назначение. Я всегда думал, что это просто худший вариант из различных способов комментирования... - person Robert Penridge; 14.03.2019
comment
Вы можете использовать макрокомментарии в определениях макросов, и они не будут печататься, когда опция MPRINT включена, в то время как обычные комментарии в стиле операторов будут печататься. Таким образом, вы можете использовать макрокомментарии, чтобы помочь программисту понять код, и использовать обычные комментарии в стиле операторов, чтобы помочь пользователю понять лог. - person Tom; 14.03.2019