Несколько циклов do в SAS - PullRequest
       28

Несколько циклов do в SAS

0 голосов
/ 29 января 2019

У меня есть набор данных о деньгах, заработанных в процентах, каждую неделю в 2017–2018 годах. У некоторых нет данных в начале 2017 года, так как они не начали зарабатывать позже.Недели нумеруются как 201701, 201702 - 201752 и 201801 - 201852.

Я хотел бы иметь 104 новые переменные с именем WEEK0 - WEEK103, где WEEK0 будет иметь первое непустое значение столбцаколонки заработанные деньги.Вот пример данных:

MON_EARN_201701      MON_EARN_201702      MON_EARN_201703    MON_EARN_201704
     30                     21                  50                 65   
     .                       .                  30                 100   
     .                      102                 95                 85    

Затем я хочу, чтобы в моих данных были следующие столбцы (пример)

WEEK0      WEEK1      WEEK2      WEEK3
  30         21         50         65
  30        100          .          .
  102        95         85          .

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

Я подумал, что мне нужно попытаться сделать какие-то циклы do, поэтому до сих пор я пробовал:

DATA want;
SET have;
ARRAY mon_earn{104} mon_earn_201701 - mon_earn_201752 mon_earn_201801 -mon_earn_201852;
ARRAY WEEK {104} WEEK0 - WEEK103;
DO i = 1 to 104;
IF mon_earn{i} NE . THEN;
WEEK{i} = mon_earn{i};
END;
END;
RUN;

Это не работает, как не работаетt заполнить WEEK0, когда первое значение пусто.

Если вам нужна дополнительная информация, пожалуйста, прокомментируйте, и я добавлю ее.

Ответы [ 3 ]

0 голосов
/ 29 января 2019

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

Этот пример кода «выжмет» все пропущенные доходы;даже те недостающие доходы, которые возникают после некоторого заработкаНапример,

заработок: . . . 10 . 120 . 25 … сократится до
неделя: 10 120 25 …

data have;
  array earn earn_201701-earn_201752 earn_201801-earn_201852;
  do _n_ = 1 to 1000;
     call missing (of earn(*));
     do _i_ = 1 + 25 * ranuni(123) to dim(earn);
       if ranuni(123) < 0.95 then
         earn(_i_) = round(10 + 125 * ranuni(123));
     end;
     output;
  end;
run;

data want;
  set have;
  array earn earn_201701-earn_201752 earn_201801-earn_201852;
  array week(0:103);

  j = -1;
  do i = 1 to dim(earn);
    if not missing(earn(i)) then do;
      j+1;
      week(j) = earn(i);
    end;
  end;

  drop i j;
run;

Если вы хотите сохранить внутренние недостающие доходы, логика будет

    if not missing(earn(i)) or j >=0 then do;
      j+1;
      week(j) = earn(i);
    end;
0 голосов
/ 29 января 2019

Похоже, вам просто нужно найти отправную точку для копирования.

Сначала просмотрите список доходов по календарному месяцу, пока не найдете первое не пропущенное значение.Затем скопируйте значения, начиная с этого, в новый массив доходов по месяцам.

data want;
  set have;
  array mon_earn mon_earn_201701 -- mon_earn_201852;
  array week (104);
  do i = 1 to dim(mon_earn) until(found);
    if mon_earn{i} ne . then found=1;
  end;
  do j=1 to dim(week) while (i+j<dim(mon_earn));
    week(j) = mon_earn(i+j-1);
  end;
run;

ПРИМЕЧАНИЕ. Я упростил определения ARRAY.Для входного массива я предположил, что переменные определены по порядку, чтобы вы могли использовать список позиционных массивов.Для массива WEEK SAS и мне нравится начинать считать с одного, а не с нуля.

0 голосов
/ 29 января 2019

Вы могли бы сделать это, если бы это был длинный формат.Есть вероятность, что вам это не нужно, когда вы находитесь в длинном формате.

proc sort data=have;
by ID week;
run;

data want;
set have;
by id; *for each group/id counter;
retain counter;
if first.id then counter=0; 
if counter=0 and not missing(value) then do;
counter=1; new_week=0; end;
if counter = 1 then new_week+1;
run;

Если вам действительно это нужно в широком формате:

  1. Найдите первое не пропущенное значение и сохраните индекс в i
  2. Цикл от измерения i до конца недели
  3. Назначение недели для mon_earned от i до конца недели.

    data want;
        set have;
        array mon_earned(*) .... ;
        array week(*) ... ;
        found=0; i=0;
    
        do while(found=0);
           if not missing(mon_earned(i)) then found=1;
           i+1;
        end;
    
        z=0;
        do j=i to dim(week);
            week(z) = mon_earned(j); 
            z+1;
        end;
    run;
    
...