月度时序数据按12个月间隔长转宽的SAS代码优化问询
长时序数据转12个月窗口期宽格式单步SAS实现
前置要求
输入数据集pd_base_std需提前完成排序:proc sort data=pd_base_std; by descending credit_id date_obs; run;,保证同一账户的观测按时间先后顺序排列。
实现代码
data pd_base_ttd2 pd_base_std pd_base_all; /* 定义变量格式、存储12个月激活日期的数组,声明跨观测保留的变量 */ format ttd best12. def_count best12.; array def_dates{0:11} Flag_actived_date1-Flag_actived_date12; retain count Flag_actived_date1-Flag_actived_date12 def_count; /* 初始化hash表,用于内存中记录已处理的观测组合 */ if _n_ = 1 then do; declare hash processed(); processed.defineKey('credit_id', 'YYYY_mm'); processed.defineDone(); end; /* 第一次读取全量原始观测,生成宽格式结果 */ set pd_base_std end=eof; by descending credit_id; /* 切换到新账户时重置所有统计变量 */ if first.credit_id then do; count = 0; def_count = 0; do i = 0 to 11; def_dates{i} = .; end; end; /* 记录Flag=1的激活日期 */ if default_flag = 1 then do; def_dates{mod(count,12)} = date_obs; def_count = def_count + 1; end; count = count + 1; /* 满足输出条件时输出宽表,同时标记该观测为已处理 */ if last.credit_id or mod(count,12) = 11 then do; output pd_base_ttd2; output pd_base_all; processed.add(key:credit_id, key:YYYY_mm, data:credit_id, data:YYYY_mm); end; /* 所有观测遍历完成后,第二次读取原始数据,过滤已处理观测生成下一轮输入 */ if eof then do; do until(ef); set pd_base_std end=ef; if processed.check(key:credit_id, key:YYYY_mm) ne 0 then do; output pd_base_std; end; end; end; drop i count; run;
优化说明
- 单步完成原多步逻辑:无需中间排序、多数据集拼接操作,内存中用hash表完成已处理观测的标记和过滤,性能更高
- 数组定义直接对齐目标输出字段,生成的
pd_base_ttd2就是你需要的宽格式结果 - 输出的
pd_base_std是过滤掉已处理观测的剩余数据,可直接用于下一轮迭代,不需要额外处理
内容的提问来源于stack exchange,提问作者py14ak
相关产品推荐
相关产品推荐

