#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
но ничего не сработало.
Я хотел бы узнать
- причина неправильного вывода для
amp;ln2
,amp;ln3
и так далее - причина
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, в то время как будут печататься комментарии в обычном стиле инструкции.. Таким образом, вы можете использовать комментарии к макрокомандам, чтобы помочь программисту понять код, и использовать комментарии в стиле обычной инструкции, чтобы помочь пользователю понять журнал.