。
参考文献:Vanlaar W. A shortcut through long loops: An illustration of two alternatives to looping over observations[J]. Stata Journal, 2008, 8(4): 540-553. [PDF]
[h1]1. 问题背景[/h1]在进行数据处理的时候,我们可能会遇到这样的问题:我们试图将两份数据合并在一起,但是用来合并的唯一可识别的变量却是动态变化的,导致无法依据该变量实现完全的合并。
例如,个人的驾驶执照号码发生过变化,在两份与驾驶执照号码有关的数据中,由于数据搜集的过程不同,其中一份数据使用旧的驾驶执照号码,如下图的 master data,第1、2、3 行代表着同一个人,但是有多个驾驶执照号码,每个驾驶执照号码对应一次交通事故。而另一份数据使用最新的驾驶执照号码,如下图的 using data,每个驾驶执照号码对应个人的性别和爱好。
image.png为了成功合并数据,我们需要了解驾驶执照号码的变化过程( 如下图 sorting data ),并得到旧驾驶执照号码( 如下图 mapch data 中的 old 变量 )和最终驾驶执照号码( 如下图 mapch data 中的 recent 变量 )的对应关系。
驾驶执照管理部门能够提供驾驶执照号码的变动,即旧驾驶执照号码( 如下图 sorting data 中的 old 变量 )、更新的驾驶执照号码( 如下图 sorting data 中的 updated 变量 )、驾驶执照号码变动的时间( 如下图 sorting data 中的 date 变量 )。例如,在 sorting data 中,第 1、2 行是同一个人两次更改驾驶执照号码。
image.png如果数据量比较少或者只有少量的驾驶执照号码发生了变化,我们可以手动寻找这些变化,但是如果数据量比较大且大部分人都改变过驾驶执照号码,并且许多人不止改变过一次,用眼寻找的方法将非常耗时。
上图中 sorting data 是我们已经整理好的驾驶执照号码变更过程,比如第 1、2、3 是同一个人驾驶执照号码变化的过程,即 “A-B-C-D”,而实际中,数据的不同行之间是杂乱的,如上图中 original data 所示。
因此,为了得到能够进行数据合并的 mapch data,首先需要对 original data 进行排序,识别每个驾驶员驾驶执照号码的更改过程,即绘制 “事件链” ( mapping the chains of events ),然后需要创建一个新变量 recent,recent 的值为每个 “事件链” 的最终驾驶执照号码。
当我们得到 mapch data 后,便可以根据旧驾驶执照号码( old )将 mapch data 和 master data 合并在一起,然后根据更新的驾驶执照号码( recent )将 master data 和 using data 合并在一起。
在 Stata 中,我们可以通过数据追加、识别和合并一步一步得到最终的 “事件链”,也可以用 mapch 命令直接得到 “事件链” 的信息。下面先用分步的方法识别 “事件链”,再用
mapch
复制代码
命令实现 “事件链”。
[h1]2.分步实现[/h1][h2]第一步:构造数据[/h2]在 original data 中创建变量 link 并等于 updated 变量,保存此数据;然后在 original data 中创建变量 link 并等于 old 变量;将两份数据追加在一起。根据 link、date 排序后的结果如下所示。
use original,clear
复制代码
generate link = updated
复制代码
save original1, replace
复制代码
use original,clear
复制代码
generate link = old
复制代码
append using original1
复制代码
sort link date
复制代码
list
复制代码
+---------------------------------+
复制代码
| old updated date link |
复制代码
|---------------------------------|
复制代码
1. | A B 2017/3/2 A |
复制代码
2. | A B 2017/3/2 B |
复制代码
3. | B C 2018/3/2 B |
复制代码
4. | B C 2018/3/2 C |
复制代码
5. | C D 2019/3/2 C |
复制代码
|---------------------------------|
复制代码
6. | C D 2019/3/2 D |
复制代码
7. | E F 2018/3/2 E |
复制代码
8. | E F 2018/3/2 F |
复制代码
9. | G H 2017/3/2 G |
复制代码
10. | G H 2017/3/2 H |
复制代码
|---------------------------------|
复制代码
11. | O N 2015/3/2 N |
复制代码
12. | P O 2014/3/2 O |
复制代码
13. | O N 2015/3/2 O |
复制代码
14. | Q P 2013/3/2 P |
复制代码
15. | P O 2014/3/2 P |
复制代码
|---------------------------------|
复制代码
16. | Q P 2013/3/2 Q |
复制代码
17. | X1 X2 2011/3/2 X1 |
复制代码
18. | X1 X2 2011/3/2 X2 |
复制代码
19. | X2 X3 2012/3/2 X2 |
复制代码
20. | X2 X3 2012/3/2 X3 |
复制代码
+---------------------------------+
复制代码
[h2]第二步:识别 two-step 链[/h2]之所以不从识别 one-step 链开始,是因为 original data 本身已经包含了 one-step 链的信息,我们可以通过合并的方式将 original data 中的 one-step 链的信息复制下来。
通过第一步,新构造的数据中增加了两种噪音,即无效的行( 如第 1、16 行 )和 one-step 链的行( 如第 8、10 行 ),需要清理掉这些不需要的数据。
我们根据 link 产生变量 test1,test1 的值是 link 中每个值的个数( 如 “B” 在 link 中出现了 2 次 )。如果 test1 的值不等于2,那么该行或者是 one-step 链,如 link 第 8 行是 “E-F” 的 one-step 链;或者该行对应的 link 值是整条 “事件链” 的最开始的状态,如 link 第 1 行的 A 是 “A-B-C-D” 的开始状态。
其中,从 old 到 recent2 便是“事件链”的最终映射。
[h2]3. 使用 mapch 命令:更高效的处理方式[/h2]
mapch
复制代码
是 “map chains of events” 的简写,语法如下:
mapch begin end [time]
复制代码
其中,begin 是一个事件的开始状态,正如上文中的 old 变量,end 是一个事件的结束状态,正如上文中的 updated 变量。
mapch
复制代码
可以在包含事件发生时间的数据中使用,也可以应用于没有事件发生时间的数据。
使用
mapch
复制代码
命令会产生两个新的变量 recent 和 NoofEvents,recent 对应出了 begin 变量的结束状态,NoofEvents 包含从 begin 到 recent 每个链的事件数,同时还报告出了 n-step 链的频率。
use original,clear
复制代码
mapch old updated date
复制代码
********************
复制代码
* Mapping complete *
复制代码
********************
复制代码
Frequency of NoOfEvents:
复制代码
NoOfEvents | Freq. Percent Cum.
复制代码
------------+-----------------------------------
复制代码
1 | 2 20.00 20.00
复制代码
2 | 2 20.00 40.00
复制代码
3 | 6 60.00 100.00
复制代码
------------+-----------------------------------
复制代码
Total | 10 100.00
复制代码
The number of 1-step chains is equal to 2/1
复制代码
The number of 2-step chains is equal to 2/2
复制代码
The number of 3-step chains is equal to 6/3
复制代码
+----------------------------------------------+
复制代码
| old updated date recent NoOfEv~s |
复制代码
|----------------------------------------------|
复制代码
1. | A B 2017/3/2 D 3 |
复制代码
2. | B C 2018/3/2 D 3 |
复制代码
3. | C D 2019/3/2 D 3 |
复制代码
4. | E F 2018/3/2 F 1 |
复制代码
5. | G H 2017/3/2 H 1 |
复制代码
|----------------------------------------------|
复制代码
6. | Q P 2013/3/2 N 3 |
复制代码
7. | P O 2014/3/2 N 3 |
复制代码
8. | O N 2015/3/2 N 3 |
复制代码
9. | X1 X2 2011/3/2 X3 2 |
复制代码
10. | X2 X3 2012/3/2 X3 2 |
复制代码
+----------------------------------------------+
复制代码
如果数据中不包含事件发生的时间,那么使用
mapch
复制代码
命令后会产生一个 date 变量。
use original,clear
复制代码
drop date
复制代码
mapch old updated
复制代码
list
复制代码
+------------------------------------------+
复制代码
| old updated date recent NoOfEv~s |
复制代码
|------------------------------------------|
复制代码
1. | A B 1 D 3 |
复制代码
2. | B C 2 D 3 |
复制代码
3. | C D 3 D 3 |
复制代码
4. | E F . F 1 |
复制代码
5. | G H . H 1 |
复制代码
|------------------------------------------|
复制代码
6. | Q P 1 N 3 |
复制代码
7. | P O 2 N 3 |
复制代码
8. | O N 3 N 3 |
复制代码
9. | X1 X2 1 X3 2 |
复制代码
10. | X2 X3 2 X3 2 |
复制代码
+------------------------------------------+
复制代码
参考文献:Vanlaar W. A shortcut through long loops: An illustration of two alternatives to looping over observations[J]. Stata Journal, 2008, 8(4): 540-553. [PDF]
[h3]关于我们[/h3]
【Stata 连享会(公众号:StataChina)】由中山大学连玉君老师团队创办,旨在定期与大家分享 Stata 应用的各种经验和技巧。