在 SAS 中使用保留语句在组内创建相同的值
creating same values within a group using retain statement in SAS
我正在尝试创建一个变量 z,它将根据组内第一个观察值的两个变量 X 和 Y 的值在组内取相同的值。根据组中第一个观察值的 X 和 Y 值,一个组可以采用 4 个可能的 Z 值。
Z=1 (if X=1 & Y=1),
Z=2 (if X=2 & Y=1),
Z=3 (if X=1 & Y=2), and
Z=4 (if X=2 & Y=2).
这就是我所拥有的,也是我想要的。
X has two values, 1 or 2, within a group; while Y can take 1, 2 ,3.
Y is sorted in ascending order
if the first (or all group observations) take a value of 3, the resulting Z
value should be set to missing
这是我的:
Obs Group X Y
1 10600 1 1
2 10600 1 2
3 10600 1 3
4 10800 2 1
5 10800 2 3
6 10900 1 2
7 10900 1 3
8 11100 2 2
9 11100 2 2
10 11100 2 3
11 11100 2 2
12 11200 2 3
13 11300 2 1
14 11300 2 2
15 11300 1 3
16 11300 1 3
17 11300 1 3
18 11300 1 3
这就是我想要的:
Obs Group X Y Z
1 10600 1 1 1
2 10600 1 2 1
3 10600 1 3 1
4 10800 2 1 2
5 10800 2 3 2
6 10900 1 2 3
7 10900 1 3 3
8 11100 2 2 4
9 11100 2 2 4
10 11100 2 3 4
11 11100 2 2 4
12 11200 2 3 .
13 11300 2 1 2
14 11300 2 2 2
15 11300 1 3 .
16 11300 1 3 .
17 11300 1 3 .
18 11300 1 3 .
谢谢!
您是正确的,retain
ed 变量将在数据步骤的前向迭代中携带一个值。名义上,具有单个 set
语句的简单数据步骤一次迭代将对应于数据集中的一行。
您的保留变量将在组的开头分配,因此您将需要一个 by
语句,这反过来使自动标志变量 first.<by-group-var>
可用。
data have; input
Group X Y; datalines;
10600 1 1
10600 1 2
10600 1 3
10800 2 1
10800 2 3
10900 1 2
10900 1 3
11100 2 2
11100 2 2
11100 2 3
11100 2 2
11200 2 3
11300 2 1
11300 2 2
11300 1 3
11300 1 3
11300 1 3
11300 1 3
run;
带有 group=11300
的最后一组行有 x=2
,后跟 x=1
。你的叙述
within a group
传达了一个想法,但并不明确准确。实际分组(基于显示的需求)似乎是 group
和 x
的组合。因此,您需要
by group x notsorted;
声明。 notsorted
将导致数据步骤设置 first.
和 last.
基于值的连续性而不是值的显式排序。
data want;
set have;
by group x nostsorted;
retain z;
if first.x then do; * detect first row in combinations "group/x";
select;
when (X=1 & Y=1) Z=1; * apply logic for retained value;
when (X=2 & Y=1) Z=2;
when (X=1 & Y=2) Z=3;
when (X=2 & Y=2) Z=4;
otherwise Z=.;
end;
end;
logic_tracker_first_x = first.x;
run;
ods listing; options nocenter;
proc print data=want;
run;
输出window显示
logic_tracker_
Obs Group X Y z first_x
1 10600 1 1 1 1
2 10600 1 2 1 0
3 10600 1 3 1 0
4 10800 2 1 2 1
5 10800 2 3 2 0
6 10900 1 2 3 1
7 10900 1 3 3 0
8 11100 2 2 4 1
9 11100 2 2 4 0
10 11100 2 3 4 0
11 11100 2 2 4 0
12 11200 2 3 . 1
13 11300 2 1 2 1
14 11300 2 2 2 0
15 11300 1 3 . 1
16 11300 1 3 . 0
17 11300 1 3 . 0
18 11300 1 3 . 0
请尝试使用以下解决方案,我使用了更简单的方法,即每个组仅保留第一个 Z 变量,然后对同一数据集进行左连接,以在同一组的剩余观测值中保留第一个 z 变量-
data test;
input group 5. x 1. y 1.;
if x=1 and y=1 then z=1;
else if x=2 and y=1 then z=2;
else if x=1 and y=2 then z=3;
else if x=2 and y=2 then z=4;
datalines;
1060011
1060012
1060013
1080021
1080023
1090012
1090013
1110022
1110022
1110023
1110022
1120023
1130021
1130022
1130013
1130013
1130013
1130013
;
run;
data test1;
set test;
keep group x z;
run;
proc sort data=test1; by group x; run;
data keep_first;
set test1;
by group x;
if first.group or first.x;
run;
proc sql;
create table final
as
select a.group, a.x, a.y, b.z
from test a
left join keep_first b
on a.group=b.group
and a.x=b.x
order by a.group, a.y, a.x;
quit;
我正在尝试创建一个变量 z,它将根据组内第一个观察值的两个变量 X 和 Y 的值在组内取相同的值。根据组中第一个观察值的 X 和 Y 值,一个组可以采用 4 个可能的 Z 值。
Z=1 (if X=1 & Y=1),
Z=2 (if X=2 & Y=1),
Z=3 (if X=1 & Y=2), and
Z=4 (if X=2 & Y=2).
这就是我所拥有的,也是我想要的。
X has two values, 1 or 2, within a group; while Y can take 1, 2 ,3.
Y is sorted in ascending order
if the first (or all group observations) take a value of 3, the resulting Z
value should be set to missing
这是我的:
Obs Group X Y
1 10600 1 1
2 10600 1 2
3 10600 1 3
4 10800 2 1
5 10800 2 3
6 10900 1 2
7 10900 1 3
8 11100 2 2
9 11100 2 2
10 11100 2 3
11 11100 2 2
12 11200 2 3
13 11300 2 1
14 11300 2 2
15 11300 1 3
16 11300 1 3
17 11300 1 3
18 11300 1 3
这就是我想要的:
Obs Group X Y Z
1 10600 1 1 1
2 10600 1 2 1
3 10600 1 3 1
4 10800 2 1 2
5 10800 2 3 2
6 10900 1 2 3
7 10900 1 3 3
8 11100 2 2 4
9 11100 2 2 4
10 11100 2 3 4
11 11100 2 2 4
12 11200 2 3 .
13 11300 2 1 2
14 11300 2 2 2
15 11300 1 3 .
16 11300 1 3 .
17 11300 1 3 .
18 11300 1 3 .
谢谢!
您是正确的,retain
ed 变量将在数据步骤的前向迭代中携带一个值。名义上,具有单个 set
语句的简单数据步骤一次迭代将对应于数据集中的一行。
您的保留变量将在组的开头分配,因此您将需要一个 by
语句,这反过来使自动标志变量 first.<by-group-var>
可用。
data have; input
Group X Y; datalines;
10600 1 1
10600 1 2
10600 1 3
10800 2 1
10800 2 3
10900 1 2
10900 1 3
11100 2 2
11100 2 2
11100 2 3
11100 2 2
11200 2 3
11300 2 1
11300 2 2
11300 1 3
11300 1 3
11300 1 3
11300 1 3
run;
带有 group=11300
的最后一组行有 x=2
,后跟 x=1
。你的叙述
within a group
传达了一个想法,但并不明确准确。实际分组(基于显示的需求)似乎是 group
和 x
的组合。因此,您需要
by group x notsorted;
声明。 notsorted
将导致数据步骤设置 first.
和 last.
基于值的连续性而不是值的显式排序。
data want;
set have;
by group x nostsorted;
retain z;
if first.x then do; * detect first row in combinations "group/x";
select;
when (X=1 & Y=1) Z=1; * apply logic for retained value;
when (X=2 & Y=1) Z=2;
when (X=1 & Y=2) Z=3;
when (X=2 & Y=2) Z=4;
otherwise Z=.;
end;
end;
logic_tracker_first_x = first.x;
run;
ods listing; options nocenter;
proc print data=want;
run;
输出window显示
logic_tracker_
Obs Group X Y z first_x
1 10600 1 1 1 1
2 10600 1 2 1 0
3 10600 1 3 1 0
4 10800 2 1 2 1
5 10800 2 3 2 0
6 10900 1 2 3 1
7 10900 1 3 3 0
8 11100 2 2 4 1
9 11100 2 2 4 0
10 11100 2 3 4 0
11 11100 2 2 4 0
12 11200 2 3 . 1
13 11300 2 1 2 1
14 11300 2 2 2 0
15 11300 1 3 . 1
16 11300 1 3 . 0
17 11300 1 3 . 0
18 11300 1 3 . 0
请尝试使用以下解决方案,我使用了更简单的方法,即每个组仅保留第一个 Z 变量,然后对同一数据集进行左连接,以在同一组的剩余观测值中保留第一个 z 变量-
data test;
input group 5. x 1. y 1.;
if x=1 and y=1 then z=1;
else if x=2 and y=1 then z=2;
else if x=1 and y=2 then z=3;
else if x=2 and y=2 then z=4;
datalines;
1060011
1060012
1060013
1080021
1080023
1090012
1090013
1110022
1110022
1110023
1110022
1120023
1130021
1130022
1130013
1130013
1130013
1130013
;
run;
data test1;
set test;
keep group x z;
run;
proc sort data=test1; by group x; run;
data keep_first;
set test1;
by group x;
if first.group or first.x;
run;
proc sql;
create table final
as
select a.group, a.x, a.y, b.z
from test a
left join keep_first b
on a.group=b.group
and a.x=b.x
order by a.group, a.y, a.x;
quit;