数据合并,即两个或者多个数据集的数据合并到一个数据集中,常见的方式有3种,分别是 one-to-one reading、concatenating 和 Match-merging,其中只有最后一种Match-merging是要求匹配字段是已经排好序的。
在介绍之前,准备两个基础数据,是已经按照ID排好序的
cert.patdat
Obs | ID | Age | Sex | Date |
---|---|---|---|---|
1 | A001 | 21 | M | 08/17/1997 |
2 | A002 | 32 | M | 02/18/1986 |
3 | A003 | 24 | F | 06/07/1994 |
4 | A004 | 28 | M | 01/27/1990 |
5 | A005 | 44 | F | 04/24/1974 |
6 | A007 | 39 | M | 07/10/1979 |
7 | A008 | 30 | F | 09/16/1988 |
cert.visit
Obs | ID | Visit | SysBP | DiasBP | Weight | Date |
---|---|---|---|---|---|---|
1 | A001 | 1 | 140 | 85 | 195 | 11/05/2009 |
2 | A001 | 2 | 138 | 90 | 198 | 10/13/2009 |
3 | A001 | 3 | 145 | 95 | 200 | 07/04/2009 |
4 | A002 | 1 | 121 | 75 | 168 | 04/14/2009 |
5 | A003 | 1 | 118 | 68 | 125 | 08/12/2009 |
6 | A003 | 2 | 112 | 65 | 123 | 08/21/2009 |
7 | A004 | 1 | 143 | 86 | 204 | 03/30/2009 |
8 | A005 | 1 | 132 | 76 | 174 | 02/27/2009 |
9 | A005 | 2 | 132 | 78 | 175 | 07/11/2009 |
10 | A005 | 3 | 134 | 78 | 176 | 04/16/2009 |
11 | A008 | 1 | 126 | 80 | 182 | 05/22/2009 |
下面分别看一下三种方式
one-to-one reading
工作原理
![](https://i-blog.csdnimg.cn/blog_migrate/bcfd03788fa48a396ab51e76b94ce747.png)
创建一个新的数据集,新的数据集包含所有的变量。
根据每个观测在数据集中的位置去匹配,第2个数据集中变量的值会覆盖第1个数据集中变量的值。
结果集中观测的数量和数据量较少的那个数据集一样。
说简单一点,就是先从第1个数据集拿一行,然后再从第2个数据集拿一行去覆盖第1个数据集中数据。以次类推,直到有一个数据集结束。
语法
DATA output-SAS-data-set;
SET SAS-data-set-1;
SET SAS-data-set-2;
RUN;
示例
libname cert 'J:\sas_guide_data\base-guide-practice-data\cert';
data tmp1;
set cert.patdat;
set cert.visit;
run;
proc print data=tmp1;
run;
输出:
Obs | ID | Age | Sex | Date | Visit | SysBP | DiasBP | Weight |
---|---|---|---|---|---|---|---|---|
1 | A001 | 21 | M | 11/05/2009 | 1 | 140 | 85 | 195 |
2 | A001 | 32 | M | 10/13/2009 | 2 | 138 | 90 | 198 |
3 | A001 | 24 | F | 07/04/2009 | 3 | 145 | 95 | 200 |
4 | A002 | 28 | M | 04/14/2009 | 1 | 121 | 75 | 168 |
5 | A003 | 44 | F | 08/12/2009 | 1 | 118 | 68 | 125 |
6 | A003 | 39 | M | 08/21/2009 | 2 | 112 | 65 | 123 |
7 | A004 | 30 | F | 03/30/2009 | 1 | 143 | 86 | 204 |
可以看到,两个数据集都有的变量ID和Date,结果集中只出现1次,且被第2个数据集的值覆盖。
当然,上面这个例子没有实际的意义,下图中的例子才有实际的意义:
concatenating
工作原理
![](https://i-blog.csdnimg.cn/blog_migrate/45c8442e10d5701c31f8d88318bd4c34.png)
即将两个数据集连接起来
语法
DATA output-SAS-data-set;
SET SAS-data-set-1
SAS-data-set-2;
RUN;
示例
data tmp2;
set cert.patdat
cert.visit;
run;
proc print data=tmp2;
run;
输出:
Obs | ID | Age | Sex | Date | Visit | SysBP | DiasBP | Weight |
---|---|---|---|---|---|---|---|---|
1 | A001 | 21 | M | 08/17/1997 | . | . | . | . |
2 | A002 | 32 | M | 02/18/1986 | . | . | . | . |
3 | A003 | 24 | F | 06/07/1994 | . | . | . | . |
4 | A004 | 28 | M | 01/27/1990 | . | . | . | . |
5 | A005 | 44 | F | 04/24/1974 | . | . | . | . |
6 | A007 | 39 | M | 07/10/1979 | . | . | . | . |
7 | A008 | 30 | F | 09/16/1988 | . | . | . | . |
8 | A001 | . | 11/05/2009 | 1 | 140 | 85 | 195 | |
9 | A001 | . | 10/13/2009 | 2 | 138 | 90 | 198 | |
10 | A001 | . | 07/04/2009 | 3 | 145 | 95 | 200 | |
11 | A002 | . | 04/14/2009 | 1 | 121 | 75 | 168 | |
12 | A003 | . | 08/12/2009 | 1 | 118 | 68 | 125 | |
13 | A003 | . | 08/21/2009 | 2 | 112 | 65 | 123 | |
14 | A004 | . | 03/30/2009 | 1 | 143 | 86 | 204 | |
15 | A005 | . | 02/27/2009 | 1 | 132 | 76 | 174 | |
16 | A005 | . | 07/11/2009 | 2 | 132 | 78 | 175 | |
17 | A005 | . | 04/16/2009 | 3 | 134 | 78 | 176 | |
18 | A008 | . | 05/22/2009 | 1 | 126 | 80 | 182 |
同样的,两个数据集都有的变量ID和Date,只出现一次, 但因为这个是连接,所以不存在值覆盖问题。
同样的,上面的例子没有实际意义,只是为了展示工作原理,下面的例子才有实际意义:
Match-merging
工作原理
![](https://i-blog.csdnimg.cn/blog_migrate/22888613bf17039989587aaddf0b6c57.png)
这个就是merge了,按照某个字段的值进行匹配,如果匹配上,就合并到一条记录中。
语法
DATA output-SAS-data-set;
MERGE SAS-data-set-1
SAS-data-set-2;
BY <DESCENDING> variable(s);
RUN;
示例
data tmp2;
merge cert.patdat
cert.visit;
by id;
run;
proc print data=tmp2;
run;
输出
Obs | ID | Age | Sex | Date | Visit | SysBP | DiasBP | Weight |
---|---|---|---|---|---|---|---|---|
1 | A001 | 21 | M | 11/05/2009 | 1 | 140 | 85 | 195 |
2 | A001 | 21 | M | 10/13/2009 | 2 | 138 | 90 | 198 |
3 | A001 | 21 | M | 07/04/2009 | 3 | 145 | 95 | 200 |
4 | A002 | 32 | M | 04/14/2009 | 1 | 121 | 75 | 168 |
5 | A003 | 24 | F | 08/12/2009 | 1 | 118 | 68 | 125 |
6 | A003 | 24 | F | 08/21/2009 | 2 | 112 | 65 | 123 |
7 | A004 | 28 | M | 03/30/2009 | 1 | 143 | 86 | 204 |
8 | A005 | 44 | F | 02/27/2009 | 1 | 132 | 76 | 174 |
9 | A005 | 44 | F | 07/11/2009 | 2 | 132 | 78 | 175 |
10 | A005 | 44 | F | 04/16/2009 | 3 | 134 | 78 | 176 |
11 | A007 | 39 | M | 07/10/1979 | . | . | . | . |
12 | A008 | 30 | F | 05/22/2009 | 1 | 126 | 80 | 182 |
可以看到,两个数据集都有的变量Date,输出中只出现一次, 且被第2个数据集的值覆盖(ID是匹配字段,所以谈不上覆盖),这是第一个问题。
另外一个问题是,结果集中的ID是包含了两个数据集中所有的值,无论是否能匹配上,比如A007只在数据集中patdat中出现过,如果想要结果集中只出现匹配的项怎么办?
针对这两个问题,都是有解决方案的。
问题1:patdat和visit中都有Date变量,但两者的含义并不相同,前者是出生日期,后者是指访问日期,如何避免被覆盖?答案是可以使用rename选项,选项语法为(RENAME=(old-variable-name=new-variable-name))
示例:
data tmp2;
merge cert.patdat(RENAME=(Date=BirthDate))
cert.visit(RENAME=(Date=VisitDate));
by id;
run;
proc print data=tmp2;
run;
输出:
Obs | ID | Age | Sex | BirthDate | Visit | SysBP | DiasBP | Weight | VisitDate |
---|---|---|---|---|---|---|---|---|---|
1 | A001 | 21 | M | 08/17/1997 | 1 | 140 | 85 | 195 | 11/05/2009 |
2 | A001 | 21 | M | 08/17/1997 | 2 | 138 | 90 | 198 | 10/13/2009 |
3 | A001 | 21 | M | 08/17/1997 | 3 | 145 | 95 | 200 | 07/04/2009 |
4 | A002 | 32 | M | 02/18/1986 | 1 | 121 | 75 | 168 | 04/14/2009 |
5 | A003 | 24 | F | 06/07/1994 | 1 | 118 | 68 | 125 | 08/12/2009 |
6 | A003 | 24 | F | 06/07/1994 | 2 | 112 | 65 | 123 | 08/21/2009 |
7 | A004 | 28 | M | 01/27/1990 | 1 | 143 | 86 | 204 | 03/30/2009 |
8 | A005 | 44 | F | 04/24/1974 | 1 | 132 | 76 | 174 | 02/27/2009 |
9 | A005 | 44 | F | 04/24/1974 | 2 | 132 | 78 | 175 | 07/11/2009 |
10 | A005 | 44 | F | 04/24/1974 | 3 | 134 | 78 | 176 | 04/16/2009 |
11 | A007 | 39 | M | 07/10/1979 | . | . | . | . | . |
12 | A008 | 30 | F | 09/16/1988 | 1 | 126 | 80 | 182 | 05/22/2009 |
可以看到输出中的BirthDate和VisitDate各占了一个变量
问题2:merge的时候如何只显示真正匹配上的行?
答案是可以使用IN选项,选项语法为IN=variable,它创建一个临时变量,如果当前观测对结果集有用,那么该变量值会被设置为1,否则设置为0,在匹配的时候加上IF关健字判断即可。注:这个变量并不会出现在结果集中。
示例:
data tmp2;
merge cert.patdat(IN=tmpvar1 RENAME=(Date=BirthDate))
cert.visit(IN=tmpvar2 RENAME=(Date=VisitDate));
by id;
if tmpvar1 eq 1 AND tmpvar2 eq 1;
run;
proc print data=tmp2;
run;
输出:
Obs | ID | Age | Sex | BirthDate | Visit | SysBP | DiasBP | Weight | VisitDate |
---|---|---|---|---|---|---|---|---|---|
1 | A001 | 21 | M | 08/17/1997 | 1 | 140 | 85 | 195 | 11/05/2009 |
2 | A001 | 21 | M | 08/17/1997 | 2 | 138 | 90 | 198 | 10/13/2009 |
3 | A001 | 21 | M | 08/17/1997 | 3 | 145 | 95 | 200 | 07/04/2009 |
4 | A002 | 32 | M | 02/18/1986 | 1 | 121 | 75 | 168 | 04/14/2009 |
5 | A003 | 24 | F | 06/07/1994 | 1 | 118 | 68 | 125 | 08/12/2009 |
6 | A003 | 24 | F | 06/07/1994 | 2 | 112 | 65 | 123 | 08/21/2009 |
7 | A004 | 28 | M | 01/27/1990 | 1 | 143 | 86 | 204 | 03/30/2009 |
8 | A005 | 44 | F | 04/24/1974 | 1 | 132 | 76 | 174 | 02/27/2009 |
9 | A005 | 44 | F | 04/24/1974 | 2 | 132 | 78 | 175 | 07/11/2009 |
10 | A005 | 44 | F | 04/24/1974 | 3 | 134 | 78 | 176 | 04/16/2009 |
11 | A008 | 30 | F | 09/16/1988 | 1 | 126 | 80 | 182 | 05/22/2009 |
可以看到,结果集只有11个了。A007没有匹配上
参考资料:
SAS Certified Specialist Prep Guide