如何按ID与Start-End统一SAS数据集的Place变量值为1?
SAS分组统一更新Place变量解决方案
问题背景
现有SAS数据集have:
data have; input ID $ (Start End) (:date.) Place $; format start end date9.; cards; 0001 13JAN2015 20JAN2015 . 0001 13JAN2015 20JAN2015 1 0001 13JAN2015 20JAN2015 . 0001 21JAN2015 31DEC2015 . 0001 01JAN2018 31DEC2018 . 0001 01JAN2019 31DEC2019 . 0002 01JAN2015 31DEC2015 1 0002 01JAN2015 31DEC2015 . 0002 01JAN2015 31DEC2015 1 ;
需要实现:按ID+Start-End区间分组,只要组内有观测的Place=1,就把该组所有观测的Place改成1;组内没有1的,保留原缺失值。最终得到have1数据集。
解法1:PROC SQL(简洁高效)
用分组聚合先判断每组是否存在1,再关联回原数据更新:
proc sql; create table have1 as select h.ID, h.Start, h.End, /* 组内有1就设为1,否则保留原Place */ case when g.has_1 = 1 then '1' else h.Place end as Place from have h left join ( /* 子查询:按分组统计是否有Place=1 */ select ID, Start, End, max(Place = '1') as has_1 from have group by ID, Start, End ) g on h.ID = g.ID and h.Start = g.Start and h.End = g.End order by ID, Start, End; quit;
逻辑解释:
- 子查询里
max(Place='1')会返回1(组内有1)或0(没有),因为比较表达式在SAS里会自动转成1/0 - 主查询通过关联把这个标记带回原数据集,用
case语句统一替换Place值
解法2:DATA步+PROC SUMMARY(直观易读)
先统计分组标记,再合并更新:
/* 第一步:用PROC SUMMARY生成每组的标记 */ proc summary data=have nway; class ID Start End; /* 指定分组变量 */ var Place; /* 输出组内Place的最大值:只要有1,max就是1 */ output out=group_mark(keep=ID Start End max_place) max=max_place; run; /* 第二步:合并原数据和标记,更新Place */ data have1; merge have group_mark; by ID Start End; if max_place = '1' then Place = '1'; drop max_place; /* 删掉临时标记变量 */ run;
逻辑解释:
PROC SUMMARY的nway参数只保留全分组的结果,max(Place)能直接拿到组内的最高值,只要有1就会返回1- 用
merge按分组变量合并,直接判断标记更新Place,逻辑简单直观
解法3:纯DATA步(无需额外过程)
如果不想用PROC过程,纯DATA步也能实现,前提是先排序:
/* 先按分组变量排序,保证BY组处理的顺序 */ proc sort data=have; by ID Start End; run; data have1; set have; by ID Start End; retain group_has_1; /* 跨观测保留组内标记值 */ /* 每组的第一个观测时,初始化标记并检查组内是否有1 */ if first.End then do; group_has_1 = 0; /* 遍历当前组的所有观测,找是否有Place=1 */ do i = _n_ to _n_ + (last.End - first.End); set have(keep=Place) point=i; if Place = '1' then do; group_has_1 = 1; leave; /* 找到就退出循环,节省资源 */ end; end; end; /* 根据标记更新Place */ if group_has_1 = 1 then Place = '1'; drop group_has_1 i; run;
逻辑解释:
retain变量用来跨观测保存组内的标记状态- 在每组的第一个观测(
first.End)时,用point=指针遍历当前组的所有观测,判断是否存在1 - 后续观测直接用标记更新Place,无需重复判断
内容的提问来源于stack exchange,提问作者NewUsr_stat
相关产品推荐
相关产品推荐

