如果这样讲你还不懂,不如干脆...
在开始今天的文章前,对昨天的这篇文章 ,我们做一个补充:

随着经验和知识的积累,我们后续会在 里针对 imputation 进行更多的介绍。
回到今天的主题,如果大家还有印象的话,前面这篇文章 ,是还没有完结的。我原计划不会用太多的文字应该就可以讲清楚,现在看来,并不是这么一回事。还是需要先将二者各自讲清楚,再来分析之间的异同点。
基于此,我们今天就要把 merge by 尽量讲清楚,如果这样你还掌握不了,干脆......收藏这篇文章😜
merge 的目的
首先,你要弄清楚,你要用它做什么?你一定回答我,横向合并。为什么横向合并?因为某个数据集缺少一些变量,我们想用另一个或一些数据集来更新它。仅仅是这样么?不,当某个数据集中某个变量的取值并不完整时,我们通常会用 SAS 制作一个 shell,将 shell 与原数据集进行 merge,以达到补充取值尽量使其取值完整的目的(在我们这里,我们称这种操作为 dummy),从这个角度来看,merge 并不是为了增加横向的 columns,而是增加了纵向的 rows。
所以,再次问你,你要用 merge 来做什么?你应该回答我,为了补充完整的所有变量、所有行。这个说法不知道你熟不熟悉,反正我是熟悉的,因为在这篇文章里 ,我也同样提过,set 的作用也是补充完整的所有变量、所有行。那你要问我了,那既然都是所有变量所有行,为什么还要弄两个,直接一个不就行了么?因为它们的出发点是不一样的,尽管最后可能都补充完整的所有变量所有行。
搞清楚了你要用它的目的,我们就可以继续往下讲它具体的实现逻辑了。
对于 merge 的横向合并,我们分为两大类来说明:
不使用 by,merge 对两个或多个数据集的横向合并
具体地,对于编译阶段,SAS 按照 merge 语句中数据集的先后顺序,依次读入各数据集中变量的描述部分,并将各变量置入 PDV(只添加后续新变量,PDV 中无重复变量);对于执行阶段,SAS 按照 merge 语句中数据集的先后顺序,从第一个数据集中读入第一条观测,并复制到 PDV 中,再从第二个数据集中读入第一条观测,并复制到 PDV 中,若两个数据集中有同名变量,后读入的值将覆盖掉先读入的值。如此重复操作,依次处理各个数据集中的各条观测,直到处理完其中较少行数的数据集,而后,该数据集相对于另一数据集缺少的行所包含的变量,在 PDV 中均被置为缺失值,直到读入所有变量所有行。
上 code:

这里,我要提醒大家注意的是:注意看 A、B两个数据集有 common variable --- id,在做不使用 by 的一对一横向不匹配 merge 合并时,对于两个数据集的同名变量,后读入的变量的值讲覆盖更新先读入的值,非同名变量则不受影响,独自美丽。
使用 by,merge 对两个或多个数据集的横向合并
使用 by,从而可以更进一步地控制横向合并,这种我们称之为横向匹配合并,也是我们在 programming 中最常遇到的情况。对于横向匹配合并,需要分别考虑三种情况,我们一一来看:
1. by 变量值在所有数据集中均只有唯一观测
什么意思?即,在每个数据集中,每个 by 变量值出现且只出现一次,换句话说,在任一数据集中,每个 by 变量组合都只有一条观测。
操作逻辑为:对于编译阶段,SAS 按照 merge 语句中数据集的先后顺序,依次读入各数据集中变量的描述部分,并将各变量置入 PDV(只添加后续新变量,PDV 中无重复变量);对于执行阶段,SAS 按照各数据集中 by 变量值的第一个值确定排在第一位读入的 by 组合,再按照 merge 语句中数据集的先后顺序,从第一个数据集中读入第一个 by 组合所属的观测,并复制到 PDV 中,再从第二个数据集中读入同一 by 组合所属的观测,并复制到 PDV 中,若两个数据集中有同名变量,后读入的值将覆盖掉先读入的值。
注意‼️,若某数据集相对于另一数据集缺少该 by 组合的行观测,则在 PDV 中,该数据集除 by 组合变量外的所有变量均被置为缺失值,而另一数据集的全部变量则正常读入。当读取完所有数据集中第一个 by 组合的行观测,我们认为完成了一次 data step 的迭代,因而,SAS 将 PDV 中所有变量值都重置为缺失值。如此重复操作,直到读入所有变量所有行。
2. by 变量值在某一数据集中存在重复观测
即,在某一数据集中,某个或某些 by 组合存在多条观测,这种横向匹配合并,我们称为一对多合并。
操作逻辑为:对于编译阶段,SAS 按照 merge 语句中数据集的先后顺序,依次读入各数据集中变量的描述部分,并将各变量置入 PDV(只添加后续新变量,PDV 中无重复变量);对于执行阶段,SAS 按照各数据集中 by 变量值的第一个值确定排在第一位读入的 by 组合,再按照 merge 语句中数据集的先后顺序,从第一个数据集中读入第一个 by 组合所属的第一条观测,并复制到 PDV 中,再从第二个数据集中读入同一 by 组合所属的第一条观测,并复制到 PDV 中,若两个数据集中有同名变量,后读入的值将覆盖掉先读入的值。
前面情况中,我们讨论了某数据集缺少某 by 组合的处理逻辑,这里同样适用,即若某数据集相对于另一数据集缺少该 by 组合的行观测,则在 PDV 中,该数据集除 by 组合变量外的所有变量均被置为缺失值,而另一数据集的全部变量则正常读入。这里,由于 by 变量值在某一数据集中存在重复观测,则必然存在某数据集不仅不缺少,反而有多个某 by 组合的观测,此时 SAS 会怎么处理两个数据集该 by 组合剩余观测的横向匹配合并呢?
当读取完所有数据集中第一个 by 组合的第一条行观测,我们认为完成了一次 data step 的迭代,此时,SAS 本应将 PDV 中所有变量值都重置为缺失值,但是由于该 by 组合变量值在某一数据集中存在重复观测,导致此时,SAS 会 retain 住 PDV 中所有变量的值,直到读入该 by 组合在两个数据集中的下一条观测,PDV 中这些变量的值才会被新的值覆盖更新(若后续观测不能提供变量新的值,则原值将被一直 retain 并写入输出数据集),而不再像上面那样直接全部重置为缺失值。但是注意‼️,由于 by 变量只在某一数据集中存在重复观测,在另一或另一些数据集中,其所属的观测仍然是唯一的,此时,由于 SAS 的 rule 规定,每行观测只会被读入处理一次,因而,unique by 变量值数据集的那行观测不会再被重复读入处理。此时,若合并的两个数据集除 by 变量外,不存在同名变量,那就很好办了,unique by 变量值数据集的其余变量的值因为不能得到新值覆盖更新,则原值会被一直 retain 并写入输出数据集,直到 SAS 处理完两个数据集各自该 by 组合的所有观测行;而若存在除 by 变量外的同名变量,则后续该同名变量会被含有重复 by 观测的数据集中的同名变量提供的新值所覆盖更新,直到 SAS 处理完两个数据集各自该 by 组合的所有观测行。
当 SAS 处理完两个数据集各自该 by 组合的所有观测行之后,SAS 此时才将 PDV 中所有变量值都重置为缺失值。如此重复操作,直到读入所有变量所有行。
这里比较绕,上 code:

这是一个简单同时又非常典型的例子。我要强调它典型的原因是,因为这里两个数据集除 by 变量外,既有同名变量,又有不同名变量。
大家应该很好理解,output 的第一行观测的 class 为 eng,因为 a2 后读入,自然 eng 覆盖更新 mth。但读完各自第一条 by 变量观测后,SAS 并未直接将 PDV 中所有变量值重置为缺失值,反而是 retain 住所有值,等待该 by 组合的剩余观测变量值来覆盖更新。而 class 为同名变量,因而从第二条观测开始,class 的值被 a1 中 class 的值覆盖更新, 但是 classno 为 a2 中的非同名变量,它的值由于不能得到数据集 a2 的更新,因而被 SAS 一直 retain 并写入输出数据集。
3. by 变量值在多个数据集中存在重复观测
即,在多个数据集中,某个或某些 by 组合存在多条观测,这种横向匹配合并,我们称为多对多合并。
一般地,这种多对多合并,我们并不建议采用 merge by 来实现。关于这种情况的合并,请期待后续文章的分析讨论。
细节
那么,讲到这里,merge 常用的操作基本已经讲完了。但是,仍然要提醒大家注意两个细节:
若使用 by,两个或多个数据集中的 by 变量一定要是相同 name、相同 type、相同 length;
若使用 by,进行 merge by 前,务必分别将两个数据集进行 sort 处理。
