950 likes | 1.07k Views
第四讲 数据集的编辑与修改. 金融学院 冯建芬 博学楼 913, 64495048 danxin_97@yahoo.com.cn. 内容提要. 改变变量或数据集的属性 通过数据集选项改变属性: data 语句, set 语句 通过语句改变属性: label 语句、 rename 语句、 retain 语句 ; 变量与观测的选择 选择变量: keep, drop 选项与语句 ; 选择观测: where 选项与语句, if 条件语句 ; Point 选项的应用 delete 语句 ; output 语句 ; Do-end 语句 ;
E N D
第四讲 数据集的编辑与修改 金融学院 冯建芬 博学楼 913, 64495048 danxin_97@yahoo.com.cn
内容提要 • 改变变量或数据集的属性 • 通过数据集选项改变属性:data语句,set语句 • 通过语句改变属性:label语句、rename语句、retain语句; • 变量与观测的选择 • 选择变量:keep, drop选项与语句; • 选择观测: • where选项与语句,if条件语句; • Point选项的应用 • delete语句; • output语句; • Do-end语句; • Select-when-end多项选择语句 • 变量编辑与观测修改 • 数据集拼接修改变量和观测:set语句,merge语句,update语句,modify语句,sort过程,by语句与数据集选项的应用; • 利用表达式与函数修改观测: sort过程,by语句; • 利用循环语句修改观测和变量:do-end; do-while等 • 利用数组修改观测:array语句;
涉及章节 《SAS编程技术教程》 第二章:2.4 第六章: 6.4,6.5,6.6; 第七章; 第八章; 第九章; 第十五章:15.1 帮助目录:SAS 产品Base SASSAS 语言字典SAS语言元素字典-->SAS数据集选项、函数和call子程序、语句 SAS 产品Base SASSAS 过程过程->sort过程
本章目的 本讲是最为核心和重要的一讲,将学习几乎全部的数据处理技术,本讲与第五讲(宏编程技术)结合就可以做到对数据的批处理功能。本讲的目的是: • 掌握更改变量属性的label、rename选项和语句使用; • 掌握选择变量的keep,drop选项和语句使用 • 掌握where语句、条件语句if-then-else、select-when,do-end语句以及do循环语句的使用; • 理解SAS处理数据的原理; • 掌握sort过程与by语句的重要应用; • 掌握output语句的使用; • 理解retain语句的巧用; • 理解数组的巧用;
4.3 变量编辑与观测修改 • 参见第二章:2.4 • 第三章:3.1-3.8 • 第六章:6.5,6.6 • 第八章, 第九章retain语句
一、数据集拼接修改变量和观测 多个数据集以一定的方式合成一个数据集,有两种方式: 纵向合并:set语句 横向合并:merge语句及其选项的应用;update语句及其选项应用,modify语句及其选项应用 应用举例: 1)不同股票交易数据的纵向合并 2)相同时间区间内,同一股票不同种类收益率的合并,如对数收益率与百分比收益率 3)多个表中,不同财务指标的合并 4)缺失值的保留问题
用于纵向合并的Set语句(6.5) Set语句同时读入多个数据集时,是以纵向合并的形式读入的,以两个数据集为例说明其规则如下: Data c; Set a b; Run; 设数据集a中有2个变量,10条记录,数据集b中有3个变量,20条记录,并且a中的1个变量和b中的1个变量变量名相同,则生成的数据集c中有四个不同的变量,30条记录。即记录个数为数据集中记录个数的加和(N_a+N_b),变量个数为不同名的变量总个数。
SET语句从一个或多个已存在的SAS数据集中读取观测值,并将这些观测组合在一个数据集中。SET语句从一个或多个已存在的SAS数据集中读取观测值,并将这些观测组合在一个数据集中。 语句格式: SET <data-set-name-1<(data-set-options-1)>> <… data-set-name-n <(data-set-options-n )>> <POINT=variable-name |KEY=index-name>/UNIQUE> <NOBS=variable-name > <END=variable-name >; 一个DATA步中可以有多个SET语句,一个SET语句中可以有任意个SAS数据集。
应用举例 例4.23程序a合并两个具有完全不同变量的数据集,程序b合并两个具有部分相同变量的数据集,程序c合并两个具有完全相同变量的数据集, d)使用多个set语句读入多数据集 a )data a; set data.ex_16_bp (in=id1) data.ex_16_dm (in=id2); one=id1; two=id2; run; b) data b; set data.ex_23(in=id1) data.ex_23_calendar(in=id2); Ex_23=id1; Ex_23_E=id2; run; C)data c; Set data.stk000001(in=id1 obs=10) data.stk000002(in=id2 obs=10); In1=id1; in2=id2; Run;
应用举例 d) data d; Set data.stk000001(obs=10); set data.stk000002(obs=20); Run; /*该程序共读入了10条记录,其值全部是stk000002的记录值。两个数据指针记录两个数据当前要读取记录的位置,一个PDV(数据向量)存储读取的当前记录值*/ • 注:当使用多个set语句时,相同变量的值会被 • 下一个set语句中的数据集记录替代,而data步在遇到第一个文件结束标示时结束运行。
应用举例 进一步验证: data e; Set data.stk000001(in=id1 obs=10); in1=id1; Output;/*输出当前记录到数据集d*/ set data.stk000002(in=id2 obs=20); /*读入数据到PDV,更新PDV中变量取值*/ in2=id2; Output; /*输出当前记录到数据集d*/ Run;
用于横向合并的merge语句(6.6) Merge语句可以横向合并一个或多个数据集, 将多个数据集中的观测合并为新数据集中的观测。语法格式为: MERGE data-set-name-1 <(data-set-options)> data-set-name-2 <( data-set-options)> <…data-set-name-n<(data-set-options )>> <END=variable-name >; 选项说明
Merge横向合并数据集时有两种方式: 1)一对一合并,向set语句一样,不需要任何排序变量,这种合并方式得到的结果是: 变量个数等于数据集中不同变量的总个数; 记录个数等于所有合并的数据集中记录个数的最大值,即max(n1,n2,…,nk)。 • 例4.20一对一合并,不需要by语句 • data a; • merge ResDat.class ResDat.stk000001; • run;
2) 匹配合并: 这时需要一个排序分组变量匹配多个数据集,这些数据集按照这个共有变量的排序先后进行横向合并,该变量值相同的会合并在同一条记录上。因此首先需要对要合并的数据利用sort过程进行排序。
数据集排序 --sort过程(15.1) 利用SAS的排序过程可以对数据集中的观测重新排序。 SAS有许多和BY配合使用的语句,如对数据集进行合并的语句或更新语句等,使用前必须先对BY变量进行排序。 Sort过程的语句格式: PROC SORT <option(s)> <collating-sequence-option>; BY <DESCENDING> variable-1 <...<DESCENDING> variable-n>;
选项说明: PROC SORT语句
BY语句 BY<DESCENDING>variable-1 < … < DESCENDING > variable-n > ; PROC SORT中必须使用BY语句,BY语句中可以规定任意多个变量, 优先顺序与变量顺序有关 BY语句中规定多个变量时,SORT过程首先按第一个变量排序,然后是第二个变量等。 BY语句中可以规定的选项: DESCENDING—对变量按降序排序。 (默认情况下是升序)
应用举例 例4.24按多变量排序。 data a; set data.Idx000001; year=year(date); /*year()时间函数,返回年*/ qtr=qtr(date); /*qtr()时间函数,返回季度:1,2,3,4*/ month=month(date); /*month()时间函数,返回1-12个月*/ procsortdata=a out=b; by year qtr month; /*默认是按升序排序*/ run; 例中,对上证数据Idx000001按年、季和月排序。
应用举例2 例4.25按单变量降序排列。 procsortdata= data.stk600601 out=a; bydescending clpr; procprintdata=a (obs=3) noobs; var date clpr; run; 例中,按收盘价CLPR的降序排列。
例4.26.(非常有用的例子!!) a)从data.lstkinfo中选取股票代码为000001-000005,600001,600020,600030的股票信息。 b)从data.idx399106中选取与data.stk000001交易日相同的指数数据,方便进一步进行收益率的计算与比较。 c)利用data.stk000001的收盘价clpr计算日百分比收益率,将其存到数据集r_day_000001. Merge的匹配合并举例
注意这种排序方法得到的记录数不再是用于合并的数据集中记录个数的最大值,而是排序变量每个相同记录个数最大值的加和。注意这种排序方法得到的记录数不再是用于合并的数据集中记录个数的最大值,而是排序变量每个相同记录个数最大值的加和。 即:假设将数据集a和b进行合并,排序分组变量为code, 设a中code的值有1,2,3,4四个不同的值,取值为1的记录有3个,取之为2的记录有2个,其他各有一个,而b中code的值为2,4,6,7, 期中取值为2的记录有4个,6的记录有2个,其他各有一个,则合并后的集合共有记录数为: Max(3,0)1+max(2,4)2+max(1,0)3+max(1,0)4+max(2,0) 6+max(1,0)7=11 (参见程序4-26-d)
纵向合并和by语句的结合 • 在纵向合并中也可以使用by语句,其结果使得合并的结果数据读取的先后次序打乱,而是按照分组变量的顺序交替连接数据集,但变量的数量和记录的个数与通常的纵向合并相同。 例4.27. data c; Set data.stk000001(in=id1 obs=10) data.stk000002(in=id2 obs=10); In1=id1; in2=id2; By date; Run;
MERGE语句和JOIN连接比较 所有行匹配无重复值情况 两个表中的by变量的值都相等且没有重复值的时候,可以使用一个内部连连接来产生同样的效果。 例BY变量值相等且没有重复值。 Table a Table b code manager code Assitant 145 Max 145 Tracy 150 Jack 150 Yao 155 Paul 155 Chen 程序如下: datamerge1; merge a b; by code; run; proc printdata=merge1 noobs; title 'Table MERGE1'; run;
Merge在合并前的两个数据集已经按code排过序,而PROC SQL则不需要排序,下面程序给出和上面同样的结果。 procsql; title 'Table MERGE1'; select a.code, a.manager, b.Assitant from a, b where a.code=b.code; quit;
有重复值情况 当用来连接两个表的列变量或者BY组中有重复值时,Merge和Proc sql的处理方式有所区别。 例21.9 BY组中有重复值。 Table newone Table newtwo code Manager code Assistant 145 Max 145 Jerry 145 Xam 145 Tracy 155 Paul 155 Chen Data步 data merge3; merge a b; by code; run; proc print data=merge3 noobs; title 'Table MERGE3'; run;
若用SQL,则会出现下面的结果: Proc sql; Title 'Table Merge3'; Select a.code, a.manager, b.assistant From a full join b On a.code=b.code; quit;
Update语句更新观测 Update语句利用一个数据集去更新另一个数据集中的观测值,其作用与merge相似,但update后面只能跟两个数据集,第一个是主数据集,第二个是更新数据集。 语法为: UPDATE master-data-set<(data-set-options)> transaction-data-set<(data-set-options)> <END=variable> <UPDATEMODE= MISSINGCHECK|NOMISSINGCHECK>; BY by-variable;
使用说明: • 一定和by语句连用,by语句给出主数据集和更新数据集匹配变量的名字; • 两个数据集必须事先按照by语句指定的变量排好序; • 对更新数据集存在缺失值的处理是通过updatemode选项设置,默认为missingcheck,即检查更新数据集,若其记录中存在缺失值,则保留主数据集中的相应数据,不更新该数据。这是与merge相区别的,merge没有此功能。 在实践中,update语句的主要用途在此。
例4.28 update与merge的比较 将data逻辑库中数据集merge_a中的数据利用merge_b进行更新,更新后的结果存储在新的数据集中,分别用merge和update实现。
Modify语句更新观测值 Modify语句也是通过横向合并来更新数据,它可以更新、删除或添加观测到一个已经存在的SAS数据集中。Modify语句是在没有备份的情况下处理SAS数据集,因此可以节省磁盘空间,其更新的效率高于merge或update的匹配访问方式。但也因此,该语句不能修改数据集的描述信息,如添加变量。
Modify的语句格式 语法为: (分别对应modify访问数据集的四种方式) 1)MODIFY master-data-set <(data-set-option(s))> transaction-data-set <(data-set-option(s))> <NOBS=variable> <END=variable> <UPDATEMODE=MISSINGCHECK| NOMISSINGCHECK>; BY by-variable; 2)MODIFY master-data-set <(data-set-option(s))> KEY=index </ UNIQUE> <NOBS=variable> <END=variable> ; 3) MODIFY master-data-set <(data-set-option(s))> <NOBS=variable> POINT=variable; 4) MODIFY master-data-set <(data-set-option(s))> <NOBS=variable> <END=variable>;
Modify的使用特点 和update语句一样,modify后只能有两个数据集,主数据集在前,更新数据集在后。 但使用modify语句的data步,其data语句后除非含有output语句,否则只能接一个数据集,就是主数据集。 选项说明: Nobs,end,point和key选项与set语句中的相应选项功能一致。 updatemode选项与update语句中的同名选项功能相同,取两个值missingcheck和nomissingcheck, 默认值为前者。
四种访问方式 1.匹配访问方式 即第一种modify语句的语法格式,该方式通过by语句指定标识变量,修改数据集的观测根据此变量和主数据集的观测进行匹配,对相应观测进行修改、删除和添加。 2. 通过索引直接访问(略,书P130) 3.通过观测序号直接访问: 在modify语句中通过选项point=指定更新数据集中的一个变量,该变量的值是主数据集中需要更新的观测序号。 4.顺序访问:最简单的一种
例4.29 modify的四种更新方式 以对stock数据集得更新为例看不同访问方式的使用(除索引访问方式外)。
Modify比set,merge,update更高效的原因 其查找满足条件的记录的方式是动态where语句的方式,即只读入满足条件的记录到缓存中,而不读入不满足条件的记录,因此节省了缓存空间,运行更快。 • 在实践中,modify在更新观测方面应用广泛, • 主要应用于: • 根据某些需求条件更新一些特定的变量; • 对主数据集的某些变量做历史累加;
二、利用表达式与函数修改观测 • 前面的语句主要对已经存在的观测进行合并、选择,要对观测值进行修改就只能依赖SAS表达式及其函数。(目录->SAS产品->base SAS->SAS语言字典->函数和call例程->按类别分类的函数和call例程) • 如果只对部分满足条件的观测进行修改,则需要使用条件选择语句if-then-else语句或select-when-otherwise-end语句; • 进一步如果满足条件时,需要处理多个语句,则需要结合do-end语句。 • 当然,有时还需要对某个观测多次调用同样的语句,这时就要涉及第三部分的循环语句。
SAS运行程序的原理举例 data a/debug; /*debug调试程序,让程序逐步运行*/ set data.ex_24; clpr=clpr+10; run; • SAS运行时是对记录逐条运行程序,因此, • 有些程序在SAS中会发生错误,但如果利用 • 好它的这种机制,能达到事半功倍的效果
综合应用举例 例4.30. a)计算以data.stk000001中收盘价/10对应的正态分布概率值; b)计算以data.stk000001中开盘价/10和收盘价/10对应的二维正态分布概率值,设相关系数为0; c)计算一个债券的当前价格,设其面值1000,息票率0.1, 年付息频率为4, 剩余付息次数为14,当前距最近付息的时间为0.1年,到期收益率为0.07,求当前的债券价值。 d)计算data.stk000001的日百分比收益率与日对数收益率,建立数据集a, 保留变量为date,stkcd,r_day_per, r_day_log. e)建立数据集b,读入数据集a,如果r_day_per>r_day_log,per_log赋值为1, 若r_day_per=r_day_log, per_log赋值为0, 否则 per_log赋值为-1 。
综合应用举例 例4.30续 f) 统计数据集b中per_log为1,0,-1的记录个数。 g) 建立数据集d,将数据集data.stk000001按照年、季、月排序(注意不是按照date)。 h)从数据集d读入数据,按照年、季、月分组, 计算年百分比收益率、季百分比收益率、月百分比收益率。 k)计算data.stk000001收盘价的周收益率。
RETAIN语句- 用于累乘(9.6,P204) • RETAIN语句来规定单个变量,变量列表,或数组元素的初始值。 • 语句格式: RETAIN<element-list-1<initial-value-1|(initial=value-1)|(initial-value-list-1)><…element-list-n<initial-value-n|(initial-value-n)|(initial-value-list-n)>>>; • 选项说明:
例4.31没有选项时,规定用INPUT语句或赋值语句创建的所有变量值从DATA步的这次执行到下一次重复时被保留。于是数据值在一些观测中可能保留了本应为缺失值的其它值。例4.31没有选项时,规定用INPUT语句或赋值语句创建的所有变量值从DATA步的这次执行到下一次重复时被保留。于是数据值在一些观测中可能保留了本应为缺失值的其它值。 data a; input id @@; retain; if id=1then test='pass'; if id=2then test='fail'; cards; 1 2 2 2 3 5 1 5 3 1 ; procprintnoobs; run;
打印输出结果为: • 例中,当ID的值为1或2时,都是对的。但当ID等于1和2以外的值时,没有一个IF条件是真的,故TEST没有接收新的值。由于有RETAIN语句,所以,TEST就保持从上一观测中得到的值,这样就产生错误。若从这段程序删除RETAIN语句,当ID值不等于1或2时TEST的值为空格(缺失值).
data a; 打印输出结果为: input id @@; if id=1then test='pass'; if id=2then test='fail'; cards; 1 2 2 2 3 5 1 5 3 1 ; procprintnoobs; run; 没有retain语句的情况:
Retain用于累乘 data b; set a; retain y 1; y=y*x; run; data a; input x; cards; 1 2 3 4 5 6 7 ; run; • 大家可以尝试是否 • 有其他方式可以实现累乘?
by语句在sort过程中指定排序变量, 但在数据步中,BY语句用于规定分组变量。控制SET,MERGE语句的操作,在规定分组变量之前,需要用sort过程将数据集按照分组变量排好序。 语句格式是一致的: By <Descending> <Groupformat> Variable-1 <...<Descending> <Groupformat> Variable-N> <Notsorted>; 再讲by语句(6.4,P119)
选项说明 • BY语句概念
SAS系统对每个BY组创建两个自动变量:First.variable 和 Last.variable, 用来标识每个BY组的第一个和最后一个观测。 对于一个BY组的第一个观测值,First.variable取1,其余取0. 对于一个BY组的最后一个观测值,Last.variable取1,其余取0. 这些变量不含在新产生的数据集中。 FIRST.变量和LAST.变量
例4.32保留各BY组的最后一个观测值。 data temp; setdata.stk000001; month=month(date); year=year(date); procsortdata=temp; by year month; data temp; set temp; by year month; if last.month; /*保留每月最后一个观测值,这里需要原始数据按照日期先后记录的 */ run;