问题描述
我想按行业和年份将经过处理的公司与控制公司进行匹配,考虑到在盈利能力(roa)方面最接近的公司。我想要1:1
个比赛。我正在使用距离测量(mahalanobis
)。
我的样本中有530,000
个企业年度观测值,即267,000
处理过的观测值和263,000
对照观测值。这是我的代码:
gen neighbor1 = .
gen idobs = .
levelsof industry
local a = r(levels)
levelsof year
local b = r(levels)
foreach i in `a' {
foreach j in `b'{
capture noisily psmatch2 treat if industry == `i' & year == `j',mahalanobis(roa)
capture noisily replace neighbor1 = _n1 if industry == `i' & year == `j'
capture noisily replace idobs = _id if industry == `i' & year == `j'
drop _treated _support _weight _id _n1 _nn
}
}
Treat
是我的治疗变量。对于已处理的观察,其值为1
;对于未处理的观察,其值为0
。
命令psmatch2
将创建变量_n1
和_id
等。 _n1
是匹配观察值(最近的邻居)的ID号,_id
是每个观察值唯一的ID号(1
-530,000
)。
代码“有效”,即未收到任何错误消息。我的变量neighbor1
具有290,724
个非缺失的观察结果。
但是,这些290,724
观察值在1
和933
之间变化,这很奇怪。变量neighbor1
应该为我提供匹配观察值的观察ID号,它可以在1
和530,000
之间变化。
该代码似乎擦除或忽略了不同子组中匹配过程的结果。我在做什么错了?
编辑:
我找到了一个公共数据集,并修改了以前的代码,以便您可以使用该数据集运行我的代码,并更清楚地了解问题所在。
我正在使用Vella和Verbeek(1998)的面板数据来研究每年545
-1980
的{{1}}人的工作,该工作来自以下网站:https://www.stata.com/texts/eacsap/
让我们说,我要匹配已观察到的观察值(即人),以根据婚姻状况(1987
)和年份(考虑工作时间相似的人(married
)来控制观察值,即最短的距离。
为此示例,我创建了一个随机处理变量(hours
。
treat
此代码应该做的是查看观察的每个子组:use http://www.stata.com/data/jwooldridge/eacsap/wagepan.dta
gen treat = round(runiform())
gen neighbor1 = .
gen idobs = .
levelsof married
local a = r(levels)
levelsof year
local b = r(levels)
foreach i in `a' {
foreach j in `b'{
capture noisily psmatch2 treat if married == `i' & year == `j',mahalanobis(hours)
capture noisily replace neighbor1 = _n1 if married == `i' & year == `j'
capture noisily replace idobs = _id if married == `i' & year == `j'
drop _treated _support _weight _id _n1 _nn
}
}
中444
个未婚的观察,1980
中已婚的101
个观察, ...,以及1980
中已婚的335
观察。考虑到工作小时数最短的距离,我希望在每个亚组中将经过处理的观察结果与对照观察结果进行匹配。
运行代码后,我看到两个问题。
首先,变量1987
在idobs
和1
之间应采用唯一的数字,因为此数据集中有4360
个观测值。这只是一个ID号。事实并非如此。一些观察值可以具有ID号4360
,1
等。
第二,2
在neighbor1
和1
之间变化,这意味着匹配的观测值仅具有从204
到1
之间变化的ID号。
我的代码有什么问题?
解决方法
这是使用命令iematch
的解决方案,该命令通过软件包ietoolkit
-> ssc install ietoolkit
安装。为了公开起见,我编写了此命令。如果您想要ATT,psmatch2
很棒。但是,如果您想要的只是使用最近的邻居对两组观察值进行匹配,那么iematch
会更干净。
在两个命令中,您都需要在子集中使每个行业年份匹配,然后合并该信息。在这两个命令中,匹配的组ID将在每个子集中从1重新开始。
使用示例数据,这会为每个子集创建一个matchID变量,然后您将不得不找到一种将它们组合为单个matchID的方法,而不会在整个数据集中产生冲突。
* use data set and keep only vars required for simplicity
use http://www.stata.com/data/jwooldridge/eacsap/wagepan.dta,clear
keep year married hour
* Set seed for replicability. NEVER use the 123456 seed in production,randomize a new seed
set seed 123456
*Generate mock treatment
gen treat = round(runiform())
*generate vars to store results
gen matchResult = .
gen matchDiff = .
gen matchCount = .
*Create locals for loops
levelsof married
local married_statuses = r(levels)
levelsof year
local years = r(levels)
*Loop over each subgroup
foreach year of local years {
foreach married_status of local married_statuses {
*This command is similar to psmatch2,but a simplified version for
* when you are not looking for the ATT.
* This command is only about matching.
iematch if married == `married_status' & year == `year',grp(treat) match(hour) seedok m1 maxmatch(1)
*These variables list meta info about the match. See helpfile for docs,*but this copy info from each subset in this loop to single vars for
*the full data set. Then the loop specfic vars are dropped
replace matchResult = _matchResult if married == `married_status' & year == `year'
replace matchDiff = _matchDiff if married == `married_status' & year == `year'
replace matchCount = _matchCount if married == `married_status' & year == `year'
drop _matchResult _matchDiff _matchCount
*For each loop you will get a match ID restarting at 1 for each loop.
*Therefore we need to save them in one var for each loop and combine afterwards.
rename _matchID matchID_`married_status'_`year'
}
}