SAS- улучшение кода для модификации нескольких наборов данных с помощью макроса

#loops #macros #sas

#циклы #макросы #sas

Вопрос:

Я пытаюсь изменить все наборы данных (имена наборов данных следуют определенным порядкам, таким как data_AXPM061203900_20120104, data_AXPM061203900_20120105, data_AXPA061204100_20120103, data_AXPA061204100_20120104) в рабочей библиотеке. Например, я хочу удалить все отсутствующие значения из переменной с именем «ask_price» во всех наборах данных.

введите описание изображения здесь

Для достижения этой цели я использую следующее.

  proc sql ;
      create table data.mytables as
      select *
      from dictionary.tables
      where libname = 'WORK' 
      order by memname ;
    quit ;


%macro test;
  proc sql ;
    select count(memname) into: obs from data.mytables;

  %let obs=amp;obs.;

    select catx("_", "data", substr(memname, 6, 13), substr(memname,20,27))
    into :setname1-:setnameamp;obs.
    from data.mytables;
quit;


%do i=1 %to amp;obs.;

data  amp;amp;setnameamp;i;
set  amp;amp;setnameamp;i;

if bid_price= '.' then delete;
%end;

%mend test;

%test;
  

Кто-то предположил, что «Это, возможно, наименее эффективная (с точки зрения программирования) настройка, которую вы можете иметь. Каждый раз, когда вы получаете доступ к этим данным, вам нужно проходить все циклы, проверки, получение данных из имени файла и т.д. что является бессмысленным ресурсом и подвержено ошибкам.» Однако он не дал мне подробного решения. В этом случае кто-нибудь может дать мне дополнительные рекомендации?

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

1. Вероятно, вам нужно дать здесь немного больше контекста. Для конкретной задачи, о которой вы упомянули, это на порядок выше оптимального. Но сама структура данных — это, на мой взгляд, бессмыслица, если только это не необходимо по какой-то причине для всего проекта, для понимания которого здесь просто недостаточно контекста. Вероятно, это можно было бы улучшить — я не понимаю, почему вы, например, восстанавливаете имена переменных, разве они уже не правильные? — но общий подход хорош, учитывая существующую структуру данных .

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

3. Я имею в виду, зачем вы это делаете? select catx("_", "data", substr(memname, 6, 13), substr(memname,20,27)) Почему это не то же самое, что select memname ?

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

5. Вы заявили, что хотите удалить пропущенные ЗНАЧЕНИЯ, но ваш код удаляет НАБЛЮДЕНИЯ, в которых отсутствует значение для определенной переменной. Делает ли пример кода то, что вы хотите? Или вы имели в виду что-то другое?

Ответ №1:

Обратите внимание, что удаление наблюдений из ваших существующих наборов данных, вероятно, является плохой идеей, потому что, если есть какая-либо ошибка, вы потеряете свои исходные данные. Но давайте просто предположим, что вы позаботились об этом в какой-то другой части общего процесса.

Итак, если вы хотите удалить наблюдения из нескольких существующих наборов данных, когда переменная bid_price отсутствует, то, возможно, вы можете просто использовать PROC SQL. Сначала вам нужно сгенерировать список наборов данных. Затем вам нужно сгенерировать отдельный оператор УДАЛЕНИЯ для каждого набора данных, чтобы удалить наблюдения.

Этот код сгенерирует код в переменной макроса. Таким образом, это будет ограничено максимальной длиной макропеременной (64 КБ) в количестве наборов данных, которые она может обработать.

 proc sql noprint ;
  create table dslist as
    select distinct 
        libname
      , memname 
    from dictionary.columns 
    where libname='WORK'
      and memname like 'DATA_APX%'
      and upcase(name)='BID_PRICE'
  ;
  %let code=;
  select catx(' ','delete * from',catx('.',libname,memname)
                 ,'where missing(bid_price)')
    into :code separated by ';'
    from dslist
  ;
  amp;code;
quit;
  

Ответ №2:

еще одна проблема с исходным кодом: если bid_price= ‘.’ затем удалите; bid_price — это числовое значение, и вы сравниваете его с символьным значением (точка в кавычках делает его символьным значением). Если вы собираетесь использовать этот тип кода, то он должен быть таким: if bid_price= . затем удалите; Однако я предпочитаю использовать функцию «отсутствует», которая работает как для символов, так и для чисел: если отсутствует (bid_price), затем удалите;

Почти всегда есть несколько способов выполнить заданную задачу в SAS.