处理时点不一致时,双向固定效应回归会把已经受处理的组当成后来才受处理那组的对照,权重甚至可能为负,估计出来的系数不再是一个清晰的平均处理效应。Callaway 和 Sant'Anna 2021 年发表在 Journal of Econometrics 的论文给出了另一套解法,这篇官方教程就是用 R 的 did 包把那套解法跑一遍:先算组别—时间平均处理效应,再按需要聚合,最后画图。
这份教程出自谁、对应哪个版本
教程标题是 Getting Started with the did Package,作者 Brantly Callaway 与 Pedro
H.C. Sant'Anna,页面标注的日期是 2026 年 7 月 30 日,源文件是包内的 vignettes/did-basics.Rmd。对应的 R 包在 CRAN 上的版本是 did 2.5.1,发布于 2026 年 7 月 8 日,要求 R 4.1.0 及以上,许可为 GPL-3。
包的定位写得很直接:标准 DID 设定只有两期两组,而大量应用有更多期、个体受处理的时间点也不一样,did 包就是为这种情形设计的。教程列出它做的四件事——允许多期和处理时点变异;允许平行趋势假设在控制协变量之后成立;估计结果不带双向固定效应回归或事件研究回归在多期、处理时点变异情形下的那些缺陷;既能给出分解到组与时间的平均处理效应,也能给出事件研究式估计和总体处理效应估计。
画图用的 ggdid 建立在 ggplot2 之上,包的其他依赖还有 DRDID、BMisc、data.table、tidyr、Matrix、pbapply、fastglm、dreamerr 等。
数据要整理成什么样
教程对数据格式的要求是长表:一行是一个个体在一个时间点上的观测。如果手上的是宽表,也就是一行包含一个个体在所有时期的信息,教程建议用 tidyr::pivot_longer 转换。
需要四个变量:个体标识、时间变量、结果变量、首次受处理的时期。在配套的真实数据 mpdta 里,这四个变量分别是 countyreal(县代码)、year(年份)、lemp(就业对数值)、first.treat(首次提高最低工资的年份);从未受处理的个体,first.treat 取 0。协变量用公式传入,例如 xformla = ~lpop,公式里也可以写变换与交互项,如 ~ I(lpop^
2)、~ log(lpop),或放入因子变量;不控制协变量时写 xformla = ~1。
mpdta 是 2003—2007 年县级青少年就业率的平衡面板,共 2500 条观测,另有 lpop(县人口对数)可作协变量。教程特别提醒三点:个体标识对同一个体不能随时间变化;分组变量对同一个体不能变;在平衡面板下,时变协变量取「基期」的值——处理后,基期是该组受处理的前一期(存在预期效应时还要再往前),处理前,基期是当期的前一期。
att_gt 怎么调用,输出表怎么读
最基础的一次调用只需要指定六个参数:
summary() 给出组别—时间平均处理效应表,列为 Group、Time、ATT(g,
t)、Std. Error 与 95% 同时置信带。教程用一份模拟数据演示:4 个时期,处理后剩余 15916 条观测(已经剔除了第一期就受处理的单位,因为它们对识别 ATT(g,
t) 没有帮助)。带星号的是置信带不覆盖 0 的单元格,例如第 2 组在第 4 期 ATT 为 2.9552,标准误 0.0680,置信带 2.7715 到 3.1389;而第 3 组在第 2 期为 -0.0433,置信带 -0.2215 到 0.1349,不带星号。
表下方还给出三项信息:平行趋势假设的预检验 p 值(模拟数据这一例是 0.60857)、对照组类型(Never Treated,预期期数 0)、估计方法(Doubly Robust,双重稳健)。
画图用 ggdid(),按组分别出图。图中红点是处理前的伪组别—时间平均处理效应,主要用来预检验平行趋势;蓝点是处理后的效应,读作某一组在某个时点上受处理的平均效应。教程还交代了同时置信带的来历:多期情形下默认用同时置信带处理多重检验问题,95% 均匀置信带的临界值是 2.7 而不是 1.96;可以在调用 att_gt 时设 bstrap=FALSE、cband=FALSE 改成点态置信区间,但作者明确表示不建议这么做。
四种聚合方式给出的 ATT 并不相同
组别和时间一多,逐格去读就不现实了。aggte() 提供四种聚合:
- 简单加权(type = "simple"):按组规模加权平均,模拟例得到 1.6583,标准误 0.0333。教程提醒这种方式会让早期受处理的组被过度加权,因为能观察到的处理后期数更多。
- 动态效应/事件研究(type = "dynamic"):按暴露长度聚合,模拟例总体 ATT 为 1.9904,标准误 0.0375;事件时间 -2、-1、0、1、2 分别为 0.0023、0.0105、0.9929、2.0231、2.9552。
- 分组效应(type = "group"):模拟例总体 1.488,第 2、3、4 组分别为 1.9545、1.5835、0.9523。教程说这是它推荐的总体效应口径,解释最接近教科书里两期两组情形的 ATT。
- 日历时间效应(type = "calendar"):模拟例总体 1.4808,第 2、3、4 期分别为 0.9209、1.5491、1.9724。
事件时间 0 是各组首次受处理那一期的平均效应,-1 是前一期,1 是首次暴露后的第一个时期。
真实数据那一例:最低工资与青少年就业
教程用 mpdta 走了一遍完整流程。不控制协变量(xformla = ~
1)时,平行趋势预检验 p 值为 0.16812,处理前各期的均匀置信带都覆盖 0。12 个组别—时间格中有两个为负且不覆盖 0:2004 年首次调薪的组在 2006 年为 -0.1373,2007 年为 -0.1008。
动态聚合给出的总体 ATT 是 -0.0772,标准误 0.0203,置信区间 -0.1171 到 -0.0374。分事件时间看,0、1、2、3 期分别为 -0.0199、-0.0510、-0.1373、-0.1008,后三期不覆盖 0。
教程还示范了 balance_e = 1:只保留能算出 e=0 与 e=1 的组(2004 与 2006 两组),剔除 2007 年那组,总体 ATT 变为 -0.0288,标准误 0.0135。这么做的理由是事件研究图里各期的组构成在变,如果效应在各组之间系统性不同,动态效应就会和选择性处理时点混在一起。
需要说明的是,教程自己写明这一例只是方法演示:要真正评估最低工资对青少年就业的影响,还有多处需要更谨慎处理,这里的结果应视为示例。
几处容易卡住的地方
- 小样本组:某个 ATT(g,
t) 估不出来时,att_gt 不会报错,而是对受影响的单元格给出警告并返回 NA。不过如果从未受处理的对照组本身太小,它会停下来并建议改设 control_group = "notyettreated";任一组观测数少于协变量个数加五时也会警告。
- 对照组:默认用从未受处理的组;若不存在这样的组,包会剔除最后一期,把到最后才受处理的单位设为对照,同时给出警告。改用「尚未受处理」作对照,设 control_group = "notyettreated"。
- 重复截面:设 panel = FALSE,此时 idname 可以省略。
- 非平衡面板:默认会强制转成平衡面板,即剔除任何时期有缺失的个体;设 allow_unbalanced_panel = TRUE 可不强制,代价是计算时间增加。
- 估计方法:默认双重稳健,即结果变量用线性回归、广义倾向得分用 logit;也可设 est_method = "ipw"(逆概率加权)或 "reg"(回归)。
- 适用范围:只适用于分批采纳且不可逆的设计,个体一旦受处理,此后各期都算受处理。
────────────────
教程页、CRAN 包页、GitHub 仓库、GPL-3 许可原文、可复现的 Rmd 源文件,以及教程中的英文原文摘录,回复后可见。
把经管之家装进你常用的 AI 智能体中 一键快捷安装经管之家 MCP/技能,让 AI 帮你查教程、找数据、读论坛帖子。 检索、阅读公开帖子不收费,安装可申请领取:3 通用积分+100 论坛币+3 元论坛资金 请点击查看安装教程与福利 → 说明: AI 算力按所用平台规则计算;附件按原帖条件获取;福利领取条件以活动页面为准。 |