前面我们介绍在实际应用中,整理和分析的数据可能是来自多个数据源,这就需要对多个数据集进行处理,如合并、转置、修改、更新等操作。今天我们将介绍数据集的处理。(详见图4-1)  数据的预处理是为数据的最终分析结果提供质量保证,即从原始数据中构造用于分析的最终数据集,包括:数据集的合并、变量和观测的选择、数据转换和清理等。接下来将从SAS数据集的调用、变量的处理、观测的处理、数据集的处理四个方面来介绍SAS实现。4.1 数据集的纵向合并
数据集的纵向合并是指将两个或两个以上数据集的观测首尾连接成一个数据集。数据集的纵向合并可以通过DATA步的SET语句、PROC APPEND程序、PROC SQL程序来实现。
*===创建合并数据集,两个数据集有重复观测; PROCIMPORTDATAFILE="E:\studyfile\Jindingtongji\SAS\score.xlsx" OUT=score_a DBMS=excel REPLACE; RANGE="A$"; RUN; PROCIMPORTDATAFILE="E:\studyfile\Jindingtongji\SAS\score.xlsx" OUT=score_b DBMS=excel REPLACE; RANGE="B$"; RUN; *===DATA步SET语句合并数据集,并删除重复观测; PROCSORTDATA=score_a; BY name; RUN; PROCSORTDATA=Score_b; BY name; RUN; DATA score; SET score_a score_b; BY name; IF first.name THEN OUTPUT; RUN; *===DATA步SET语句合并数据集,PROCSORT删除重复观测; DATA score_ab; SET score_a score_b; RUN; PROCSORTdata=score_ab OUT=score_ab1 DUPOUT=score_dup /*重复观测输出到score_dup数据集*/ NODUPKEY; BY name; RUN; *===DATA步SET语句合并数据集,PROCSORT过程步中的NODUP=选项删除重复观测; DATA score1; SET score_a score_b; RUN; PROC SORT DATA=score_ab OUT=score_ab1 NODUP; BY name; RUN; *===PROC APPEND过程纵向合并数据集; PROC APPENDbase=score_a data=score_b; RUN; PROC PRINTDATA=score_a; RUN; *===PROC SQL并运算生成数据集,删除重复观测; PROCSQL; CREATETABLEscore_u AS SELECT * FROM score_a UNION /*score_u数据集包含数据集score_a 和数据集score_b中所有的观测,删除重复观测*/ SELECT * FROM score_b; QUIT; *===PROC SQL外并数据集,未删除重复观测; PROCSQL; CREATETABLEscore_oc as SELECT * FROM score_a OUTERUNIONCORR SELECT * FROM score_b; QUIT; *===PROC SQL差运算生成数据集; PROCSQL; CREATETABLEscore_e AS SELECT * FROM score_a EXCEPT /*从数据集score_a中删除数据集score_b的行, 两个数据集有一个重复观测,新生成的数据集 不包括该重复观测和score_b的观测*/ SELECT * FROM score_b; QUIT; *===PROC SQL交运算生成数据集; PROCSQL; CREATETABLEscore_i AS SELECT * FROM score_a INTERSECT /*score_i数据集仅包含数据集score_a 和数据集score_b中共同的观测*/ SELECT * FROM score_b; QUIT; 4.2 数据集的横向合并
*===创建数据集; DATA score1; INPUT id $ name $ gender $ @@; DATALINES; X001 Jack M X002 Joyce F X003 LouiseF X004 Alice F X005 James M X006 ThomasM X007 John M X008 Jane F X009 Janet F ; RUN; DATA score2; INPUT id $ chinese math english@@; DATALINES; X001 93 55 62 X002 63 57 83 X003 50 69 88 X005 60 62 84 X006 95 75 78 X008 66 98 51 X010 79 81 92 X011 77 78 58 X012 81 89 88 ; RUN; *===DATA步MERGE语句全连接; PROCSORTdata=score1; BY id; RUN; PROCSORTdata=score2; BY id; RUN; DATA score_m; MERGE score1 score2; BY id; IF s1 or s2; RUN; *===DATA步MERGE语句左连接; DATA score_ml; MERGE score1(in=s1) score2(in=s2); BY id; IF s1; RUN; *===DATA步MERGE语句右连接; DATA score_mr; MERGE score1(in=s1) score2(in=s2); BY id; IF s2; RUN; *===DATA步MERGE语句内连接; DATA score_mi; MERGE score1(in=s1) score2(in=s2); BY id; IF s1 and s2; RUN; DATA步的MERGE语句可以用BY语句也可以不用BY语句实现横向合并。用BY语句的合并称为匹配合并,匹配合并在数据集处理中应用非常广泛。SAS在编译MERGE命令阶段,会按照数据集的排列排序,依次读入所有数据集中变量的描述部分,并置于PDV中,若不同的数据集中有同名的变量,则要求其数据类型必须相同,长度以第一次出现的变量为准。 执行MERGE命令时,SAS将各输入数据集中的观测按BY语句指定的变量进行匹配,在DATA步的每次循环中依次读入BY语句组合的每条观测,如遇到同名变量,先读入的变量值将会被后读入的变量值覆盖。从数据集中读入的变量值,会自动保留到BY变量值在所有输入数据集中都改变为止。不用BY语句的通常称为一对一合并,在实际应用时,一对一合并的情况并不多见,因此在这里没有介绍。*===PROC SQL全连接; PROCSQL; CREATETABLEscore12_f AS SELECT * FROM score1 FULLJOIN score2 ON score1.id=score2.id; QUIT; *===PROC SQL左连接; PROCSQL; CREATETABLEscore12_l AS SELECT * FROM score1 LEFTJOIN score2 ON score1.id=score2.id; QUIT; *===PROC SQL右连接; PROCSQL; CREATETABLEscore12_r AS SELECT * FROM score1 RIGHTJOIN score2 ON score1.id=score2.id; QUIT; *===PROC SQL内连接; PROCSQL; CREATETABLEscore12_in AS SELECT * FROM score1 INNERJOIN score2 ON score1.id=score2.id; QUIT; 4.3 行列转置 在实际中,我们需要对数据集的行列进行转置来满足我们进一步分析数据。数据集的行列转置可能通过DATA步和PROC TRANSPOSE过程步来实现。PROC TRANSPOSE过程步的语法如下: 
*===创建数据集; DATA score; INPUT id $ chinese math english@@; DATALINES; X001 93 55 62 X002 63 57 83 X003 50 69 88 X005 60 62 84 X006 95 75 78 X008 66 98 51 X010 79 81 92 X011 77 78 58 X012 81 89 88 ; RUN; *===PROCTRANSPOSE行转置表列; PROCTRANSPOSEdata=score out=score_tr; VAR chinese math english; /*列出要转置的变量名*/ BY id; /*对每个BY组进行转置,在输入数据集中没有被转置的变量*/ RUN; *===PROCTRANSPOSE列转置行; PROCTRANSPOSEdata=score_tr out=score1(DROP=_name_); VAR score; /*列出要转置的变量名*/ BY id; /*对每个BY组进行转置,在输入数据集中没有被转置的变量*/ ID course; /*转置后数据集的变量名*/ RUN; *===DATA步DO-END+ARRAY实现行转置列; DATA score_do(KEEP=id course score); SET score; ARRAY courses{3} chinese math english; /*需要转置的变量*/ DO i=1to3; course=vname(courses{i}); /*转置后的变量名*/ score=courses(i); /*转置后的变量值*/ OUTPUT; END; RUN; *===DATA步的DO-END语句+ARRAY语句实现列转置行; DATA score2(DROP=i course score); FORMAT id chinese math english; ARRAY name{3} chinese math english; /*转置后的变量名*/ DO i=1TO3; SET score_do; name{i}=score; /*转置后的变量值*/ END; RUN; PROC TRANSPOSE是一个比较复杂的过程,在处理大数据集时会非常耗费时间,而DATA步行列转置的运行速度要快的多。对于多元分析和重复测量数据分析时进行行列转置,PROC TRANSPOSE是非常方便的。PROC TRANSPOSE与DATA步语句组合,可以实现很多非常复杂的行列转置。需要注意的是,DATA步行转列与列转行的差别:(1)行转列时,DO循环包含SET语句,不使用OUTPUT语句;(2)列转行时,DO循环独立于SET语句,需要使用OUTPUT语句。整理不易,欢迎点亮再看哦! 参考文献: [1] 谷鸿秋. SAS编程演义[M]. 北京:清华大学出版社,2017. [2] 高惠璇. SAS系统Base SAS软件使用手册[M]. 北京:中国统计出版社,1997. [3] https://support./en/software/base-sas-support.html. [4] 夏庄坤, 徐唯, 潘红莲, 等. 深入解析SAS—数据处理、分析优化与商业应用[M]. 北京: 机械工业出版社,2014. 整理不易,欢迎点亮再看!
|