温馨提示: 定期 清理浏览器缓存,可以获得最佳浏览体验。
New!
lianxh
命令发布了:
随时搜索推文、Stata 资源。安装命令如下:
. ssc install lianxh
详情参见帮助文件 (有惊喜):
. help lianxh
⛳ Stata 系列推文:
作者:陈波 (深圳大学)
E-Mail: 1900123011@email.szu.edu.cn
目录
对于流行实证分析的经管等学科而言,每逢毕业季,大家都会殚精竭虑的寻找数据,以满足自己的研究需求,所谓“上穷碧落下黄泉,动手动脚找数据”,不外如是。但是,近年来,也有一些现成的微观数据,为大家提供了不少便利。如西南财大的中国家庭金融调查 (CHFS) 、北大国发院的中国健康与养老追踪调查 (CHARLS) 、北大中国社科调查中心的中国家庭追踪调查 (CFPS) 等。很多学界大佬都拿这些数据发过顶刊,数据质量十分可靠;多数数据对外公开,数据获取也较为便利。
但是,有时候拿到数据仅仅意味着开始,数据清洗也是一头来势汹汹的拦路虎。那么,我们该怎么清洗微观数据呢?下面我们就以北京大学的中国家庭追踪调查 (CFPS) 为例,详细讲一下怎么清洗微观数据,并构造一些较为复杂的变量。
首先,我们需要从官方渠道申请数据。目前主要有两个方式,一是直接从 CFPS 数据中心下载,该平台提供 Stata 和 SAS 两种格式,并实时更新数据。最近一次更新是 2021 年 4 月 16 日,上载了跨年个人核心变量库和技术报告 CFPS-40 《中国家庭追踪调查跨年个人核心变量库清理报告》。下文的示例也是使用该平台的数据。
北京大学开放数据平台也有提供 CFPS 数据,附有 Stata 和 SAS 两种格式。但是该平台更新较慢,最近一次更新是 2020 年 8 月,且没有最新的 CFPS2018 数据。
同时,两个网站都需要注册并进行认证,但是认证速度很快,一般能在 1-2 个工作日内完成。所以还是建议大家使用正规渠道的数据,不要使用各种非官方的野生数据。
CFPS数据中心网址:
北京大学开放数据研究平台:
下载好数据之后,我们先新建三个文件夹: CFPS2016 、 CFPS2018 和 Result_data ,存储 CFPS2016 、 CFPS2018 的原始数据和清洗后的数据。我们再在 Result_data 中新建 4 个文件夹: Dofiles 、 Logfiles 、 Temp_data 和 Working_data ,存放数据清洗的 do 文档、 log 文档、产生的过程数据和最终的结果数据。这么复杂的起手式是为了帮助我们在后续清洗过程中理清自己的思路,不至于手忙脚乱,这在处理繁复的数据中尤为重要。
我们使用 global
定义其存储路径,方便后面直接调用,不用输入一串长路径。这也为合作者提供了便利,当我们的合作者需要数据和代码时,我们将文件夹打包发给对方,对方修改一下 root 路径,即可完整的运行代码和输出结果。
* =======================================================
* Program:CFPS数据清洗
* Date:2021-04-25
* =======================================================
clear all
clear matrix
set more off
global root = "/Applications/Stata/personal/CFPS" // Mac
global root = "D:/mydata/CFPS" // Windows
global cfps2018 = "$root/CFPS2018"
global cfps2016 = "$root/CFPS2016"
global dofiles = "$root/Result_data/Dofiles"
global logfiles = "$root/Result_data/Logfiles"
global temp_data = "$root/Result_data/Temp_data"
global working_data = "$root/Result_data/Working_data"
log using "$logfiles/cfpsclean.log", replace
我们先以 CFPS2018 为例,讲解截面数据的清洗步骤。
我们先导入 CFPS2018 中的家庭经济问卷,这是一份超过 300 个变量的长问卷,而我们只需要其中小部分变量。因此我们可以使用 keep
提取需要的家庭信息,如家庭id、省份、区县顺序码、村居顺序码、城乡分类等。
*- 提取变量
. use "$cfps2018/cfps2018famecon_202101.dta", clear
. keep fid18 fid16 provcd18 countyid18 cid18 urban18 ///
resp1pid fk1l ft200 fincome1_per total_asset familysize18
提取完之后,我们先用 sum
看一下这份数据,发现里面有一些异常值,诸如 -9 、 -8 。这些值代表着什么含义呢?
. sum
Variable | Obs Mean Std. Dev. Min Max
-------------+----------------------------------------------------
fid18 | 14,218 401481.9 316756.2 100051 6759191
fid16 | 14,218 372239.8 171404.6 100051 2845311
provcd18 | 14,217 38.13913 14.95284 11 65
countyid18 | 14,199 567.5955 1681.507 1 9992
cid18 | 13,122 319687.8 267463.4 100100 999544
-------------+----------------------------------------------------
urban18 | 14,218 .3703756 1.275113 -9 1
resp1pid | 14,218 3.85e+08 1.53e+08 1.00e+08 2.49e+09
fk1l | 14,218 3.241103 1.985484 1 5
ft200 | 14,218 4.726122 1.186591 -8 5
fincome1_per | 14,218 30592.59 85940.67 0 5660000
-------------+----------------------------------------------------
total_asset | 13,423 775690.7 1842052 -2470000 5.05e+07
familysize18 | 14,218 3.55901 1.917424 1 21
这时候我们可以使用 label list
,查看变量的标签值。发现原来 -9 是缺失值, -8 是不使用,以及其他一些 missing value :
*- 查看变量标签
. label list urban18
urban18:
-10 无法判断
-9 缺失
-8 不适用
-2 拒绝回答
-1 不知道
0 乡村
1 城镇
这些缺失值我们用不上,因此可以将数字全部变为 .
。因为涉及多个变量和多个值,我们可以引入 for
循环和 inlist
:
*- 缺失值替换为.
. for var _all: replace X =. if inlist(X, -10, -9, -8, -2, -1)
另外, label list
一下,发现 fk1l 和 ft200 都不是常用的 0-1 变量,而是 1 =是, 5 =否,因此我们可以用 recode
重新赋值:
. *- 重新赋值
. recode fk1l (1 = 1 "是")(5 = 0 "否"), gen(agri)
. recode ft200 (1 = 1 "是")(5 = 0 "否"), gen(finp)
随后,我们删除掉冗余变量,将其存储到事先建立的 Temp_data 文件夹中:
. *- 存储家庭变量
. drop fk1l ft200
. save "$temp_data/family_2018.dta", replace
大部分情况下,单个表的变量并不能满足我们的研究需求,我们需要进行跨表间的变量合并。我们以最常见的家庭库和个人库合并为例。
我们先调入个人库,将所需变量提取出来,并将各种原因的缺失值统一替换为.
:
*- 提取个人库变量
. use "$cfps2018/cfps2018person_202012.dta", clear
. keep pid fid18 fid16 provcd18 countyid18 cid18 urban18 gender age ///
qa301 qea0 qp605_s_* cfps2018edu
. for var _all: replace X =. if inlist(X, -10, -9, -8, -2, -1)
然后对变量重新赋值。户口状况中,有 21人 无户口, 12人 非中国国籍,我们将其做缺失值处理。婚姻状态是一个五分类变量,我们也将其重新赋值,将在婚、同居定义为有配偶,未婚、离婚、丧偶定义为配偶。学历也做相似处理,将大专、大学本科、硕博划分为大学及以上。
. tab qa301
现在的户口状况 | Freq. Percent Cum.
-------------------+-----------------------------------
农业户口 | 22,585 73.85 73.85
非农业户口 | 7,964 26.04 99.89
没有户口 | 21 0.07 99.96
不适用(非中国国籍) | 12 0.04 100.00
-------------------+-----------------------------------
Total | 30,582 100.00
. tab qea0
当前婚姻 |
状态 | Freq. Percent Cum.
---------------+-----------------------------------
未婚 | 4,147 13.56 13.56
在婚(有配偶) | 23,938 78.25 91.81
同居 | 133 0.43 92.24
离婚 | 624 2.04 94.28
丧偶 | 1,750 5.72 100.00
---------------+-----------------------------------
Total | 30,592 100.00
. recode qa301 (1 = 1 "农业户口")(3 = 0 "非农户口")(5 79 =.), gen(hukou)
. recode qea0 (2 3 = 1 "有配偶")(1 4 5 = 0 "无配偶"), gen(spouse)
. recode cfps2018edu ///
(1 = 0 "文盲/半文盲") ///
(2 = 1 "小学") ///
(3 = 2 "初中") ///
(4 = 3 "高中") ///
(5 6 7 8 = 4 "大学以以上"), gen(edu)
有时候,我们需要一些较为复杂的变量,例如说受访者是否购买了医疗保险、购买了具体哪种医疗保险,以及购买了几种医疗保险。而医保类型有 5 个变量,我们不能直接对其进行 recode
,这个时候就需要善用 for
循环了。
我们先将 5 个医保变量中的数值 78 替换为 .
( 78 表示以上都没有),然后生成 3 个变量:medsure_dum 、medsure_xnh 和 medsure_num,分别表示是否购买医保、是否购买了新农合,以及购买医保数量。
我们编写了 3 个 for
循环,第一个循环计算是否购买医保,其含义是:若 5 个医保变量中任一一个存在非缺失值(回答了具体保险类型),就将 medsure_dum 替换为 1 。第二个循环是计算是否购买新农合,其含义是:若 5 个医保变量中,任一一个回答其购买了新农合(标签值为 5 ),就将 medsure_xnh 替换为 1 。第三个循环是计算医保数量,其含义是:若医保类型
. des qp605_s_*
storage display value
variable name type format label variable label
------------------------------------------------------------
qp605_s_1 double %47.0g qp605_s_1
医疗保险类型1
qp605_s_2 double %47.0g qp605_s_2
医疗保险类型2
qp605_s_3 double %47.0g qp605_s_3
医疗保险类型3
qp605_s_4 double %47.0g qp605_s_4
医疗保险类型4
qp605_s_5 double %47.0g qp605_s_5
医疗保险类型5
*- 计算是否有医保及医保数量
. for var qp605_s_*: replace X =. if X == 78
. gen medsure_dum = 0
. gen medsure_xnh = 0
. gen medsure_num = 0
. for var qp605_s_*: replace medsure_dum = 1 if X !=.
. for var qp605_s_*: replace medsure_xnh = 1 if X == 5
. for var qp605_s_*: replace medsure_num = medsure_num + 1 if X !=.
最后我们删除冗余变量,也将其存储到的 Temp_data 文件夹中:
. drop qa301 qea0 qp605_s_* cfps2018edu
. save "$temp_data/person_2018.dta", replace
闲话少叙,现在我们正式进行跨表合并。
跨表合并也分为两种,一种是以个人库作为主表 master
,家庭库作为附表 using
,进行合并。此类研究一般是以个体作为分析对象,例如研究医保对个体健康的影响。另一种是以家庭作为 master
,个人库作为 using
,此类研究一般以家庭作为分析对象,例如研究金融素养对家庭金融投资的影响。
如果以个人库作为 master
,一般是以家庭 id ifd18 作为唯一识别码,进行 merge
。 keepusing
为指定using
中具体的变量, keep(1 3)
为仅保留 master
和匹配成功的样本, nogen
为不生成 _merge
变量。
. *- 跨表合并
//个人库merge家庭库
. use "$temp_data/person_2018.dta", clear
. merge m:1 fid18 using "$temp_data/family_2018.dta", ///
keepusing(fincome1_per total_asset familysize18 agri finp) keep(1 3) nogen
Result # of obs.
-----------------------------------------
not matched 619
from master 619
from using 0
matched 36,735
-----------------------------------------
可以看到,有 619 个样本没有匹配到家庭信息,它们的家庭信息可能因为某些原因缺失了。我们给部分变量加上 label
,并进行 rename
之后,一般就可以直接使用了。
. label var medsure_dum "是否购买医保"
. label var medsure_xnh "是否购买新农合"
. label var medsure_num "购买医保数量"
. rename (provcd18 countyid18 cid18 urban18 familysize18) ///
(provcd countyid cid urban familysize)
. save "$temp_data/person2family2018.dta", replace
如果以家庭库作为 master
的话,则情况相对复杂,因为它属于一对多的关系,一个家庭中有多位家庭成员。此时我们一般选择户主作为家庭库与个人库的连接。户主的选取则参考 CFPS 的建议,将家庭的财务管理者认定为户主。关于户主的选取,大家可以详细阅读这篇文章:CFPS数据中有没有“户主”信息?|CFPS小课堂·家庭篇。
我们将家庭库中财务回答人的 resp1pid
改为 pid
,然后再进行 merge
。具体代码如下:
. //家庭库merge个人库
. use "$temp_data/family_2018.dta", clear
. rename resp1pid pid
. merge 1:1 fid18 pid using "$temp_data/person_2018.dta", ///
keepusing(gender-medsure_num) keep(1 3) nogen
Result # of obs.
-----------------------------------------
not matched 715
from master 715
from using 0
matched 13,503
-----------------------------------------
此时有 715个 家庭的户主信息没有匹配上。同样的,我们给部分变量加上 label
,修改变量名,存储到 Temp_data 文件夹里。
. label var medsure_dum "是否购买医保"
. label var medsure_xnh "是否购买新农合"
. label var medsure_num "购买医保数量"
. rename (provcd18 countyid18 cid18 urban18 familysize18) ///
(provcd countyid cid urban familysize)
. save "$temp_data/family2person2018.dta", replace
将数据整理出来之后,我们还可以进一步对数据进行核查。例如查看这个样本的变量缺失情况,我们可以引入 egen
里面的 rowmiss
函数:
*- 数据核查
. use "$temp_data/family2person2018.dta", clear
//查看变量缺失情况
. egen miss = rowmiss(urban fincome1_per total_asset familysize agri finp gender age)
. tab miss
miss | Freq. Percent Cum.
------------+-----------------------------------
0 | 12,600 88.62 88.62
1 | 875 6.15 94.77
2 | 613 4.31 99.09
3 | 121 0.85 99.94
4 | 9 0.06 100.00
------------+-----------------------------------
Total | 14,218 100.00
可以发现, 12600个 样本有上述八个变量的完整数据,占总样本的 88.62% ,四个变量有缺失数据的样本数为9,占总样本的 0.06% 。如果我们需要剔除变量缺失的样本,输入 keep if miss == 0
即可。
另外,我们观察数据发现,户主的年龄范围为 [11, 95] , 11 岁的户主显然说不过去,我们可以保留 16-85 岁的户主样本,这一步可以用 inrange
来实现:
//保留16-85岁的样本
. keep if inrange(age, 16, 85)
. save "$working_data/result_cfps2018.dta", replace
截面数据整理到这一步,已经基本算是告一段落了,我们将其存储到 Working_data 文件夹,方便后续进行回归分析。
但是,有时候截面数据并不能满足我们的研究需求,还需要进一步构造面板数据,甚至是多期面板数据。下面以 CFPS2016-2018 的家庭库为例,构造一个两期的面板数据。
我们先导入数据,用 keep
提取需要的变量,将各种原因的缺失值统一赋值为.
,在对变量进行重新赋值,操作与 CFPS2018 家庭库的处理方法一致。跨年合并需要注意一点,那就是保持变量名,以及变量值所代表的含义在各年之间保持不变。所以我们需要对部分变量 rename
,并生成一个年份变量。处理代码如下所示:
*- 跨年合并
. use "$cfps2016/cfps2016famecon_201807.dta", clear
. keep fid16 provcd16 countyid16 cid16 urban16 resp1pid fk1l ft200 ///
fincome1_per total_asset familysize16
//缺失值替换为.
. for var _all: replace X =. if inlist(X, -10, -9, -8, -2, -1)
//重新赋值
. recode fk1l (1 = 1 "是")(5 = 0 "否"), gen(agri)
. recode ft200 (1 = 1 "是")(5 = 0 "否"), gen(finp)
//存储家庭变量
. drop fk1l ft200
. rename (provcd18 countyid18 cid18 urban18 familysize18) ///
(provcd countyid cid urban familysize)
. gen year = 2016
. save "$temp_data/family_2016.dta", replace
我们导入 CFPS2018 的数据,同样进行 rename
和生成年份变量(实际上这一步在清洗 CFPS2018 时即可完成):
//CFPS2018数据
. use "$temp_data/family_2018.dta", clear
. rename (provcd18 countyid18 cid18 urban18 familysize18) ///
(provcd countyid cid urban familysize)
. gen year = 2018
. save "$temp_data/family_2018.dta", replace
然后我们对两份数据进行合并,并用 xtset
设定面板数据:
. //合并数据
. use "$temp_data/family_2016.dta", clear
. append using "$temp_data/family_2018.dta"
. drop fid18
. order fid16 year
. xtset fid16 year
repeated time values within panel
结果发现数据报错了,出现了 repeated time values
,也就是说有时间值是重复的。这主要是因为,我们以 CFPS2016 作为基期进行 append
,而在 2016-2018 两年间,有小部分家庭分家了。这部分家庭 fid16 是一样的, fid18 却不一致(实际上,以 CFPS2018 作为基期进行 append
,也会出现相似的问题)。我们需要删除分家的样本,仅保留两家/多家中的一家,或者两家/多家都删除。
我们可以先使用 duplicates tag
,标记出分家的样本。可以看到,两年间,有 989 个样本分成了两家, 89 个样本分成了三家, 7 个样本分成了四家。
//标记分家样本
. duplicates tag fid16 year, gen(num)
. tab num
num | Freq. Percent Cum.
------------+-----------------------------------
0 | 25,964 91.95 91.95
1 | 1,978 7.00 98.96
2 | 267 0.95 99.90
3 | 28 0.10 100.00
------------+-----------------------------------
Total | 28,237 100.00
我们即可以将分家的样本全部剔除,也可以仅保留分家中的一家,两种方法最终都可以组合成一个非平衡面板(推荐第一种方法,因为分家之后家庭可能发生了系统性变化,已不适合作为分析样本):
//删除全部分家样本
. keep if num == 0
. xtset fid16 year
panel variable: fid16 (unbalanced)
time variable: year, 2016 to 2018, but with gaps
delta: 1 unit
//保留分家中的一家样本
. duplicates drop fid16 year, force
. xtset fid16 year
panel variable: fid16 (unbalanced)
time variable: year, 2016 to 2018, but with gaps
delta: 1 unit
出于一些研究需求,有时候我们需要构建一份平衡面板。这时候我们可以借助 egen
中的 count
函数,计算出 fid16 出现的次数,并保留出现了两次的样本(说明该家庭在 CFPS2016 和 2018 中皆有出现)。可以发现,有 84.05 的家庭在两次调查中都存在。此时, xtset
之后就是平衡面板了。
//构建平衡面板
. bys fid16: egen num = count(fid16)
. tab num
num | Freq. Percent Cum.
------------+-----------------------------------
1 | 4,140 15.95 15.95
2 | 21,824 84.05 100.00
------------+-----------------------------------
Total | 25,964 100.00
. keep if num == 2
(4,140 observations deleted)
. drop num
. xtset fid16 year
panel variable: fid16 (strongly balanced)
time variable: year, 2016 to 2018, but with gaps
delta: 1 unit
很多文献都喜欢使用某个变量的社区/区县均值作为工具变量,因为人作为社会化的动物,必然会受到周围环境的影响,但是单独的个体却很难影响到环境。我们以是否持有金融产品为例,也计算一个“除自身以外,社区内持有金融产品的比例”。
我们先使用 bys+egen+count
计算出该社区的总人数 cidnum ,基于同样的逻辑,计算出该社区持有金融产品的人数 finpnum ,随后将持有金融产品人数减去自身,社区人数减去 1 ,两者之商即是社区均值(如果使用的是截面数据,去掉 bys
后面的 year 即可)。
//构造社区均值
. bys cid year: egen cidnum = count(cid)
. bys cid year: egen finpnum = sum(finp)
. gen average = (finpnum - finp) / (cidnum -1)
面板数据的一大优势的可以做双重差分 (DID) ,而 DID 则必然会有处理组和对照组,那么我们如何在微观数据中进行分组呢?我们继续以金融产品持有为例,假如我们想研究金融产品持有对
在具体的实现上,我们可以先对 finp 进行差分,即下一期减去当期,并用差分值对缺失值进行填补。由此,我们就可以知道每个样本持有金融产品的变化情况了。
可以发现, 235 个样本退出了金融市场, 10371 个样本的金融产品持有状况保持不变, 270个 样本则进入了金融市场,进入金融市场的样本就是我们的处理组。
//构造对照组与处理组
. xtset fid16 year
. bys fid16: gen treat = finp[_n+1] - finp[_n]
. bys fid16: replace treat = treat[_n-1] if mi(treat)
. tab treat
treat | Freq. Percent Cum.
------------+-----------------------------------
-1 | 470 2.16 2.16
0 | 20,742 95.36 97.52
1 | 540 2.48 100.00
------------+-----------------------------------
Total | 21,752 100.00
我们可以删除退出金融市场的样本,并生成一个时间虚拟变量 post
,此时, DID 的两个基本变量就已经完成了。
. drop if treat == -1
. gen post = (year == 2018)
. save "$working_data/panel2016_2018.dta", replace
下面我们来进行一个简单总结。在处理 CFPS 等微观数据时,我们可以先从单个表入手,提取出需要的变量,进行简单清洗。随后使用 merge
命令进行跨表合并,整理成截面数据。如果想进一步清洗面板数据的话,则需要将各年数据先整合成截面,然后再使用 append
进行跨年合并。
当然,以上都只是一家之言,笔者也只是给大家提供一种数据清洗的思路而已。
最后附上本文的全部代码,供大家参考:
* ======================================================
* Program:CFPS数据清洗
* Revised:2021-04-25
* ======================================================
clear all
clear matrix
set more off
global root = "/Applications/Stata/personal/CFPS"
global cfps2018 = "$root/CFPS2018"
global cfps2016 = "$root/CFPS2016"
global dofiles = "$root/Result_data/Dofiles"
global logfiles = "$root/Result_data/Logfiles"
global working_data = "$root/Result_data/Working_data"
global temp_data = "$root/Result_data/Temp_data"
log using "$logfiles/cfpsclean.log", replace
*- 提取家庭库变量
use "$cfps2018/cfps2018famecon_202101.dta", clear
keep fid18 fid16 provcd18 countyid18 cid18 urban18 resp1pid fk1l ft200 ///
fincome1_per total_asset familysize18
//查看变量标签
label list urban18
//缺失值替换为.
for var _all: replace X =. if inlist(X, -10, -9, -8, -2, -1)
//重新赋值
recode fk1l (1 = 1 "是")(5 = 0 "否"), gen(agri)
recode ft200 (1 = 1 "是")(5 = 0 "否"), gen(finp)
//存储家庭变量
drop fk1l ft200
save "$temp_data/family_2018.dta", replace
*- 提取个人库变量
use "$cfps2018/cfps2018person_202012.dta", clear
keep pid fid18 fid16 provcd18 countyid18 cid18 urban18 gender age ///
qa301 qea0 qp605_s_* cfps2018edu
for var _all: replace X =. if inlist(X, -10, -9, -8, -2, -1)
tab qa301
tab qea0
//重新赋值
recode qa301 (1 = 1 "农业户口")(3 = 0 "非农户口")(5 79 =.), gen(hukou)
recode qea0 (2 3 = 1 "有配偶")(1 4 5 = 0 "无配偶"), gen(spouse)
recode cfps2018edu (1 = 0 "文盲/半文盲")(2 = 1 "小学")(3 = 2 "初中")(4 = 3 "高中") ///
(5 6 7 8 = 4 "大学以以上"), gen(edu)
//计算是否有医保及医保数量
for var qp605_s_*: replace X =. if X == 78
gen medsure_dum = 0
gen medsure_xnh = 0
gen medsure_num = 0
for var qp605_s_*: replace medsure_dum = 1 if X !=.
for var qp605_s_*: replace medsure_xnh = 1 if X == 5
for var qp605_s_*: replace medsure_num = medsure_num + 1 if X !=.
drop qa301 qea0 qp605_s_* cfps2018edu
save "$temp_data/person_2018.dta", replace
*- 跨表合并
//个人库merge家庭库
use "$temp_data/person_2018.dta", clear
merge m:1 fid18 using "$temp_data/family_2018.dta", ///
keepusing(fincome1_per total_asset familysize18 agri finp) keep(1 3) nogen
label var medsure_dum "是否购买医保"
label var medsure_xnh "是否购买新农合"
label var medsure_num "购买医保数量"
rename (provcd18 countyid18 cid18 urban18 familysize18) ///
(provcd countyid cid urban familysize)
save "$temp_data/person2family2018.dta", replace
//家庭库merge个人库
use "$temp_data/family_2018.dta", clear
rename resp1pid pid
merge 1:1 fid18 pid using "$temp_data/person_2018.dta", ///
keepusing(gender-medsure_num) keep(1 3) nogen
label var medsure_dum "是否购买医保"
label var medsure_xnh "是否购买新农合"
label var medsure_num "购买医保数量"
rename (provcd18 countyid18 cid18 urban18 familysize18) ///
(provcd countyid cid urban familysize)
save "$temp_data/family2person2018.dta", replace
*- 数据核查
use "$temp_data/family2person2018.dta", clear
//查看变量缺失情况
egen miss = rowmiss(urban fincome1_per total_asset familysize agri finp gender age)
tab miss
keep if miss == 0
//保留16-85岁的样本
keep if inrange(age, 16, 85)
save "$working_data/result_cfps2018.dta", replace
*- 跨年合并
use "$cfps2016/cfps2016famecon_201807.dta", clear
keep fid16 provcd16 countyid16 cid16 urban16 resp1pid fk1l ft200 ///
fincome1_per total_asset familysize16
//缺失值替换为.
for var _all: replace X =. if inlist(X, -10, -9, -8, -2, -1)
//重新赋值
recode fk1l (1 = 1 "是")(5 = 0 "否"), gen(agri)
recode ft200 (1 = 1 "是")(5 = 0 "否"), gen(finp)
//存储家庭变量
drop fk1l ft200
rename (provcd16 countyid16 cid16 urban16 familysize16) ///
(provcd countyid cid urban familysize)
gen year = 2016
save "$temp_data/family_2016.dta", replace
//CFPS2018数据
use "$temp_data/family_2018.dta", clear
rename (provcd18 countyid18 cid18 urban18 familysize18) ///
(provcd countyid cid urban familysize)
gen year = 2018
save "$temp_data/family_2018.dta", replace
//合并数据
use "$temp_data/family_2016.dta", clear
append using "$temp_data/family_2018.dta"
drop fid18
order fid16 year
*xtset fid16 year
//标记分家样本
duplicates tag fid16 year, gen(num)
tab num
//删除全部分家样本
keep if num == 0
xtset fid16 year
drop num
//保留分家中的一家样本
duplicates drop fid16 year, force
xtset fid16 year
//构建平衡面板
bys fid16: egen num = count(fid16)
tab num
keep if num == 2
drop num
xtset fid16 year
//构造社区均值
bys cid year: egen cidnum = count(cid)
bys cid year: egen finpnum = sum(finp)
gen average = (finpnum - finp) / (cidnum -1)
//构造对照组与处理组
xtset fid16 year
bys fid16: gen treat = finp[_n+1] - finp[_n]
bys fid16: replace treat = treat[_n-1] if mi(treat)
tab treat
drop if treat == -1
gen post = (year == 2018)
save "$working_data/panel2016_2018.dta", replace
Note:产生如下推文列表的 Stata 命令为:
lianxh 普林斯顿 数据处理 reshape 合并
安装最新版lianxh
命令:
ssc install lianxh, replace
免费公开课
最新课程-直播课
专题 | 嘉宾 | 直播/回看视频 |
---|---|---|
⭐ 最新专题 | 文本分析、机器学习、效率专题、生存分析等 | |
研究设计 | 连玉君 | 我的特斯拉-实证研究设计,-幻灯片- |
面板模型 | 连玉君 | 动态面板模型,-幻灯片- |
面板模型 | 连玉君 | 直击面板数据模型 [免费公开课,2小时] |
⛳ 课程主页
⛳ 课程主页
关于我们
课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法
等
连享会小程序:扫一扫,看推文,看视频……
扫码加入连享会微信群,提问交流更方便
✏ 连享会-常见问题解答:
✨ https://gitee.com/lianxh/Course/wikis
New!
lianxh
命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh