Ошибка имени SAS при использовании переменной из циклического макроса внутри инструкции hash dataset



Какие-либо советы о том, как я могу изменить эту строку кода проблемы ниже, чтобы получить мои наборы данных именованные без ошибок?



У меня есть набор данных, в котором я хочу сопоставить фирмы по лечению (4400) с примерно 100 000 контролирующих фирм по 48 отраслям и 14 годам, а затем ближайший размер без замены. Мой метод ниже может быть немного неуклюжим, но я учусь по мере того, как иду. Я разделяю наборы данных обработки и контроля на группы 48x14, (после этого я попытаюсь выполнить ближайшее совпадение без кода замены через какой-то тип петли).

Я уже использовал вариант приведенного ниже хэш-кода, чтобы сделать 48 наборов данных out1...out48. Теперь я пытаюсь далее подгруппировать каждый из этих 48 наборов данных в 14 лет с помощью приведенного ниже кода. Я получаю строку создания набора данных с ошибкой, где я пытаюсь создать наборы данных 48x14 с именами out12004, out22004, out32004. . .out482013



Строка кода задачи (примерно на 2/3 ниже кода): hh.output (dataset: 'out'| / &i / / put (год, лучший.-Л)) ;



Ошибки SAS выглядят следующим образом:



Ошибка: значение OUT 12004 не является допустимым именем SAS.



Ошибка: произошла ошибка при использовании метода экземпляра OM_OUTPUT (505) из "DATASTEP.ХЭШ".



Вот полный код (модифицированный из
можно ли замкнуть цикл над наборами данных SAS? и SUGI30 бумага 236-30



 %MACRO process_datasets(mdataset);
data &mdataset.;
set &mdataset.;
data _null_ ;
dcl hash hoh (ordered: 'a') ;
dcl hiter hih ('hoh' ) ;
hoh.definekey ('year' ) ;
hoh.definedata ('year', 'hh' ) ;
hoh.definedone () ;
dcl hash hh () ;
do _n_ = 1 by 1 until ( eof ) ;
set out&i. end = eof ;
if hoh.find () ne 0 then do ;
hh = _new_ hash (ordered: 'a') ;
hh.definekey ('industry','cik', 'year', '_n_') ;
hh.definedata ('industry','cik','year','eventdat', 'at', 'roa') ;
hh.definedone () ;
hoh.replace () ;
end ;
hh.replace() ;
end ;
do rc = hih.next () by 0 while ( rc = 0 ) ;
hh.output (dataset: '_'||&i||put(year, best.-L)) ;
rc = hih.next() ;
end ;
stop ;
run;

data _null_;
file 'tmp.csv' mod dsd dlm=','; *saving everything to the same file;
set &mdataset.;
put (_all_) (+0);
run;

%MEND process_datasets;

%MACRO loop_through_all;
%DO i = 1 %to 48;
%process_datasets(out&i.);
%END;
%MEND loop_through_all;
599   3  

3 ответов:

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

&i действительно доступен здесь, хотя я бы предположил, что это плохой стиль, чтобы использовать его так, как вы делаете. Макропеременные, на которые полагаются внутренние макросы, должны быть определены как макропараметры; это позволяет понять, откуда они взялись. Однако технически это не так, понимаете это:

%macro caller;
%do i=1 %to 5;
  %called;
%end;
%mend;
%macro called;
%put &i;
%mend called;

%caller;
Однако было бы лучше сделать I параметром, таким как %macro called(i=);, чтобы сделать ваш макрос более ясным и более многоразовым. Во-вторых, отсутствие кавычек на самом деле не является прямой проблемой, хотя опять же указывает на проблему и является решением в некотором смысле. SAS действительно преобразует числовые значения в символьное значение - в противном случае вы получите совсем другое сообщение об ошибке; однако это не помогает. Наиболее похожая реализация того, что вы сделали, - это чтобы добавить compress вокруг него. Это потому, что проблема заключается в том, как SAS преобразует цифры в текст; &i - это число (1 в вашем примере). Его нужно преобразовать в "1", а вместо этого он преобразуется с помощью best12. в " 1". Это проблема.
hh.output (dataset: compress('_'||&i||put(year, best.-L))) ;

Это работает. Лучшей реализацией было бы намеренное преобразование в символьное значение. Макропараметры очень легко конвертировать: просто добавьте " " вокруг них.

hh.output(dataset: cats('_',"&i.",year);

cats удаляет все пробелы и делает -L ненужный. Это будет работать так же хорошо с &i, хотя, конечно, лучше добавить кавычки.

Я бы добавил,что вы могли бы подумать, почему вы их подставляете. Я не думаю, что в этом есть что-то концептуально неправильное, но есть вероятность, что если вы делаете что - то по годам, вы можете использовать by year и уйти от их подстановки-сохраняя их в одном наборе данных для каждой группы лечения (и, возможно, даже by group year?). Кроме того, вы можете сделать это за меньшее количество шагов. Что ты собираешься делать, наконец? Предположим, у вас был один набор данных для каждой группы/года. Какой код вы бы тогда запустили? Возможно, вы можете написать это за один или несколько шагов, не разбивая наборы данных 48x14, что, вероятно, не эффективно. Если вам интересно это выяснить, начните новый вопрос с подробных сведений о том, что вы хотели бы сделать с помощью всего лишь пары наборов данных.

Чтобы обратиться к вашей конкретной точке относительно выходной Линии: -

hh.output (dataset: '_'||&i||put(year, best.-L)) ;

Несколько примечаний: -

  • аргумент dataset должен быть заключен в кавычки, например ..(dataset: "Out123"). В настоящее время ваша-нет.
  • Главный макрос не имеет доступа к переменной макроса &i. Он создается в вызывающем макросе и доступен только в этой области. Вы можете добавить другой параметр в основной макрос и отправить &i таким образом.

По правде говоря, код, который вы создаете, выглядит очень трудно поддерживать; хэш в макросе-это кошмар для отладки. И если вы создаете код, который создает множество выходных наборов данных, которые должны вызвать сигнал тревоги; оператор by в SAS позволяет применять критерии к отдельным группам в наборе данных и определенно предпочтителен для многих наборов данных.

Давайте посмотрим на проблему: вы сопоставляете элементы управления с лечением, используя переменные, которые дадут несколько контрольных групп на лечение? Затем вы выберете элемент управления per лечение, основанное на некоторых критериях дистанции?

Для первой части слияние Proc SQL звучит примерно правильно. Вы получите длинный набор данных, в котором каждая лечебная фирма повторяет количество раз, когда она была сопоставлена с контролем. Затем отсортируйте по treatment descending [distance criteria] и выберите первый из них для группы by. И это должно быть так. Конечно, я уверен, что что-то неправильно понял...

Заключительная точка; вы можете просто искать соответствующие алгоритмы в SAS, особенно "оптимальное соответствие" или "жадное соответствие". В моем опыт, SAS не очень хорош для сопоставления, особенно если он включает случайный элемент (ваш-нет), но вы должны быть в состоянии найти код более полезным, чем то, с чем вы работаете прямо сейчас.

Я думаю, что вы можете значительно упростить приведенный выше код, используя подстановочные знаки в операторе set вместо использования нескольких операторов set для "циклического перебора".

Например, приведенный ниже код будет проходить через все ваши наборы данных, начинающиеся с одного из префиксов, чтобы вы могли работать с ними без нескольких операторов set.
data all;
  set out1:
      out2:
      out3:
      out4:
      ;
run;
Это может даже позволить вам устранить необходимость в макросе, что в свою очередь упростит код. Этот существующий код выглядит очень сложно поддерживать / отлаживать, поэтому я думаю, что упрощение - это первый шаг.

Comments

    Ничего не найдено.