如何用数组简化SAS中Proc SQL多列重复聚合操作?
SAS用数组简化患者事件汇总代码
需求背景
现有SAS数据集morbidity,包含患者编号列Pat_TNO和20个以morb_开头的事件列(取值1=No,2=Yes),同一患者存在多行数据。需要生成新数据集,汇总每位患者是否至少发生过各类事件,替代原来需要手动写20个max()的Proc SQL代码。
解决方案:DATA步+数组实现
Proc SQL不支持数组操作,因此用DATA步结合BY分组+数组来自动处理所有morb_开头的列,无需逐个列名编写:
步骤1:按患者编号排序(BY分组要求数据集有序)
proc sort data=morbidity; by Pat_TNO; run;
步骤2:用数组汇总事件状态
data morbidity_summary; set morbidity; by Pat_TNO; /* 定义数组,自动匹配所有以morb_开头的变量 */ array morb_events[*] morb_:; /* 仅在患者第一行数据时初始化:默认所有事件为No(1) */ if first.Pat_TNO then do; do i = 1 to dim(morb_events); morb_events[i] = 1; end; end; /* 遍历更新事件状态:只要某行事件为Yes(2),就保留为Yes */ do i = 1 to dim(morb_events); if morb_events[i] = 2 then retain morb_events[i]; end; /* 只输出患者最后一行,即汇总后的结果 */ if last.Pat_TNO then output; /* 指定保留的变量 */ keep Pat_TNO morb_:; /* 给所有morb_列应用YN.格式 */ format morb_: yn.; run;
代码说明
array morb_events[*] morb_::通过通配符morb_:自动捕获所有以morb_开头的列,不管列名是morb_amputation还是morb_mi都能匹配,无需手动列出20个列名by Pat_TNO:按患者编号分组,first.Pat_TNO标记当前患者的第一行数据,last.Pat_TNO标记最后一行retain语句:确保事件状态为Yes(2)时,后续行不会覆盖这个值,最终保留患者是否发生过该事件的结果- 最后只输出患者的最后一行,得到每位患者的汇总数据
另一种写法:用MAX函数直接取最大值
因为2(Yes)大于1(No),也可以用max()函数直接更新事件状态,逻辑更直观:
data morbidity_summary; set morbidity; by Pat_TNO; array morb_in[*] morb_:; array morb_out[*] morb_:; /* 保留输出变量的值 */ retain morb_out:; /* 初始化患者首行数据 */ if first.Pat_TNO then do; do i = 1 to dim(morb_out); morb_out[i] = 1; end; end; /* 逐行取最大值,只要出现过2就保留2 */ do i = 1 to dim(morb_in); morb_out[i] = max(morb_out[i], morb_in[i]); end; if last.Pat_TNO then output; keep Pat_TNO morb_:; format morb_: yn.; run;
内容的提问来源于stack exchange,提问作者jackahall
相关产品推荐
相关产品推荐

