☰
多期DID的Stata实操全流程:从数据构造到异质性稳健估计
2026/11/2 8:39:55 网站建设 项目流程

多期双重差分DID的stata操作,这个话题在实证研究圈子里热度一直居高不下。但凡做过政策评估类课题的人,几乎绕不开它。我接触过的项目中,十有八九需要处理“不同个体在不同时间点受到政策冲击”这种数据结构,而多期DID正是应对这类场景的主力工具。Stata作为实证研究的主流软件,其DID实现方式经历了从手工构造交互项到官方命令didregress、xtdidregress的演进,再到社区命令csdid、did_multiplegt的百花齐放。这篇文章面向的是已经具备基础计量知识、正在或即将处理多期政策评估数据的研究者,无论你是刚接触DID的研究生,还是需要快速复现文献结果的从业者,下面这些从实操中沉淀下来的流程和踩坑记录,应该都能直接拿来用。

1. 多期DID到底在做什么:从设计逻辑到模型设定

1.1 多期DID与经典两期DID的本质差异

很多人学DID是从两期开始的:一个处理组、一个对照组,政策在某一个统一时点实施,交互项系数就是处理效应。这个框架干净漂亮,但现实中的数据往往不是这个样子。多期DID的核心特征在于处理时点因个体而异——A省2015年推行了某项改革,B省2017年才跟进,C省始终没有推行。这时候你面对的是一个“交错处理”(staggered adoption)的面板数据,每个个体的处理状态随时间变化,处理组和对照组的构成也在动态调整。

这个差异带来的第一个直接后果是:不能再简单地用“处理组×政策后”一个交互项来概括全部信息。你需要为每个个体-年份观测定义处理状态变量,模型设定也要从两期框架扩展到多期框架。更关键的是,当处理效应存在异质性时,传统的双向固定效应(TWFE)估计量可能会产生偏误,这一点在后文会详细展开。

从模型形式上看,多期DID的标准设定可以写成:

[ Y_{it} = \alpha_i + \lambda_t + \beta D_{it} + \gamma X_{it} + \varepsilon_{it} ]

其中 (D_{it}) 是个体 (i) 在 (t) 期是否处于处理状态的虚拟变量,(\alpha_i) 和 (\lambda_t) 分别是个体固定效应和时间固定效应。这个式子看起来和普通面板回归没什么区别,但 (D_{it}) 的结构决定了它是不是一个合格的DID设计。我见过不少初学者直接把“是否处理组”和“是否政策后”两个变量相乘当作 (D_{it}),在交错处理场景下这是错误的——因为“政策后”对不同个体对应的是不同日历年份,必须逐个体逐年份地判断处理状态。

1.2 平行趋势假设在多期框架下的特殊含义

平行趋势是DID的命门,多期场景下它的含义比两期更微妙。两期DID只需要处理组和对照组在政策前满足共同趋势,多期DID则要求在每个处理队列(cohort)的处理前时期,该队列与尚未处理的个体之间满足平行趋势。换句话说,平行趋势是“队列-时期”层面的条件,而不是一个笼统的整体假设。

实操中检验平行趋势的常见做法是事件研究法(event study),即构造相对时间虚拟变量:

[ Y_{it} = \alpha_i + \lambda_t + \sum_{k=-K, k\neq -1}^{K} \beta_k \cdot \mathbb{1}(t - E_i = k) + \varepsilon_{it} ]

其中 (E_i) 是个体 (i) 的处理年份,(k) 是相对时间。以 (k=-1) 为基期,如果 (k<0) 的各期系数 (\beta_k) 统计上不显著异于零,就为平行趋势提供了支持性证据。这里有个实操细节值得强调:基期的选择会影响所有系数的解读,但不会改变趋势检验的实质结论。我习惯把 (k=-1) 设为基期,因为这是最接近处理时点的“干净”时期,但如果你发现基期本身受到预期效应污染,可以考虑改用 (k=-2) 或更早的时期。

还有一个容易被忽略的点:多期DID中不同队列的处理前窗口长度不同。一个2015年处理的队列,其 (k=-4) 对应2011年;一个2019年处理的队列,其 (k=-4) 对应2015年。如果样本期跨度不够长,早期队列的远端相对时间可能没有观测值,事件研究图的左右两端会不对称。这不是错误,但需要在报告中说明。

1.3 何时该警惕TWFE的偏误问题

这是多期DID领域近几年的核心议题,也是审稿人越来越关注的点。Goodman-Bacon(2021)的分解表明,交错处理下的TWFE估计量实际上是所有可能的“2×2 DID”的加权平均,其中包含“已处理组作为对照组”的比较。当处理效应随时间或队列变化时,这些“坏比较”会污染估计结果,甚至导致系数符号与真实效应相反。

具体来说,TWFE的权重可能为负,这意味着某些2×2比较的效应被反向加权。一个直观的例子:假设早期处理队列的效应很大,晚期处理队列的效应很小,TWFE会把“晚期队列作为早期队列的对照”这种比较纳入进来,而晚期队列在处理前的趋势如果与早期队列不同,就会产生偏误。De Chaisemartin和D'Haultfœuille(2020)进一步指出,即使处理效应同质,只要存在异质性处理时点,TWFE在某些条件下也不是无偏的。

那是不是所有多期DID都不能用TWFE了?也不是。如果你的处理效应在同队列内和跨队列间都近似同质,或者处理时点的变异不大,TWFE的偏误可能很小。但作为审稿人视角的稳妥做法,建议至少报告一种异质性稳健估计量作为对照,比如Callaway-Sant'Anna(csdid)或Sun-Abraham(eventstudyinteract)。这不是为了堆砌稳健性检验,而是因为审稿人现在默认会问这个问题。

2. Stata实现路径全解析:从数据构造到命令选型

2.1 数据结构要求与面板设定

在动手写任何命令之前,先把数据结构理清楚。多期DID的标准数据格式是个体-年份层面的面板数据,每一行是一个个体在某一年的观测。核心变量包括:

  • 个体标识符(如id)
  • 年份标识符(如year)
  • 结果变量(如y)
  • 处理状态变量(如treat,处理当年及之后为1,之前为0)
  • 处理年份变量(如first_treat,个体首次接受处理的年份,从未处理设为缺失或0)
  • 协变量(如有)

面板设定用xtset id year完成。这里有个常见坑:如果数据中有个体在某些年份缺失,xtset不会报错,但后续命令的滞后项和差分项会受影响。建议先用xtdescribe检查面板的平衡性,用xtsum看关键变量的组内和组间变异。对于多期DID,特别要关注first_treat的分布——用tab first_treat看看有多少个处理队列,每个队列的规模如何。如果某个队列只有一两个个体,估计该队列的异质性效应时标准误会很大,需要在结果解读时注意。

处理状态变量treat的生成逻辑是:gen treat = (year >= first_treat) if first_treat != .。对于从未处理的个体,treat始终为0。这里要确保first_treat的缺失值处理正确——Stata中缺失值是最大值,直接用year >= first_treat会把从未处理个体错误地标记为处理状态。我习惯用gen treat = (year >= first_treat) & !missing(first_treat)来避免这个问题。

2.2 手工构造交互项:最透明但最费劲的路子

在官方命令和社区命令成熟之前,大家做多期DID基本靠手工。核心思路是生成处理状态变量后,直接跑xtreg y treat i.year, fe或reghdfe y treat, absorb(id year)。这种做法的优点是完全透明——你知道自己在估计什么,系数就是处理状态的平均效应。缺点是它本质上就是TWFE,面对异质性处理效应时存在前述偏误。

手工路子的一个变体是生成队列×年份的交互项来做事件研究。具体操作是:先gen rel_time = year - first_treat,然后对每个相对时间生成虚拟变量,以 (k=-1) 为基期。代码大致如下:

gen rel_time = year - first_treat replace rel_time = -999 if missing(first_treat) * 生成相对时间虚拟变量,以-1为基期 forvalues k = 5(-1)2 { gen pre_`k' = (rel_time == -`k') } forvalues k = 0/5 { gen post_`k' = (rel_time == `k') } * 回归 reghdfe y pre_* post_*, absorb(id year) cluster(id)

这里有几个实操要点。第一,相对时间的窗口选择要结合样本期长度和处理队列分布,不能机械地取-5到+5,如果早期队列的处理前观测不足5期,pre_5会有大量缺失。第二,基期必须省略,否则完全共线。第三,聚类标准误的层级选择——通常聚类到个体层面,但如果处理是在更高层级(如省份)分配的,应该聚类到那个层级。我见过不少论文聚类层级和处理的分配层级不匹配,这是审稿人常挑的问题。

手工路子的另一个问题是多重共线性和虚拟变量陷阱。当你同时放入个体固定效应、时间固定效应和相对时间虚拟变量时,需要确保没有遗漏基期、没有重复定义。reghdfe会自动处理部分共线,但不会替你检查逻辑错误。建议跑完回归后用estat或手动检查一下被省略的变量是否符合预期。

2.3 官方命令 didregress 与 xtdidregress 的用法与边界

Stata 17引入了didregress和xtdidregress,这是官方对DID的正式支持。xtdidregress用于面板数据,基本语法是:

xtset id year xtdidregress (y) (treat), group(id) time(year)

这个命令的优势是内置了聚类标准误和多种设定选项,输出格式也更规范。它支持协变量、支持加权、支持多种聚类层级。但需要注意,xtdidregress默认的估计方法仍然是TWFE,也就是说它并没有解决异质性处理效应下的偏误问题。官方文档明确说了这一点,但很多使用者不看文档,以为用了官方命令就万事大吉。

xtdidregress的一个实用功能是内置的平行趋势检验。通过estat trendplots可以画出事件研究图,通过estat ptrends可以做正式的平行趋势检验。这比手工构造相对时间虚拟变量方便不少。但要注意,内置的趋势检验也是基于TWFE框架的,在交错处理下同样受偏误问题影响。我的建议是:用xtdidregress做基准回归和快速检验没问题,但正式发表前最好用异质性稳健方法交叉验证。

还有一个边界需要注意:xtdidregress要求数据是强平衡面板吗?不是强制的,但不平衡面板下,处理状态的定义和固定效应的估计都需要格外小心。如果个体在某些年份缺失,xtdidregress会基于可用观测进行估计,但处理效应的识别可能受到影响。建议在跑命令前用xtdescribe确认面板结构,必要时考虑用csdid等对不平衡面板更稳健的方法。

2.4 社区命令 csdid:异质性稳健估计的主流选择

csdid是Callaway和Sant'Anna(2021)方法的Stata实现,目前是多期DID异质性稳健估计中使用最广的命令之一。安装方式:

ssc install csdid, replace ssc install drdid, replace

基本语法:

csdid y, ivar(id) time(year) gvar(first_treat) method(dripw)

其中gvar指定首次处理年份变量,从未处理的个体该变量应设为0(不是缺失)。method(dripw)是默认的 doubly robust 估计方法,也可以选reg或ipw。csdid的输出包括每个队列-时期的ATT、总体ATT以及事件研究形式的汇总结果。

csdid的几个关键选项值得展开。agg(event)可以输出事件研究形式的汇总,agg(simple)输出简单平均,agg(group)按队列汇总。做事件研究图用csdid_plot:

csdid y, ivar(id) time(year) gvar(first_treat) method(dripw) csdid_plot, horizon(5) pre(5)

这里有个实操细节:csdid对从未处理组的要求是gvar=0,如果你把从未处理设为缺失,命令会报错或结果异常。另外,csdid默认使用从未处理组作为对照,如果你的数据中没有从未处理组(所有个体最终都被处理),需要用notyet选项,即用“尚未处理”的个体作为对照。这个选项在普遍推行政策的场景下很关键。

csdid的局限性也要清楚。第一,它要求处理是吸收型的(一旦处理就一直处理),如果政策可以反复进出,csdid不适用。第二,它对协变量的处理是通过结果回归和倾向得分加权实现的,协变量很多时计算量较大。第三,csdid的标准误计算基于影响函数,在大样本下表现良好,但小样本下可能需要bootstrap。我通常会在正式结果中报告csdid的解析标准误,同时用bootstrap做一次稳健性对照。

2.5 其他值得了解的估计量:did_multiplegt 与 eventstudyinteract

did_multiplegt是De Chaisemartin和D'Haultfœuille(2020)方法的实现,特别适合处理处理状态可以反复变化的场景。安装:

ssc install did_multiplegt, replace

基本语法:

did_multiplegt y id year treat, robust_dynamic dynamic(5) placebo(5) breps(100) cluster(id)

这个命令的优势是允许处理状态非吸收型,并且提供了动态效应和安慰剂检验的一体化输出。缺点是计算量较大,尤其是breps设得较高时。我一般先用breps(20)快速跑通看结果方向,确认无误后再用breps(100)或更高做正式报告。

eventstudyinteract是Sun和Abraham(2021)方法的实现,基于交互加权估计。安装:

ssc install eventstudyinteract, replace ssc install avar, replace

基本语法:

eventstudyinteract y pre_* post_*, absorb(id year) cohort(first_treat) control_cohort(never_treat) vce(cluster id)

其中control_cohort指定对照组的标识变量。这个命令的输出直接就是事件研究形式的系数,画图很方便。它的一个特点是对队列和相对时间的交互进行了加权处理,从而避免了TWFE的负权重问题。

这三个命令(csdid、did_multiplegt、eventstudyinteract)各有适用场景,不是互相替代的关系。我的经验是:如果处理是吸收型的、有干净的从未处理组,csdid是首选;如果处理可以反复、或者需要动态效应和安慰剂检验的一体化输出,did_multiplegt更合适;如果审稿人明确要求Sun-Abraham方法,就用eventstudyinteract。三者结果如果方向一致,说服力会强很多;如果差异较大,需要深入排查原因,而不是挑一个“好看”的报告。

3. 完整实操流程:从数据清洗到结果输出

3.1 数据清洗与处理变量构造的完整代码

假设手头有一份省级面板数据,包含prov_id、year、gdp、policy_year(政策实施年份,从未实施为缺失)等变量。完整的数据准备流程如下:

* 设定面板 xtset prov_id year * 检查面板结构 xtdescribe xtsum gdp * 构造处理状态变量 gen treat = 0 replace treat = 1 if year >= policy_year & !missing(policy_year) * 构造首次处理年份变量(从未处理设为0) gen first_treat = policy_year replace first_treat = 0 if missing(policy_year) * 检查处理队列分布 tab first_treat * 检查处理状态的时间变异 tab year treat, row

这段代码里,first_treat的构造是关键。csdid要求从未处理组为0,而eventstudyinteract的cohort选项也通常要求从未处理组有明确标识。如果你用的命令对缺失值和0的约定不同,需要相应调整。我习惯在数据清洗阶段就把first_treat统一为“从未处理=0”,然后在具体命令中按文档要求转换。

还有一个细节:处理年份是否可能早于样本期?如果某个个体的政策实施年份早于数据起始年份,那么该个体在整个样本期内都处于处理状态,它实际上没有“处理前”观测。这类个体在事件研究中无法贡献处理前系数,在csdid中会被归入“始终处理”组。如果这类个体数量较多,需要考虑是否将它们排除,或者确认它们的存在不会扭曲对照组的构成。

3.2 基准TWFE回归与事件研究图

先跑基准回归建立参照系:

* 基准TWFE reghdfe gdp treat, absorb(prov_id year) cluster(prov_id) * 带协变量 reghdfe gdp treat ln_pop ln_fdi, absorb(prov_id year) cluster(prov_id)

事件研究图的手工构造:

* 相对时间 gen rel_time = year - first_treat replace rel_time = -999 if first_treat == 0 * 生成相对时间虚拟变量(窗口-5到+5,基期-1) forvalues k = 5(-1)2 { gen pre_`k' = (rel_time == -`k') } forvalues k = 0/5 { gen post_`k' = (rel_time == `k') } * 回归 reghdfe gdp pre_5 pre_4 pre_3 pre_2 post_0 post_1 post_2 post_3 post_4 post_5, absorb(prov_id year) cluster(prov_id) * 画图(需要coefplot) ssc install coefplot, replace coefplot, keep(pre_* post_*) vertical yline(0) xline(6, lpattern(dash)) /// coeflabels(pre_5="-5" pre_4="-4" pre_3="-3" pre_2="-2" /// post_0="0" post_1="1" post_2="2" post_3="3" post_4="4" post_5="5") /// ciopts(recast(rcap)) msymbol(O)

画图时有个小技巧:xline(6, lpattern(dash))中的位置需要根据系数个数调整,因为coefplot默认按系数顺序排列,基期被省略后位置会偏移。更稳妥的做法是用coefplot的at()选项显式指定横坐标。另外,事件研究图的纵轴是系数大小,横轴是相对时间,基期位置应该留空或标注为0,而不是画一个点,否则读者会误以为基期系数被估计了。

3.3 csdid的完整调用与结果解读

* 安装 ssc install csdid, replace ssc install drdid, replace * 基准csdid csdid gdp, ivar(prov_id) time(year) gvar(first_treat) method(dripw) * 事件研究汇总 csdid gdp, ivar(prov_id) time(year) gvar(first_treat) method(dripw) agg(event) * 画图 csdid_plot, horizon(5) pre(5) * 带协变量 csdid gdp ln_pop ln_fdi, ivar(prov_id) time(year) gvar(first_treat) method(dripw)

csdid的原始输出会列出每个队列在每个时期的ATT,信息量很大但不够直观。agg(event)把结果汇总到相对时间维度,更适合做事件研究图。解读时要注意:csdid的总体ATT是各队列-时期ATT的加权平均,权重取决于队列规模和时期分布,所以它和TWFE的系数不完全可比。如果两者差异较大,不要慌,先检查处理效应是否存在明显的队列异质性——用agg(group)看各队列的ATT,如果早期队列效应大、晚期队列效应小,TWFE的偏误方向就可以预判了。

csdid_plot的默认图形可能不够美观,可以用graphoptions()调整。我通常会把csdid_plot和手工事件研究图放在一起对比,如果两者在处理前系数上都接近零、处理后系数方向一致,结果就比较可信。

3.4 稳健性检验的组合拳

多期DID的稳健性检验不是跑一个命令就完事,而是一套组合拳。我通常按以下顺序组织:

检验类型目的命令/操作
平行趋势检验验证处理前无显著差异事件研究图 +estat ptrends
异质性稳健估计排除TWFE负权重偏误csdid、did_multiplegt、eventstudyinteract
安慰剂检验排除随机因素随机分配处理时点,重复500次
预期效应检验排除政策提前反应加入处理前一期虚拟变量
样本敏感性排除极端值/特定队列驱动剔除早期/晚期队列、缩尾处理
聚类层级敏感性验证标准误稳健性个体/更高层级双向聚类

安慰剂检验的代码框架:

* 随机分配处理时点(保持队列规模不变) preserve set seed 12345 * 这里需要根据实际数据结构编写随机化逻辑 * 核心思路:在每个队列内部随机打乱处理年份 * 重复500次,记录伪处理系数 restore

预期效应检验的做法是在事件研究框架中加入pre_1(处理前一期)的虚拟变量,如果该系数显著,说明处理前一期已经出现反应,平行趋势假设存疑。但要注意,预期效应和真实的前趋势有时难以区分,如果pre_1显著但pre_2、pre_3不显著,可能是预期效应;如果多个处理前系数都显著,更可能是趋势差异。

4. 踩坑实录:多期DID实操中的典型问题与排查

4.1 处理变量构造错误:最常见的低级但致命问题

我见过最多的错误是处理状态变量的构造。典型症状包括:从未处理组的treat被错误标记为1、处理年份边界判断错误(如政策当年是否算处理)、面板不平衡导致某些年份的处理状态缺失。这些错误在回归结果上可能表现为系数方向完全相反,或者标准误异常大。

排查方法:跑回归前先做交叉表tab year treat,逐年检查处理组和对照组的数量变化是否符合预期。如果某个年份处理组数量突然跳变,检查是否有队列的处理年份集中在该年。再用tab first_treat treat检查每个队列的处理状态是否从first_treat当年开始为1。还有一个快速检查:assert treat == 0 if year < first_treat & first_treat != 0,如果报错说明构造逻辑有问题。

另一个隐蔽的坑是政策实施年份的编码。有些数据中政策年份记录的是“政策发布年”,但实际生效可能是下一年;有些政策在年中实施,当年是否算处理状态需要明确约定。这些细节不会在代码层面报错,但会影响结果解读。建议在数据清洗阶段就明确记录每个队列的处理年份定义,并在论文中说明。

4.2 平行趋势检验不通过的应对策略

平行趋势不通过是多期DID中最让人头疼的问题之一。先别急着换模型或删样本,按以下顺序排查:

第一,检查事件研究图的窗口选择。如果远端相对时间的系数显著,但近端不显著,可能是远端样本量太小导致的标准误膨胀,不一定是真的趋势差异。试着缩短窗口,看结论是否稳定。

第二,检查对照组构成。如果从未处理组很少,或者从未处理组与处理组在可观测特征上差异很大,平行趋势可能不成立。考虑用倾向得分匹配后的样本做DID,或者用csdid的notyet选项改变对照组定义。

第三,考虑加入协变量。有时候平行趋势不通过是因为遗漏了随时间变化的混杂因素。加入协变量后如果趋势改善,说明原模型存在遗漏变量偏误。但要注意,协变量必须是处理前确定的或外生的,把处理后的变量作为协变量会引入bad control问题。

第四,如果以上都不奏效,考虑用合成控制法或合成DID作为替代方案。合成DID(synthdid)通过加权组合对照组来构造合成对照,对平行趋势的要求相对宽松。但合成DID的实操复杂度更高,适合作为稳健性检验而非主回归。

4.3 标准误聚类层级的抉择

聚类层级的选择不是纯技术问题,而是和研究设计紧密相关的。基本原则是:聚类到处理分配的层级。如果政策是在省级层面统一实施的,即使个体数据是地市或县级,也应该聚类到省级。原因在于,同一省内个体的误差项可能因为共同的政策冲击而相关,聚类到更低层级会低估标准误。

但实际操作中常有妥协。如果省级单位数量太少(比如只有十几个省),聚类到省级会导致标准误估计不稳定,这时候可以考虑双向聚类(个体和年份)或者用wild bootstrap。Stata中双向聚类用vce(cluster prov_id year)或reghdfe的cluster(prov_id year)。wild bootstrap可以用boottest命令:

reghdfe gdp treat, absorb(prov_id year) cluster(prov_id) boottest treat, reps(9999)

还有一个容易被忽略的点:不同命令的默认聚类方式不同。xtdidregress默认聚类到group()指定的层级,csdid默认聚类到ivar()指定的层级,reghdfe需要手动指定。在报告结果时,要明确说明聚类层级,并且确保不同模型的聚类方式一致,否则系数和标准误的可比性会打折扣。

4.4 结果不显著时的排查清单

结果不显著不一定是坏事,但需要系统排查原因。我通常按以下清单过一遍:

  • 处理效应是否真的存在:先看描述统计,处理组和对照组的结果变量在处理前后是否有肉眼可见的差异。如果描述统计上就没什么差异,回归不显著可能是真实的零效应。
  • 样本量是否足够:多期DID的识别依赖于每个队列的处理前后观测,如果某些队列的观测很少,该队列的ATT估计会很不精确,拉低总体显著性。
  • 处理强度是否被稀释:如果处理变量是0/1虚拟变量,但实际政策强度因地区而异,可以考虑用连续型处理变量或强度加权。
  • 时间窗口是否合适:政策效应可能需要时间显现,如果只取处理后一两年,可能捕捉不到长期效应。试着延长处理后窗口。
  • 是否存在异质性效应被平均掉:总体不显著但某些子组显著,说明效应存在异质性。用csdid的agg(group)看各队列效应,或者做子组分析。

4.5 常见报错与快速修复

报错信息可能原因修复方法
gvar must be positivefirst_treat含负值或缺失未处理为0检查first_treat编码,从未处理设为0
variable treat not found处理变量未生成或名称拼写错误确认变量名,检查gen treat是否执行
panel variable not set未执行xtset先xtset id year
conformability error协变量有缺失值或类型不匹配misstable summarize检查缺失,确保数值型
csdid报错no never treated所有个体最终都被处理加notyet选项,用尚未处理组作对照
eventstudyinteract报错control_cohort对照组标识变量未正确指定确认control_cohort是0/1变量且与cohort对应

这些报错大多源于数据准备阶段的疏忽。我的习惯是在跑任何DID命令之前,先跑一遍codebook和misstable summarize,把关键变量的分布和缺失情况摸清楚,能省掉大量调试时间。

5. 从结果到论文:报告规范与审稿应对

5.1 多期DID结果表的规范呈现

多期DID的结果表不能只放一个TWFE系数就完事。审稿人现在期望看到至少两列:一列是基准TWFE,一列是异质性稳健估计(如csdid的总体ATT)。如果空间允许,再加一列事件研究形式的汇总。表格下方要注明聚类层级、控制变量、固定效应类型和样本量。

事件研究图是标配,但图的呈现有讲究。处理前系数应该和零线有清晰的视觉对比,置信区间不能太宽以至于看不出任何信息。如果处理前系数都接近零但置信区间很宽,说明检验力不足,这时候需要诚实报告,而不是宣称“平行趋势成立”。我见过不少论文把宽置信区间的事件研究图当作平行趋势的证据,这在方法上是不严谨的。

5.2 审稿人常问的问题与预备答案

多期DID论文的审稿意见中,高频问题包括:为什么用TWFE而不是异质性稳健估计?平行趋势检验的窗口为什么这样选?聚类层级为什么是个体而不是政策层级?处理效应是否存在队列异质性?这些问题在写作阶段就应该准备好答案,而不是等审稿人问了再补。

我的建议是:在方法部分主动说明TWFE的局限性,并报告至少一种异质性稳健估计作为对照;在平行趋势部分说明窗口选择的依据(如样本期长度、队列分布);在标准误部分解释聚类层级与研究设计的关系;在异质性部分用csdid的队列汇总或子组分析展示效应差异。主动交代比被动回应更能建立可信度。

5.3 代码可复现性的实操建议

最后说一个容易被忽视但越来越重要的点:代码的可复现性。多期DID的实操涉及多个命令和大量数据转换,如果代码组织混乱,几个月后自己都看不懂。我的习惯是按以下结构组织do文件:

* 01_clean.do:数据清洗、变量构造、面板设定 * 02_baseline.do:基准TWFE、事件研究图 * 03_robust.do:csdid、did_multiplegt、eventstudyinteract * 04_placebo.do:安慰剂检验、敏感性分析 * 05_output.do:结果导出、表格生成

每个do文件开头用注释说明输入输出和依赖的包,关键步骤加注释说明“为什么这样做”而不只是“做了什么”。用version命令锁定Stata版本,用ssc install记录外部命令的安装。如果期刊要求提交复现包,这些准备工作能省掉大量返工。

我个人在实际操作中的体会是,多期DID的难点从来不在命令本身——csdid的语法半小时就能学会——而在于对研究设计的理解和对数据结构的把控。处理变量怎么构造、对照组怎么选、平行趋势怎么检验、标准误怎么聚类,这些决策的质量决定了结果的可信度,而命令只是把这些决策翻译成数字。踩过几次坑之后,我现在养成了一个习惯:跑任何回归之前,先用tab和sum把处理组和对照组在各个时期的关键特征过一遍,肉眼看看趋势是否平行、样本是否均衡。这个看似笨拙的步骤,往往比事后一堆稳健性检验更能提前发现问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询