如果你管着一份10000条的客户数据,有一天,老板拿着一个500人的表告诉你,这表上的500位客户的信息发生了变动,而且变动的变量很不规律,如客户102是收入发生了变动、客户126是职业发生了变动....,叫你在10000条的那个客户主数据中改一下,你怎么办?
用合并?用IF筛选有没有变动?还是一个一个手动去改?都不需要,用update语句更新一下即可。
本节目录:
6.1 使用SET语句复制数据集
6.2 使用SET语句堆叠数据
6.3 使用SET语句插入数据集
6.4 一对一匹配合并数据
6.5 一对多匹配合并数据
6.6 合并统计量与原始数据
6.7 合并total和原始数据
6.8 update:用交易数据更新主数据
6.9 使用数据集选项
6.10 使用in=option追踪观测值
6.11 output:写多维数据集
6.12 output:将一个观测值变成多个
6.13 proc transpose:将观测值转变为变量
6.14 使用SAS内置变量
【SAS Says】基础篇:6. 开发数据(复制、合并、更新、输出、转置)
6.1 使用SET语句复制数据集
SET语句可以复制数据集。基本形式为:
DATA new-data-set;
SET data-set;
Data语句指定了新数据集名,set指定要读取的老数据集名。如果不想创建新的,则也可以在data中指定老数据集。
下面的代码创建了一个Friday的新数据集,将sales数据集中的day属于Friday的观测值复制,并创建了新变量total:
例子 有一份关于火车运汽车的数据,汽车主为了在高峰期节省时间,或者为了节省汽油,选择让火车运汽车的方法,变量依次为:
一天中发车的时间、火车上的汽车数、火车中的人数:
数据被读入一个永久数据集trains中,储存在MYSASLIB目录文件夹下:
由于每辆车的最大乘客数为6人,现在想知道一列火车上,平均每两汽车的乘客数是多少,可以在数据中插入一列,但这不在原始数据中计算,而是在一个新数据集中计算:
结果如下:
6.2 使用set语句堆叠数据
运用set语句可以把一个数据集堆在另一个数据集上,如上图所示,适用于两个变量相同的两个数据集。基本形式为:
DATA new-data-set;
SET data-set-1 data-set-n;
首先指定一个新的数据集,然后列出需要合并的旧数据集。
如果一个数据集包含了另一个数据集没有的变量,那么合并后,该变量下将会出现缺失值。
例子 有如下两份南北数据,北方数据比南方多了一行变量(最后一行),其他变量均相同:
下面有三段代码,前两段将南方和北方的数据各输入数据集,并打印。第三段使用SET语句将南北方数据合并,并创建了新变量,AmountPaid:
输出结果如下:
6.3 使用SET语句插入数据集
前面的堆叠数据,可能把数据顺序打乱,当然可以再用proc sort再将数据排序。但这可能效率低下。在set语句中使用by语句可以高效率的将数据按顺序合并,基本形式为:
DATA new-data-set;
SET data-set-1 data-set-n;
BY variable-list;
BY语句中,可以指定一个或多个变量,让SAS进行排序。
注意,在合并几个数据之前,每个数据都要用BY进行排序,如果没有,则要用proc sort完成。
例子 仍然是刚才的例子:
注意南方的数据已经按照pass number(第二个变量)进行了排序,北方的没有。下面还是三段代码,第一段对南方的数据输入,打印。第二段对北方的数据输入、排序、打印。第三段进行合并,并创建新变量INTERLEAVE。
下面是输出结果:
6.4 一对一匹配合并数据集
横向合并数据集:
(1)首先一定要排序!使用sort过程按照匹配变量排序。
(2)之后在data语句中对新SAS数据集命名。
(3)再使用merge语句列出要合并的数据集名。使用BY语句说明共同变量。
DATA new-data-set;
MERGE data-set-1 data-set-2;
BY variable-list;
注意,如果两个数据集有重叠的变量——除了BY变量,那么第二个数据集中的此变量会覆盖第一个数据集中的。
例子 有一个巧克力店记录了每天所卖巧克力的类型以及数量,第一个文件sales data记录了所卖的巧克力代码和数量,第二个记录了巧克力代码、所代表的类型、描述。
下面有三段代码:
前两段读取sales数据,description数据。
后者已经对codenum变量进行排序,前者需要用proc sort进行排序。否则会出现错误的信息:ERROR:BY variables are
not properly sorted
结果如下:
注意K086的销售记录缺失,因为sales data中没有关于其的记录。
6.5 一对多匹配合并数据
一对多合并是指一个数据集中的一个观测值可以与另一个数据集中的多个观测值匹配。基本形式与一对一一样:
DATA new-data-set;
MERGE data-set-1 data-set-2;
BY variable-list;
注意数据集的顺序,一对多的一要放在前面。在进行合并之前,仍然要对两个数据集按照匹配变量进行排序。其他注意与6.4差不多。
例子 有一份关于鞋子打折的数据,其中训练鞋、跑步鞋、走路鞋的折扣各不同。第一份数据是关于鞋子的风格、类型、价格。第二份数据是关于每个类型鞋子的折扣:
下面的代码用多对一合并了两个数据:
结果如下:
6.6 合并统计量与原始数据
当你想比较每一个观测值和一组变量的均值时,可以先使用proc means计算统计量,并保存输出文件,再与原始文件合并。
例子 有一份关于鞋子销量的数据,变量为鞋子风格、类型、销量。现在想列出每种类型鞋子里,各风格的销售量所占的百分比:
代码:
描述统计量的结果summarydata如下:
合并后的数据如下:
6.7 合并total和原始数据
可以通过means过程创建一个包含总计(不是分组总计)的数据集。但不能直接与原始数据合并,因为没有匹配变量。幸运的是,可以用两个set语句:
DATA new-data-set;
IF_N_=1 THEN SET summary-data-set;
SET original-data-set;
原始数据包含了不止一个观测值,而summary数据集只有一个观测值。只在数据步的第一次迭代中,SAS读取了summary数据集,之后为新数据的所有变量记住这个变量值。
它的工作原理在于SET语句是自动记住的。往常之中,记住的变量会被下一个观测值改写,但这里变量只在第一次迭代的时候读取,并为所有观测值记住,这一技术适用于没有匹配变量的情况下,将一个单个观测值合并到多个观测值中。
例子 与上节同样的例子,现在想看每种类型的鞋子销量占总销量的百分比:
代码为:
输出结果为:
6.8 update:用交易数据更新主数据
update语句用来更新大量新数据信息。如上图显示的那样,左边是主数据,右边是交易数据,现在
- id=2的数据出现了更新,第二个变量变成了2;
- id=3的数据,第一个变量需要更新成b;
- 另外数据还要更新的是增加了id=5的数据。
对于这样的更新需求,如何操作?
update语句提供了这种操作,与merge语句一样,按照匹配变量来更新数据,不同点在于:
- 匹配变量的变量值有唯一性(即不允许出现两个一样id的数据)。
- 交易数据的缺失值不会改写主数据中存在的值。
基本形式为:
DATA master-data-set;
UPDATE master-data-set transaction-data-set;
BY variable-list;
只能指定两个数据集,一个是主数据集一个是交易数据,都需要按照匹配变量排序。且BY变量必须具有唯一性。
例子 一家医院有一份关于病人的主数据。变量依次为病人账户号码、名字、地址、出生日期、性别、保险代码、信息最后被更新的时间。
当有新病人,或其他病人再进医院时,信息会被更新,比如,第一个病人的保险代码被更换了、最后一个病人的缺失数据被填补上、有新病人加入:
下面的代码将这个数据放入一个名为patientmaster的永久数据集中,目录为C盘下的MySASLib:
下面的代码读取交易数据并排序,使用update语句将交易数据更新到主数据中。
输出结果如下:
6.9 使用数据集选项
前面已经见过很多选项,SAS语言主要有三种选项:系统选项、语句选项、数据集选项。系统选项有全局影响力,而数据集选项的影响力有限。
系统选项在SAS会话或工作期间都有效,包括center选项,它告诉SAS,center所有的输出。以及LINESIZE=option,设置输出中每一行的最大长度。
语句选项出现在某个语句中,影响某一个数据步或者过程步。
数据集选项影响的只是SAS如何读取和写入一个单个的数据集,可以在数据步(DATA,SET,MERGE,or UPDATE 语句)和过程步(conjuctionwith a DATA=statement option)中使用。用法是,接在数据集名之后,用括号括起来。有些最常见的选项:
- KEEP=variable-list 告诉SAS保留哪个变量
- DROP=variable-list 告诉SAS丢弃哪个变量
- RENAME=(oldvar=newvar) 重命名某个变量
- FIRSTOBS=n 从观测值n开始读取变量
- OBS=n 到观测值n停止读取
- IN=new-var-name 猜一猜,这个是干什么的?
选择并重命名变量 下面是关于KEEP=,DROP=,和RENAME=的数据集选项的例子:
KEEP=,DROP=,和RENAME=的作用与keep、drop、rename很相似。区别在于,后者适用于数据步中的所有变量,而前者仅使用与语句前面的那个数据集。而且,后者仅可以在数据步中使用,而前者除了数据步和过程步,还可以在输入和输出数据集中使用。
用observation number选择观测值 可以使用FIRSTOBS=和obs=来选择读取哪些观测值
这也类似于同名的语句选项和同名的系统选项,语句选项只适用于infile语句,数据集选项是用于数据步和过程步中存在的数据集,而系统选项适用于所有的文件和数据集。如果同时使用同样的系统选项和数据集选项,那么后者将覆盖前者。
追踪观测值 这里提到的选项都是针对现有的变量,而in=option则自己创建一个新变量。这个新变量是临时的,并且有自己在选项中指定。下面的例子,SAS创建了两个临时变量:InAnimals和InHabitat:
该变量只存在于现在的过程步中。
6.10 使用in=option追踪观测值
如果将数据集a、b合并,那么在合并的数据集中,你知道那个是来自a哪个是来自b吗?in=option,就是用来追踪原始数据集对应新数据集中的哪个观测值。
In=data选项可以被用在数据步中的任何地方——SET,MERGE或者UPDATE——但大部分用在merge语句上,接在要追踪的数据集后面。
下面的数据步创建了一个both数据集,合并两个数据集,state和ounty。并用in=Option创建了两个变量InState和 InCounty:
创建的变量是临时的,只存在于数据步期间。SAS给新变量赋值为0和1。比如county数据集没有关于Louisiana的数据(Louisiana只有parishes,没有counties),因此上例中,两个数据集都含有一个关于Louisiana的观测值,InState变量下的这个观测值为1,InCounty的为0。
Instate和InCounty经常被用在IF或IF-THEN语句中,最为筛选:
Subsetting IF: IF InState=1; IF InCounty=0; IF InState=1 AND InCounty=1; IF-THEN: IF InCounty=1 THEN Origin=1; IF InState=1 THEN State='Yes';
例子 一家运动品厂商有两份数据,一个包括所有客户的数据,一份包括了第三季度订单的数据。现在想要了解哪些客户在第三季度没有任何订单,即可以用in=option选项。客户数据包括客户编号、姓名、地址;订单数据包括客户编号、总价格:
发现没有订单客户的代码如下,数据步中创建了新变量recent,如果出现在客户数据中的观测值没有出现在order中,则recent赋为0,否则赋为1。
结果如下:
6.11 output:写多维数据集
有时候想在一个数据步中创建多个数据,可以在DATA语句后面多接几个数据集名即可,如下语句告诉SAS创建三个数据集:LIONS、
TIGERS、和 BEARS:
DATA lions tigers bears;
这样仅仅是创建了三个一样的数据集,如果想创建不同的,可以用output语句。
每一个数据步的结尾都有一个暗含的output语句,它告诉SAS在处理下一个观测值之前,将当前的观测值写入输出数据集中。可以用自己的output语句来推翻这个暗含的output语句,基本形式为:
OUTPUT data-set-name;
如果遗漏了数据集名,则将被写入数据步中所有的数据集中去,output可以单独使用,也可以使用在IF-THEN或DO-loop过程中:
IF family='Ursidae' THEN OUTPUT bears;
例子 有一份关于动物园给动物喂食的数据,变量为动物类型、生物学分类、居住区域、喂食是否在早上/下午/两者:
下面的代码创建了两个列表,一个是早上喂食,一个是下午喂食:
日志:
输出报告为:
6.12 output:将一个观测值变成多个
SAS通常在数据步结尾将一个观测值写入数据中,但可以写入多个观测值,在DO loop中或单独使用output语句。
例子 下面的代码阐述如何在DO LOOD语句中使用output语句来产生一个数据集。
这个代码没有INPUT或SET语句,故整个数据步中只有一次迭代——但包括了DO LOOP中的六次循环。由于OUTPUT语句在DO LOOP循环中,因此每次循环都会创建一个观测值。如果没有OUTPUT语句,SAS仅会写入一个观测值,因为结尾处暗含的OUTPUT语句:
例子 有一份关于三个电影院的门票销售数据,记录了月份、电影院名称、门票销售额:
现在需要将电影院名作为一个变量、销售额作为一个变量、月份重复三次。
下面的代码使用三次input语句读取同一个原始文件。第一个读取变量month、location和tickets,并用@停留住数据行,接着用OUTPUT语句输出这个观测值。下一个INPUT读取这行后面的名、销售额,并再停留住行。接着读取,但释放行,进入下一个迭代。这个代码用output语句使每一行创建了三个观测值:
结果为:
6.13 proc transpose:将观测值转变为变量
transpose过程可以转置数据集,将观测值转变为变量或将变量转变为观测值。不部分情况下,将观测值转变为变量,可以使用下面代码:
PROC TRANSPOSE DATA=old-data-set OUT=new-data-set;
BY variable-list;
ID variable;
VAR variable-list;
ID语句 ID语句命名变量,这些变量值将变成新的变量名,ID变量在一个数据集中只能发生一次,如果有BY语句,那么在一个by-group中,变量值必须是唯一的。如果ID变量是数值型变量,新的变量名必须有一个下划线作为前缀(_1 or_2,for example)。如果不适用ID语句,新变量将命名为COL1,COL2等。
VAR语句 VAR语句命名变量,这个变量的变量值是要转置的。
例子 有一份关于儿童棒球联盟选手的数据,包括队名、选手编号、数据类型(salary or batting average)、以及entry:
现在想考察平均打击数与salary之间的关系,首先要将salary和平均打击数变量变量。下面的代码读取数据、按照队伍、选手排序数据,再转置数据:
在proc transpose这步中,BY变量是team和player。ID变量是type,它的值salary和batavg将是新变量名,将要转置的变量entry在VAR语句中指定。注意原来是变量名的entry,现在作为_name_变量下面的变量值。结果为:
6.14 使用SAS内置变量
SAS有一些自动变量,这些变量看不到,是临时并不会被储存。但在数据步中,可以任意使用。
_N_和_ERROR_ _N_记录了SAS在数据步中循环的次数,它不一定等于循环次数。因为诸如IF语句就可以使迭代次数与观测数不一致。如果一个观测值的数据出现错误,_ERROR_会被赋值为1,否则赋值为0。错误数据包括无效数据(数值型格式变量却赋为字符串值),转换错误(0作为除数),函数中不合法的自变量(log(0))。
FIRST.variable和LAST.variable 当使用BY语句时,这两个变量才有效。SAS处理一个观测值时,如果某个变量的新变量值是第一次出现,first.variable被赋值为1,其他观测值中被赋为0。LAST.variable是同理的某变量的变量值是最后一次出现时,赋为1,其他赋为0。
例子 有一份不知道绕着镇中心走路比赛的数据,变量为entry number、age group和 finishing time。注意每行不止一个观测值:
第一件要做的事情是为完成情况创建一个新变量。下面代码读取数据,按照finishing time排序,另一个数据步创建新变量place,并赋给它当前的_N_值,print过程产生finishers列表:
第二段代码给出了每个年龄组的第一名:BY语句中自动产生了first.variable,后面的IF语句保留了每个年龄组的第一个观测值,由于数据是按照年龄组agegroup和time排序的,因此第一个观测值就是第一名。结果为: