配套视频、笔记与代码

相关命令:

  • "append": 数据纵向接驳
  • "merge": 精确数据匹配
  • "reclink"](siyuan://blocks/20220406230229-pmnxtfx): 模糊数据匹配
  • "joinby": 多对多的匹配
  • "nearmrg": 相似值的匹配

其中,reclinkjoinbynearmrg 的用法来自:

Stata:数据合并与匹配-merge-reclink| 连享会主页 (lianxh.cn)

  ‍

其他命令:

mergemanymergeall

mergemany -- 一个灵活的命令来合并许多文件 - 简书 (jianshu.com)

mergeall -- 合并多个文件的安全方法 - 简书 (jianshu.com)

  ‍

一、数据接驳: append

  数据接驳是数据集的纵向扩展,将不同的数据集纵向拼接在一起。

  • 数据匹配使用 append 命令。与 merge 不同,数据接驳 append 命令不需要指定识别变量;
  • 当前使用的数据是 master data,append 命令可以生成一个结果变量注明样本的来源;
  • 在接驳的数据集中,变量名相同的变量的值将保存在同一变量名下。

  基本语法:

1
2
3
append using filename [filename ...] [, options]
/* Note: filename 表示待接驳的外部数据,若不在当前工作路径下,可以使用cd命令变更工作路径,
或者在filename处填写完整的数据存放路径;append命令一次可以接驳多条命令。 */

  所有选项 options:

  append 的选项大多与 merge 命令相同。

1
2
3
4
5
/*Options: 
keep(varlist):仅从其他数据集中接驳varlist变量到master data,简写作"keep(varlist)";
generate(newvar):生成一个新变量标记样本的来源,简写作"gen(newvar)";
nolabel:在匹配完成后,去除using data匹配变量中的值标签,简写作"nol";
force:强制接驳配字符型与数值型变量。 */

  比较常用的 options 是 keepus(varlist)gen(newvar)

  示例:

(⚠️注意:不同设备的显示字体不同,可能会出现字符错位的现象。将错位的文本复制到其他文本编辑器 / Stata do 文件编辑器中,可以解决此问题。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use "data1.dta"
append using "data2.dta"
save "new_data.dta"

/* 接驳数据图示:
new_data
data1 data2 +---------------------+
+---------------+ +----------------+ | i x1 x2 x3 |
| id x1 x3 | | id x1 x2 | |---------------------|
|---------------| |----------------| append | 101 3 . 2 |
| 101 3 2 | | 103 1 3.3 | ----------> | 102 5 . 1.1 |
| 102 5 1.1 | | 104 2 3.0 | | 103 1 3.3 . |
+---------------+ +----------------+ | 104 2 3.0 . |
+---------------------+ */

  ‍

二、精确数据匹配: merge

  数据匹配是数据集的横向扩展,通过识别某些变量在不同数据集中的对应关系,将其他数据集的一些变量匹配到当前数据中。

  • 数据匹配使用 merge 命令,当前打开的数据称为 master data,待匹配的数据称为 using data;
  • 数据匹配包含 1:1,1:m,m:1,m:m 四种类型;
  • 在匹配完成后,会生成一个显示匹配结果的变量,默认是“_merge”。

  基本语法:

1
2
3
4
merge X:X varlist using filename [, options]
/* Note: X:X 表示匹配类型,可以是1:1,1:m,m:1,m:m;
varlist 表示master data和using data之间匹配的识别变量,根据匹配的类型不同,varlist的要求也不同;
filename 表示using data的名称,若不在当前工作路径下,可以使用cd命令变更工作路径,或者在filename处填写完整的数据存放路径。*/

  所有选项 options:

1
2
3
4
5
6
7
8
9
/*Options: 
keepusing(varlist):仅从using data中匹配varlist变量到master data,简写作"keepus(varlist)";
generate(newvar):定义匹配结果变量名,默认是"_merge",简写作"gen(newvar)";
nogenerate:匹配完成后,不生成匹配结果变量"_merge",简写作"nogen",不能和gen(newvar)选项同时使用;
nolabel:在匹配完成后,去除using data匹配变量中的值标签,简写作"nol";
update:更新同名变量数据,即使用using data中的非缺失值替换master data中同名变量的缺失值;
replace:替换同名变量数据,即使用using data中的非缺失值替换master data中的所有同名变量的值;
noreport:不汇报匹配结果;
force:强制匹配字符型与数值型变量。 */

  merge 命令一般使用 options 较少,比较常用的 options 是 keepus(varlist)gen(newvar)

  匹配结果:

  不论哪种匹配方式,生成的匹配结果变量会有三个固定的取值:

  _merge=1:未匹配成功,该样本的数据仅来自 master data;

  _merge=2:未匹配成功,该样本的数据仅来自 using data;

  _merge=3:匹配成功,该样本的数据同时来自 master data 和 using data;

  因此,可以根据匹配结果变量的取值,筛选出需要的样本:

1
2
3
4
5
6
7
8
** 不删除任何样本,直接删除_merge变量
drop _merge
** 仅保留匹配成功的样本
keep if _merge==3
** 仅保留来自master data相关的样本
drop if _merge==2
** 删除master data中未匹配成功的样本
drop if _merge==1

第一种:one-to-one merge

  使用 1:1 匹配的条件:用于匹配的 varlist 在 master data 和 using data 中可以唯一识别每一个样本。若某一个变量不能唯一识别每个样本,则要求通过多个变量可以唯一识别两套数据中的每一个样本。

  示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use "master_data.dta"
merge 1:1 id using "using_data.dta"
drop _merge
save "new_data.dta"

** 匹配结果展示
Result Number of obs
-----------------------------------------
Not matched 2
from master 1 (_merge==1)
from using 1 (_merge==2)

Matched 3 (_merge==3)
-----------------------------------------

/* 匹配结果图示:
master_data using_data new_data
+--------------+ +------------+ +---------------------------------------+
| id x1 x2 | | id x3 | | id x1 x2 x3 _merge |
|--------------| |------------| |---------------------------------------|
| 101 1 4.1 | | 101 2 | merge | 101 1 4.1 2 Matched (3) |
| 102 2 4.5 | | 102 1.1 | ---------> | 102 2 4.5 1.1 Matched (3) |
| 103 3 3.3 | | 103 5 | | 103 3 3.3 5 Matched (3) |
| 104 4 3.0 | | 105 7 | | 104 4 3.0 . Master only (1) |
+--------------+ +------------+ | 105 . . 7 Using only (2) |
+---------------------------------------+ */

第二种:one-to-many merge

  使用 1:m 匹配的条件:用于匹配的 varlist 在 master data 中可以唯一识别每一个样本,且在 using data 中对应多个样本。

  常见使用场景:

  • master data 是家庭数据,using data 是个体数据,一个家庭对应多个个体,使用家庭的编码进行识别;
  • master data 是省级数据,using data 是地级市数据,一个省对应多个地级市,使用省份的编码进行识别。

  示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use "master_data.dta"
merge 1:m id using "using_data.dta"
drop _merge
save "new_data.dta"

** 匹配结果展示

Result Number of obs
-----------------------------------------
Not matched 1
from master 1 (_merge==1)
from using 0 (_merge==2)

Matched 4 (_merge==3)
-----------------------------------------

/* 匹配结果图示:
master_data using_data new_data
+--------------+ +------------+ +---------------------------------------+
| id x1 x2 | | id x3 | | id x1 x2 x3 _merge |
|--------------| |------------| |---------------------------------------|
| 101 1 4.1 | | 101 2 | merge | 101 1 4.1 2 Matched (3) |
| 102 2 4.5 | | 102 1.1 | ---------> | 102 2 4.5 1.1 Matched (3) |
| 103 3 3.3 | | 102 2.7 | | 102 2 4.5 2.7 Matched (3) |
| 104 4 3.0 | | 103 5 | | 103 3 3.3 5 Matched (3) |
+--------------+ +------------+ | 104 4 3.0 . Master only (1) |
+---------------------------------------+ */

第三种:many-to-one merge

  将 1:m 匹配中的 master data 和 using data 的数据特征互换时,就应该使用 m:1 匹配。

  使用 m:1 匹配的条件:用于匹配的 varlist 在 using data 中可以唯一识别每一个样本,且在 master data 中对应多个样本。

  常见使用场景:

  • master data 是个体数据,using data 是家庭数据,多个个体可以同时在一个家庭内,使用家庭的编码进行识别;
  • master data 是地级市数据,using data 是省级数据,多个地级市同属于一个省份,使用省份的编码进行识别。

  示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use "master_data.dta"
merge m:1 id using "using_data.dta"
drop _merge
save "new_data.dta"

** 匹配结果展示

Result Number of obs
-----------------------------------------
Not matched 1
from master 1 (_merge==1)
from using 0 (_merge==2)

Matched 4 (_merge==3)
-----------------------------------------

/* 匹配结果图示:
master_data using_data new_data
+--------------+ +------------+ +---------------------------------------+
| id x1 x2 | | id x3 | | id x1 x2 x3 _merge |
|--------------| |------------| |---------------------------------------|
| 101 1 4.1 | | 101 2 | merge | 101 1 4.1 2 Matched (3) |
| 102 2 4.5 | | 102 1.1 | ---------> | 102 2 4.5 1.1 Matched (3) |
| 103 3 3.3 | | 103 5 | | 103 3 3.3 5 Matched (3) |
| 103 9 5.5 | +------------+ | 103 9 5.5 5 Matched (3) |
| 104 4 3.0 | | 104 4 3.0 . Master only (1) |
+--------------+ +---------------------------------------+ */

第四种:many-to-many merge

  m:m 匹配不建议使用,因为其匹配结果是不确定的!

  在数据匹配时,多数情况使用 1:1、1:m、m:1 已经可以解决问题。此处不再展示 m:m 的用法。

  ‍

  在横向合并时,若匹配变量在内容上有些差别,如在第一份数据中为「Princeton University」,而在第二份数据中为「Princeton U」,我们可以通过 reclink 命令快速模糊匹配,以避免繁琐的人工识别。具体示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
*输入两份数据
clear
input str13 name str14 city
"Zhang ziye" "Beijing"
"Liu biqian" "Shanghai"
"Hu,yi" "Guangzhou"
"Yang,Zhou" "Hennan"
end
gen id1=_n
save file1.dta, replace

clear
input str14 name str10 city
"Zhan, ziye" "beijing"
"LIU Biqian" "Shaanghai"
"huyi" "guangdong"
"Zhou yang" "henan"
end
gen id2=_n
save file2.dta, replace

*-模糊匹配
use file1.dta,clear
reclink name city using file2.dta, idmaster(id1) idusing(id2) gen(matchscore)
list, clean noobs

  模糊匹配后结果:

1
2
3
4
5
6
      name        Uname        city     Ucity   id1   matchs~e   id2   _merge
Zhang ziye Zhan, ziye Beijing beijing 1 0.9719 1 3
Yang,Zhou Zhou yang Hennan henan 4 0.7797 4 3
Liu biqian Shanghai 2 . . 1
Hu,yi Guangzhou 3 . . 1

  reclink 命令注意事项

  • 两份数据中 id 名必须不同。如,在上述命令中 idmaster(id1)idusing(id2) 分别代表 master data 中的 id 和 using data 中的 id ,结果第五列和第七列解读为 master data中的id1 = 1 和 using data 中的 id2 = 1 匹配成功;
  • **_merge** 变量含义与前文类似;
  • reclink 命令可解决的匹配问题:大小写不同、部分字母缺漏或增加、以及顺序颠倒;
  • matchscore 变量为匹配分数,分数越高代表匹配效果越好。

  另外,reclink 命令还允许对匹配变量设定不同权重。比如,在这个例子中,我们认为 city 是最重要的,则仅需增加 vmatch() 选项设定权重。具体示例如下:

1
2
3
4
use file1.dta,clear
reclink name city using file2.dta, idmaster(id1) idusing(id2) gen(matchscore) wmatch(1 15)
list, clean noobs

  模糊匹配后结果:

1
2
3
4
5
6
      name        Uname        city       Ucity   id1   matchs~e   id2   _merge
Zhang ziye Zhan, ziye Beijing beijing 1 0.9659 1 3
Liu biqian LIU Biqian Shanghai Shaanghai 2 0.9475 2 3
Yang,Zhou Zhou yang Hennan henan 4 0.8129 4 3
Hu,yi Guangzhou 3 . . 1

  可以看出,该结果与前文结果具有一定差异。

  当然,模糊匹配也可以使用 matchit 命令。更多有关 reclinkmatchit 的介绍请参考「Stata:模糊匹配之matchit」

  ‍

四、多对多的匹配: joinby

  在进行多对多匹配时,我们可以使用 mergejoinby 命令,但二者又具有哪些差别?具体示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
*输入数据
clear
input group str3 x1
1 "A"
1 "B"
1 "C"
1 "D"
end
save file1.dta,replace

clear
input group str3 x2
1 "M"
1 "N"
end
save file2.dta,replace

*merge 多对多匹配
use file1.dta,clear
merge m:m group using file2.dta
list, clean noobs

*joinby 多对多匹配
use file1.dta,clear
joinby group using file2.dta
list, clean noobs

  merge 命令多对多匹配结果:

1
2
3
4
5
6
group   x1   x2        _merge
1 A M matched (3)
1 B N matched (3)
1 C N matched (3)
1 D N matched (3)

  可以看出,merge 命令的多对多合并是有问题的,其会以较少数据文件的最后一行值 (比如这里的 file2.dta 的最后一行数据「group1,x2=N」) 进行重复合并。

  joinby 命令多对多匹配结果:

1
2
3
4
5
6
7
8
9
10
group   x1   x2
1 A N
1 A M
1 B M
1 B N
1 C N
1 C M
1 D N
1 D M

  可以看出,joinby 命令显然更符合我们的要求。关于 joinby 命令更多详细介绍,请查看帮助文件 help joinby

  ‍

五、nearmrg 命令:相似值的匹配

  上文已经介绍了字符串模糊匹配命令 reclink,这里再介绍一下数值模糊匹配命令 nearmrg。关于该命令更多介绍,请查看帮助文件 help nearmrg

1
2
3
4
5
6
7
8
9
10
11
12
*生成一份数据
sysuse auto.dta, clear
keep make price mpg
keep if make == "Toyota Celica" | ///
make == "BMW 320i" | ///
make == "Cad. Seville" | ///
make == "Pont. Grand Prix" | ///
make == "Datsun 210"
rename make make2
save "using.dta", replace
list, clean noobs

  列出数据:

1
2
3
4
5
6
7
make2               price   mpg
Cad. Seville 15,906 21
Pont. Grand Prix 5,222 19
BMW 320i 9,735 25
Datsun 210 4,589 35
Toyota Celica 5,899 18

  然后,我们将该数据与 auto.dta 进行合并,并找出 using.dta 数据中价格浮动在 $50 上下的数据。

1
2
3
4
5
sysuse auto.dta, clear
nearmrg using "using.dta", upper nearvar(price) genmatch(usingmatch) limit(50)
keep make price mpg make2 _merge usingmatch
list, clean noobs

1
2
3
4
5
6
7
8
9
10
11
make                price   mpg   make2                   _merge   usingm~h
Datsun 210 4,589 35 Datsun 210 matched (3) 4,589
Buick Regal 5,189 20 Pont. Grand Prix matched (3) 5,222
Pont. Grand Prix 5,222 19 Pont. Grand Prix matched (3) 5,222
Olds Cutl Supr 5,172 19 Pont. Grand Prix matched (3) 5,222
Dodge Magnum 5,886 16 Toyota Celica matched (3) 5,899
Toyota Celica 5,899 18 Toyota Celica matched (3) 5,899
BMW 320i 9,735 25 BMW 320i matched (3) 9,735
Audi 5000 9,690 17 BMW 320i matched (3) 9,735
Cad. Seville 15,906 21 Cad. Seville matched (3) 15,906

  可以看出,using data 中原有 5 行数据,合并后变成了 9 行数据。之所以如此,是因为 auto.dta 中价格浮动在 50 之内的数据都被保留了下来。

  ‍

  ‍