Sas: итерация от начала до даты окончания в макросе

У меня есть такой набор данных:

DATA tmp;
    INPUT
        identifier $
        d0101 d0102 d0103 d0104 d0105 d0106
        d0107 d0108 d0109 d0110 d0111 d0112
    ;
    DATALINES;
    a 1 2 3 4 5 6 7 8 9 10 11 12
    b 4 5 7 4 5 6 7 6 9 10 3 12
    c 5 2 3 5 5 4 7 8 3 1 1 2
    ;
RUN;

И я пытаюсь создать такой набор данных:

DATA tmp;
    INPUT
        identifier $ day value
    ;
    DATALINES;
    a '01JAN2018'd 1
    a '02JAN2018'd 2
    a '03JAN2018'd 3
    a '04JAN2018'd 4
    a '05JAN2018'd 5
    a '06JAN2018'd 6
    a '07JAN2018'd 7
    a '08JAN2018'd 8
    a '09JAN2018'd 9
    a '10JAN2018'd 10
    a '11JAN2018'd 11
    a '12JAN2018'd 12
    b '01JAN2018'd 4
    b '02JAN2018'd 5
    b '03JAN2018'd 7
    ...
    ;
RUN;

Я знаю синтаксис для «плавления» такого набора данных - я выполнил аналогичный макрос для столбцов, представляющих конкретное значение в каждом из двенадцати месяцев в году.

Я борюсь с тем, как перебирать все дни с начала года (предполагается, что в наборе данных have все дни с начала года представлены в виде столбцов).

Я привык к Python, поэтому мог бы кое-что сделать там:

>>> import datetime
>>> 
>>> def dates_ytd():
...     end_date = datetime.date.today()
...     start_date = datetime.date(end_date.year, 1, 1)
...     diff = (end_date - start_date).days
...     for x in range(0, diff + 1):
...         yield end_date - datetime.timedelta(days=x)
... 
>>> def create_date_column(dt):
...     day, month = dt.day, dt.month
...     day_fmt = '{}{}'.format('0' if day < 10 else '', day)
...     month_fmt = '{}{}'.format('0' if month < 10 else '', month)
...     return 'd{}{}'.format(month_fmt, day_fmt)
... 
>>> result = [create_date_column(dt) for dt in dates_ytd()]
>>> 
>>> result[:5]
['d1031', 'd1030', 'd1029', 'd1028', 'd1027']
>>> result[-5:]
['d0105', 'd0104', 'd0103', 'd0102', 'd0101']

Вот моя попытка SAS:

%MACRO ITER_DATES_YTD();
    DATA _NULL_;
        %DO v_date = '01012018'd %TO TODAY();
            %PUT d&v_date.;
            * Will do "melting" logic here";
        %END
%MEND ITER_DATES_YTD;

Когда я запускаю это, используя %ITER_DATES_YTD();, в моем журнале даже ничего не печатается. Что мне здесь не хватает? Я в основном хочу перебирать столбцы "YTD", например эти d0101, d0102, d0103, ....

У вас уже есть набор данных SAS? Или у вас просто есть необработанный текстовый файл, похожий на ваши данные? Если у вас есть необработанные данные в такой форме, их несложно прочитать прямо в вертикальной структуре.

Tom 31.10.2018 19:31

Это набор данных SAS с этими столбцами d0101d0102 в качестве заголовков.

blacksite 31.10.2018 19:35

Итак, последующий вопрос: можете ли вы исправить источник для доставки данных в другом формате, который было бы проще использовать?

Tom 31.10.2018 19:40
1
3
428
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это скорее проблема транспонирования, чем проблема макроса / шага данных.

Основная проблема заключается в том, что у вас есть данные в метаданных, то есть «дата» закодирована в именах столбцов.

Пример 1:

Транспонируйте данные, затем используйте значения d<yymm>_name_ для вычисления фактической даты.

proc transpose data=have out=have_t(rename=col1=value);
  by id;
run;

data want (keep=id date value);
  set have_t;

  * convert the variable name has day-in-year metadata into some regular data;
  date = input (cats(year(today()),substr(_name_,2)),yymmdd10.);

  format date yymmdd10.;
run;

Пример 2:

Сделайте транспонирование на основе массива. Переменные D<mm><dd> используются в роли value_at_date, и их легко объединить в массив благодаря согласованному соглашению об именах. Функция VNAME извлекает исходное имя переменной из ссылки на массив и вычисляет значение даты из части <mm><dd>.

data want;
  set have;
  array value_at_date d:;

  do index = 1 to dim(value_at_date);
    date = input(cats(year(today()),substr(VNAME(value_at_date(index)),2)), yymmdd10.);
    value = value_at_date(index);
    output;
  end;

  format date yymmdd10.;
  keep id date value;
run;

Чтобы перебирать даты, вы должны сначала преобразовать их в числа, а затем извлечь из них часть даты.

%macro iterateDates();
    data _null_;
        %do i = %sysFunc(inputN(01012018,ddmmyy8.)) %to %sysFunc(today()) %by 1;
            %put d%sysFunc(putN(&i, ddmmyy4.));
        %end;
    run;
%mend iterateDates;

%iterateDates();

Я думаю, что '01012018'd обрабатывается только в шаге данных, а не в коде макроса. И имейте в виду, что сначала выполняется код макроса, и только затем выполняется шаг данных. Вы можете думать об этом как о создании кода SAS с помощью макросов SAS и его последующем запуске.

Другие вопросы по теме