SAS — создание переменных шага данных с использованием динамической макропеременной

#sas

#sas

Вопрос:

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

Я попробовал следующий код:

 data a;
set a;
if MOB = 1 then do;
   MOB1_accounts = accounts;
   call symput('MOB1_acct', MOB1_accounts);
end;
else if MOB > 1 then MOB1_accounts = amp;MOB1_acct.;
run;
 

У меня есть серия повторяющихся мобов (1-36). Я хочу создать поле с именем MOB1_Accts, установить его равным количеству учетных записей для этой когорты, где MOB = 1, и сохранить это значение, когда MOB = 2, 3, 4 и т.д. По сути, я хочу «перетаскивать» значение MOB 1 каждые 36 записей.

По какой-то причине эта макропеременная возвращает «1» вместо правильного # accounts. Я думаю, что это может быть проблема с символами / числами, но я не уверен. Я перепробовал все возможные перестановки одинарных кавычек, двойных кавычек, символов и т.д… не повезло.

Спасибо за помощь!

Ответ №1:

Вы неправильно используете макросистему.

Вводящий элемент ampersand ( amp; ) в исходном коде сообщает SAS разрешить следующий символ и поместить его в поток отправки кода. Таким образом, разрешенные данные amp;MOB1_acct. не могут быть изменены на этапе выполнения ДАННЫХ. Другими словами, выполняемый шаг не может изменить свой исходный код — разрешенная макропеременная будет одинаковой для всех неявных итераций шага, поскольку ее значение стало частью исходного кода шага.

Вы можете использовать SYMPUT() SYMGET() функции и для перемещения строк из шага ДАННЫХ в шаг ДАННЫХ и обратно. Но это все равно неправильный подход к вашей проблеме.

Наиболее простой метод может быть

  • использование retain переменной ed
  • mod (_n_, 36) вычисление для определения каждой 36-й строки. ( _n_ является прокси для номера строки на простом шаге с одним набором.)

Пример:

 data a;
  set a;

  retain mob1_accounts;

  * every 36 rows change the value, otherwise the value is retained;
  if mod(_n_,36) = 1 then mob1_accounts = accounts;
run;
 

Вы не показали никаких данных, поэтому фактические инструкции программы, которые вам нужны, могут немного отличаться.

В отличие SYMPUT/SYMGET от RETAIN

Как указано, SYMPUT/SYMGET это возможный способ сохранить значения, отключив их сохранение в таблице символов макросов. Однако существует штраф. Для SYM* сохранения / извлечения символьного значения и, возможно, дополнительных преобразований между символьным и числовым требуется вызов функции и любые манипуляции / черные ящики.

Пример:

1 000 000 прочитанных строк. DATA _null_ шаги, позволяющие избежать записи накладных расходов как части контраста.

 data have;
  do rownum = 1 to 1e6;
    mob   1;
    accounts = sum(accounts, rand('integer', 1,50) - 10);
    if mob > 36 then mob = 1;
    output;
  end;
run;

data _null_;
  set have;

  if mob = 1 then call symput ('mob1_accounts', cats(accounts));

  mob1_accounts = symgetn('mob1_accounts');
run;

data _null_;
  set have;
  retain mob1_accounts;

  if mob = 1 then mob1_accounts = accounts;
run;
 

В моих системных журналах

 142  data _null_;
143    set have;
144
145    if mob = 1 then call symput ('mob1_accounts', cats(accounts));
146
147    mob1_accounts = symgetn('mob1_accounts');
148  run;

NOTE: There were 1000000 observations read from the data set WORK.HAVE.
NOTE: DATA statement used (Total process time):
      real time           0.34 seconds
      cpu time            0.34 seconds


149
150  data _null_;
151    set have;
152    retain mob1_accounts;
153
154    if mob = 1 then mob1_accounts = accounts;
155  run;

NOTE: There were 1000000 observations read from the data set WORK.HAVE.
NOTE: DATA statement used (Total process time):
      real time           0.04 seconds
      cpu time            0.03 seconds
 

Или

    way          real   cpu
------------- ------  ----
SYMPUT/SYMGET   0.34  0.34
    RETAIN      0.04  0.03
 

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

1. По какой-то причине мой вызов symput symget/symgetn по-прежнему возвращает только «1». Но оператор retain работал отлично. Я не знаю, как я не слышал об этом до сих пор — большое спасибо!