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;
如果你真的需要它:
- 找到第一个不缺失的值并将索引存储在 i
- 从 i 循环到周末维度
将周分配给 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 和我都喜欢从一开始计数,而不是零。
我有一个 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;
如果你真的需要它:
- 找到第一个不缺失的值并将索引存储在 i
- 从 i 循环到周末维度
将周分配给 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 和我都喜欢从一开始计数,而不是零。