Создание фиктивных строк в SAS от последней даты входа до указанной даты - PullRequest
0 голосов
/ 30 августа 2018

Предположим, у меня есть следующий набор данных SAS:

Account  Month  Balance  LastMonth   MonthDate    LastMonthDate
1        Jan    5        May         2012-01-01  2012-05-01
1        Feb    2        May         2012-02-01  2012-05-01
1        Mar    1        May         2012-03-01  2012-05-01
2        Feb    6        Apr         2012-02-01  2012-04-01
2        Mar    4        Apr         2012-03-01  2012-04-01

Мне нужно создать следующее:

Account  Month  Balance  LastMonth   MonthDate    LastMonthDate
1        Jan    5        May         2012-01-01  2012-05-01
1        Feb    2        May         2012-02-01  2012-05-01
1        Mar    1        May         2012-03-01  2012-05-01
1        Apr    1        May         2012-04-01  2012-05-01
1        May    1        May         2012-05-01  2012-05-01
2        Feb    6        Apr         2012-02-01  2012-04-01
2        Mar    4        Apr         2012-03-01  2012-04-01
2        Apr    4        Apr         2012-04-01  2012-04-01

То есть мне нужно добавить дополнительные строки для каждой учетной записи, чтобы у каждой учетной записи была запись для каждого месяца вплоть до столбца «LastMonth». Для месяцев, которых нет в исходном наборе данных, баланс должен поддерживаться постоянным с балансом последней записи в наборе данных. Мой набор данных уже отсортирован по «Учетной записи» и «Месяцу».

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

Редактировать: «MonthDate» и «LastMonthDate» хранятся следующим образом: enter image description here

Ответы [ 2 ]

0 голосов
/ 30 августа 2018

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

Ключевые понятия

  • с использованием LAG и INTCK для поиска пропусков внутри группы
  • с использованием INTNX для вычисления итераций цикла
  • поддержание состояния с помощью переменных поддержки, которые позже были удалены

Пример кода

Предполагается, month и lastmonth являются правильными переменными даты

data have;
attrib account format=8. month format=yymon7. informat=date9. lastmonth format=yymon7. informat=date9.;
input
Account  Month        Balance  LastMonth; datalines;
1        01-Jan-18    5        01-May-18
1        01-Feb-18    2        01-May-18
1        01-Mar-18    1        01-May-18
2        01-Feb-18    6        01-Apr-18
2        01-Mar-18    4        01-Apr-18
3        01-Jan-18    15       01-May-18
3        01-Mar-18    11       01-May-18
run;

data want;
  do _n_ = 1 by 1 until (last.account);

    set have;
    by account;

    prior_month = lag(month);
    prior_balance = lag(balance);

    * fill-in gaps within group;
    if _n_ > 1 and intck('month', prior_month, month) > 1 then do;
      curr_month = month;
      curr_balance = balance;

      balance = prior_balance;

      gap_start = intnx('month', prior_month, 1);
      gap_end   = intnx('month', curr_month, -1);

      * repeat prior observed months data for missing months;
      do month = gap_start by 0 until (month >= gap_end);
        OUTPUT;
        put 'NOTE: ' account= 'within-group gap data output ' month= balance=;

        month = intnx('month', month, 1);
      end;

      * restore original state;
      month = curr_month;
      balance = curr_balance;
    end;

    * unconditional output for within group data;
    OUTPUT;
  end;

  gap_start = intnx('month', month, 1);
  gap_end   = intnx('month', lastmonth, 0); * just for saftey sake;

  * conditional output for post-group months using data from last row in group ;
  do month = gap_start by 0 until (month > gap_end);
    OUTPUT;
    put 'NOTE: ' account= '  post-group gap data output ' month= balance=;    
    month = intnx('month', month, 1);
  end;

  drop prior_: curr_: gap_:;
run;
0 голосов
/ 30 августа 2018

Вам необходимо проверить, находитесь ли вы в последней строке учетной записи (требуется, чтобы данные были отсортированы по учетной записи). Затем преобразуйте строковые месяцы в числа, переберите их и выведите новое имя месяца.

EDIT

Исходя из комментариев, этот шаг данных будет работать с вашими данными. Сохранил старый ответ для дополнительной информации:

data want;
set have;
by account;

output;

if last.account then do;
    /*Current month as a number*/
    month_n = month(MonthDate);
    /*LastMonth as a number*/
    to_month = month(LastMonthDate);

    do i=month_n+1 to to_month;
        month = put(mdy(i,1,2000),monname3.); /*Increment the month and write the month name*/
        output;
    end;
end;

drop month_n to_month i;
run;

Конец РЕДАКТИРОВАТЬ

К сожалению, в SAS нет простого формата или информации для преобразования между месяцами в виде строк и чисел. Поэтому здесь я делаю их даты и извлекаю номер месяца с помощью функции month():

data want;
set have;
by account;

output;

if last.account then do;
    /*Current month as a number*/
    month_n = month(input(catt("01",strip(month),"2000"),date9.));
    /*LastMonth as a number*/
    to_month = month(input(catt("01",lastMonth,"2000"),date9.));

    do i=month_n+1 to to_month;
        month = put(mdy(i,1,2000),monname3.); /*Increment the month and write the month name*/
        output;
    end;
end;

drop month_n to_month i;
run;

Вы всегда можете создать свой собственный формат и информацию для преобразования. Это сделает код немного чище.

proc format;
value MName 1="Jan"
             2="Feb"
             3="Mar"
             4="Apr"
             5="May"
             6="Jun"
             7="Jul"
             8="Aug"
             9="Sep"
             10="Oct"
             11="Nov"
             12="Dec";

invalue MName "Jan"=1
             "Feb"=2
             "Mar"=3
             "Apr"=4
             "May"=5
             "Jun"=6
             "Jul"=7
             "Aug"=8
             "Sep"=9
             "Oct"=10
             "Nov"=11
             "Dec"=12;
run;

data want2;
set have;
by account;

output;

if last.account then do;
    /*Current month as a number*/
    month_n = input(month,MName.);
    /*LastMonth as a number*/
    to_month = input(lastMonth,MName.);

    do i=month_n+1 to to_month;
        month = put(i,MName.);
        output;
    end;
end;

drop month_n to_month i;
run;
...