SAS 中的多个 do 循环

Multiple do loops in SAS

我有一个 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;

这不起作用,因为当第一个值为空时它不会填充 WEEK0。

如果需要更多信息,请发表评论,我会添加。

如果是长格式,您可以这样做。长格式时您可能不需要它。

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;
    

您需要第二个索引变量,将其命名为 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;

听起来你只需要找到复制的起点。

首先按日历月查看收入列表,直到找到第一个非缺失值。然后按相对月份将从那里开始的值复制到新的收入数组中。

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 和我都喜欢从一开始计数,而不是零。