Объединение переменных SAS через шаг данных

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

Пример набора данных work.test:

AddToStringYN    Value
     Y           One
     Y           Two
     N           Three
     Y           Four
     N           Five

В итоге переменная будет выглядеть так: OneTwoFour (или даже лучше FourTwoOne). Это выглядит так просто, но я не могу найти способ сделать это. Еще я пробовал работать с такими макропеременными:

%let stringvar=;
Data _null_;
  set work.test;
  if AddToStringYN = "Y" then do;
    call symput('stringvar',"&stringvar" || strip(value));
  end;
Run;

Но это дает:

GLOBAL STRINGVAR Four

Так что я получаю только последнее значение. Я понимаю, что это должно быть из-за моего неправильного понимания этого макроса, но я не понимаю, почему в переменной есть только последнее значение. Я думал, что это был только последний раз, когда симпут был вызван, что он действительно был запущен или что-то в этом роде, но потом, когда я настраиваю код на:

%let stringvar=;
Data _null_;
  set work.test;
  if AddToStringYN = "Y" then do;
    call symput('stringvar'||strip(value),"&stringvar" || strip(value));
  end;
Run;

Тогда я получаю их все:

GLOBAL STRINGVARONE  One
GLOBAL STRINGVARTWO  Two
GLOBAL STRINGVARFOUR  Four

Итак, мое последнее предположение заключается в том, что при прохождении этапа данных строка 'call symput ...' фактически добавляется в макропроцессор, где "& stringvar" уже заменен, и только после последнего оператора все они выполняются.
Это хорошее предположение или есть другое объяснение? И вернемся к исходному вопросу: есть ли простой способ добиться этого (имея желаемую переменную)?


person Yoh    schedule 29.04.2011    source источник


Ответы (2)


Приветствие Кажется достаточно простым, вот мое решение:

data a;
set test end=eof;
length cat $100.;
retain cat;
if AddToStringYN = "Y" then do;
   cat=trim(left(cat))||trim(left(value));
end;
if eof then do;
   call symput("VAR",cat);
   output;
end;
run;

%put VAR=&VAR;

в этом примере у вас есть конкатенация вашей переменной в наборе данных A в столбце «CAT», и у вас есть макропеременная VAR с тем же списком

person Fabio Prevedelli    schedule 29.04.2011
comment
Идеально! Я помню, как пытался использовать такую ​​конструкцию (комбинацию повторного использования переменных сохранения и sas), но это не сработало. Пока не могу найти то, что изменилось, но ЭТО РАБОТАЕТ! Да и вообще достаточно просто .... если знаешь где искать;) Спасибо! (есть идеи по дополнительному вопросу, если моя логика верна с макропеременной?) - person Yoh; 29.04.2011
comment
Также попробуйте заменить функции trim (left ()) функциями cat (), catt (), cats (), catx (). Они очень гибкие, простые в использовании и выполняют автоматическое преобразование типов за вас! Доступно в SAS9 и более поздних версиях ... - person Robert Penridge; 29.04.2011

Ниже приводится мой ответ на ваш идентичный вопрос о RunSubmit.com.. Я думаю, что вы и @Fabio можете чрезмерно разрабатывать решение, ему вообще не нужен повторяющийся код шага данных ...

Во-первых, простой способ сделать то, что вы пытаетесь сделать, выглядит так:

proc sql;
  select Value into :StringVar separated by ''
    from work.test
    where AddToStringYN='Y'
    ;
quit;

Здесь вы можете воспользоваться преимуществами интерфейса SQL с SAS / MACRO, используя синтаксис select into. Вы даже можете добавить предложение order by, чтобы получить конкретный заказ, который вы ищете.

Во-вторых, поскольку вы кое-что узнали о том, как работает макрос SAS, и хотите это понять: в вашем первом примере компилятор первым делом перед выполнением кода вычисляет значение &stringvar, которое при этом точка пуста. Итак, после компиляции с заменой этого токена ваш код для SAS выглядит так ...

%let stringvar=;
Data _null_;
  set work.test;
  if AddToStringYN = "Y" then do;
    call symput('stringvar',"" || strip(value));
  end;
Run;

... тогда SAS запускает этот код (который оказывается действительным кодом, но присоединяет пустую строку к началу чего-либо). И из-за того, как работает шаг данных, каждая итерация шага данных фактически заменяет значение StringVar, поэтому в конце шага данных остается последнее значение, которое было прочитано.

person sasfrog    schedule 29.04.2011
comment
Увидел ваш ответ на RunSubmit, еще не успел ответить. Прежде всего большое спасибо, особенно за объяснение о макросе SAS. На самом деле, я слишком много думал о том, как это работает, разрешение макропеременной происходит только один раз, а не на каждой итерации шага данных. Об использовании proc sql: я всегда учился использованию приоритета кода SAS над SQL (то есть времени обработки). Я не знаю, подходит ли это для этого примера. - person Yoh; 02.05.2011
comment
@Yohsoog: нет строгого правила относительно производительности кода шага данных SAS по сравнению с PROC SQL - какой из них быстрее, будет зависеть от всех видов факторов. Вы всегда можете попробовать два решения и проверить журнал, чтобы узнать, что в этом случае быстрее всего с вашими данными. Но есть и другие соображения для вас, такие как читаемость кода, удобство обслуживания, ясность для других, стандарты кодирования и т. Д. Что касается меня, я бы предпочел метод PROC SQL, если вы также не делаете много других вещей в шаг данных, который делает ввод / вывод полезным для результата. - person sasfrog; 03.05.2011
comment
Да, действительно, в этом случае я делаю много других вещей на этапе данных. Шаг данных фактически проходит через таблицу, генерирующую полный xml. И строка, которую я собрал здесь, также разрезается в другом месте на том же этапе данных, поэтому использование метода PROC SQL было бы даже невозможно. Но хорошо подумать, как вы говорите, для удобочитаемости и т. Д. - person Yoh; 03.05.2011