Sas 满足条件时按组跳转到下一个
我有一个记录婚姻状况变化的文件——身份证、变化类型(婚姻、离婚、丧偶)和变化年份(和月份)。我想计算每个人在任何给定年份的婚姻状况(已婚、离婚、寡妇(呃)、从未结婚)。因为一个人可以经历许多更改,而我的文件大约有2000万行,所以当我找到答案时,我想跳到下一个人,而不是继续浏览那个人的所有其他记录 我想按ID和更改日期降序排序,然后按ID设置。对于每个ID,如果我感兴趣的年份大于(或等于)更改年份,则计算婚姻状况并输出ID和婚姻状况。如果没有,则继续下一个记录,直到满足条件。如果没有符合条件的记录,则婚姻状况=从未结婚Sas 满足条件时按组跳转到下一个,sas,Sas,我有一个记录婚姻状况变化的文件——身份证、变化类型(婚姻、离婚、丧偶)和变化年份(和月份)。我想计算每个人在任何给定年份的婚姻状况(已婚、离婚、寡妇(呃)、从未结婚)。因为一个人可以经历许多更改,而我的文件大约有2000万行,所以当我找到答案时,我想跳到下一个人,而不是继续浏览那个人的所有其他记录 我想按ID和更改日期降序排序,然后按ID设置。对于每个ID,如果我感兴趣的年份大于(或等于)更改年份,则计算婚姻状况并输出ID和婚姻状况。如果没有,则继续下一个记录,直到满足条件。如果没有符合条件的记
data a;
length type_change $10;
input ID type_change yr_change mnth_change;
cards;
1 marriage 2006 9
1 divorce 2010 5
10 marriage 2005 2
10 divorce 2012 10
10 marriage 2016 8
23 marriage 2017 6
35 marriage 2002 7
35 widow 2013 12
;
run;
2015年,我希望得到:
-身份证婚姻状况
-1离婚
-10离婚
-23从未结过婚
-35丧偶
提前谢谢 然后使用retain语句 提取所有ID:
proc sort data=a out=ids(keep= id) nodupkey ;
by id;
run;
生成所有ID所需的所有年份
data years;
set ids;
must_be_date=2000;
do i = 1 to 20;
must_be_date+1;
output;
end;
drop i;
run;
按条件加入:
proc sql;
create table res as
select *
from years left join a on years.must_be_date = a.yr_change and a.id = years.id
;
run;
proc sort ;
by id must_be_date;
run;
使用保留:
data res;
retain temp "never been married";
set res;
by id must_be_date;
if first.id then temp="never been married";
if type_change="" then type_change = temp;
else temp=type_change;
run;
检查:
data res_2015;
set res;
where must_be_date=2015;
run;
结果表:
+--------------------+----+--------------+-------------+-----------+-------------+
| temp | ID | must_be_date | type_change | yr_change | mnth_change |
+--------------------+----+--------------+-------------+-----------+-------------+
| divorce | 1 | 2015 | divorce | . | . |
| divorce | 10 | 2015 | divorce | . | . |
| never been married | 23 | 2015 | never been | . | . |
| widow | 35 | 2015 | widow | . | . |
+--------------------+----+--------------+-------------+-----------+-------------+
/*仅执行一次此排序并保存已排序*/
proc sort data=have out=sorted;
由id yr_更改;
跑
proc sort data=have(keep=id)out=ids nodupkey;
按身份证;
跑
数据步骤1;
集合排序;
其中,yr_change如果跳过的意思是不阅读它们,则不能“跳过”观察结果。但您可以使用IF语句(或其他条件逻辑)忽略它们
使用“保留”和“分组处理”应该可以得到答案
%let year=2015;
data want ;
set a ;
by id yr_change mnth_change ;
length status $20;
retain status ;
if first.id then status='never been married ';
if yr_change <= &year then status=type_change ;
if last.id;
keep id status;
run;
如果您可以访问ID的主列表,则可以转换为使用WHERE语句,这可能会减少处理所有记录所需的I/O。例如,将ID列表与婚姻状况更改记录的子集合并
data want;
merge id_list a(in=in2 where=(yr_change <= &year));
by id;
length status $20;
retain status ;
if first.id then status='never been married ';
if in2 then status=type_change ;
if last.id;
keep id status;
run;
需要数据;
合并id_列表a(in=in2,其中=(yr_changeDOW循环将允许您计算组的结果。隐式输出将保存为组计算的结果。由于结果取决于您感兴趣的年份,因此您还需要在任何创建的数据集中跟踪该结果
%let YEAR_CUTOFF = 2015;
data want (keep=id status year_cutoff);
attrib
id length = 8
status length=$20 label="Status at year end &YEAR_CUTOFF"
year_cutoff length = 8
;
retain year_cutoff &YEAR_CUTOFF;
status = 'never been married';
do until (last.ID); /* The DOW loop */
set have (rename=status=status_of_interest);
by id;
if year <= &YEAR_CUTOFF then status = status_of_interest;
end;
/* No explicit OUTPUT in the step, so,
* an implicit OUTPUT occurs here at the bottom of the step
*/
run;
%let YEAR\u CUTOFF=2015;
需要数据(保留=身份证状态年份\截止日期);
阿特里布
id长度=8
状态长度=$20 label=“年终状态和年终截止状态”
年份\截止长度=8
;
保留年度截止和年度截止;
状态='从未结婚';
直到(last.ID);/*道循环*/
设置有(重命名=状态=感兴趣的状态);
按身份证;
如果你有一份所有人的名单,那可能已经结婚了吗?我有一份所有人的名单。在这里,我关注的是那些至少结过一次婚的人,因为从未结过婚的人很容易处理。根据抽样的数据和你的代码,我得到了:1-离婚10-离婚35个寡妇。没有23个I-在你改变的地方删除col中的空格umn名称“类型更改”这给了我ID=1的“从未结婚”而不是离婚。我只是编辑以从<更改为>。很抱歉,需要做更多的编辑,但这会给我一个巨大的表来保存和处理。我有1300万人,可以追溯到1900年。我相信他指的是跳过,实际上可以使用where而不是if来避免IO对于效率更高的PDV,建议的解决方案处理了所有2000万条记录,我相信用户希望避免这些记录。注意,如果源是外部数据库,则WHERE只能提供显著的性能改进,在外部数据库中过滤观察结果将减少从数据库到SAS的数据传输。但这将有丢失的风险识别ID=23这样的主题的能力。因此需要提供ID列表的另一个来源。在这一点上,我会与你有所不同。也许对于这样一个狭窄/相对较小的数据集,这是真的。我们已经在磁盘中的数据集上做了基准测试,大约有1000亿条记录,每个记录都有200-300个属性,其中在使用if时,使用which over if是非常重要的。在某些情况下,它可能很重要。访问可用于减少从磁盘读取的I/O块数的索引。磁盘I/O相对于内存/CPU速度的相对速度。使用if状态时,观察范围极广将需要更多内存到内存的传输t、 谢谢大家。我不想处理所有2000万条记录。在“set have(rename=status=status\u of interest)”行中状态是指类型改变吗?如果是,那么ID 1,10是已婚而不是离婚。是的,status
是type\u change
。我可能将其编码为阅读@Tom答案的人工制品。你的yr\u change
在我的代码中只是year
,这就是你看到的原因,运行copy/paste ha人类的危险因理解而减轻。
data want;
merge id_list a(in=in2 where=(yr_change <= &year));
by id;
length status $20;
retain status ;
if first.id then status='never been married ';
if in2 then status=type_change ;
if last.id;
keep id status;
run;
%let YEAR_CUTOFF = 2015;
data want (keep=id status year_cutoff);
attrib
id length = 8
status length=$20 label="Status at year end &YEAR_CUTOFF"
year_cutoff length = 8
;
retain year_cutoff &YEAR_CUTOFF;
status = 'never been married';
do until (last.ID); /* The DOW loop */
set have (rename=status=status_of_interest);
by id;
if year <= &YEAR_CUTOFF then status = status_of_interest;
end;
/* No explicit OUTPUT in the step, so,
* an implicit OUTPUT occurs here at the bottom of the step
*/
run;