Toolbox

The did2s Package in R: Two-Stage Difference-in-Differences for Staggered Adoption

1 What problem does this tool solve?

When treatment is adopted at different times by different units, the two-way fixed effects (TWFE) regression that generations of applied economists reached for can return a badly biased estimate even a coefficient of the wrong sign because already-treated units serve as controls for newly-treated ones, contaminating the comparison with negative weights [Goodman-Bacon, 2021, de Chaisemartin and D'Haultfœuille, 2020]. A wave of "robust" estimators fixes this. The did2s package [Butts and Gardner, 2022] implements the two-stage imputation estimator of Gardner [2022], closely related to the imputation approach of Borusyak et al. [2024]. Its appeal is conceptual clarity and speed: it estimates the untreated potential outcome from never- and not-yet-treated observations, then reads the treatment effect off the residuals.

2 The estimator in one paragraph

Assume untreated potential outcomes follow a two-way model $Y_{it}(0)=\mu_{i}+\lambda_{t}+\epsilon_{it}$: unit fixed effects $\mu_{i}$ plus time fixed effects $\lambda_{t}$. Stage one estimates $\mu_{i}$ and $\lambda_{t}$ using only observations that are not yet treated (where $Y_{it}=Y_{it}(0)$ is observed), never touching the treated cells. Stage two forms the imputed counterfactual $\hat{Y}_{it}(0)=\hat{\mu}_{i}+\hat{\lambda}_{t}$ and regresses the residual $Y_{it}-\hat{Y}_{it}(0)$ on treatment indicators to recover the effect

$$\hat{\tau} = \text{(residualised outcome projected on treatment dummies)}$$

$$Y_{it} - \hat{Y}_{it}(0) = \tau D_{it} + \text{noise}. \qquad (1)$$

Because the first stage never uses treated observations to estimate the fixed effects, the already-treated-as-control contamination cannot arise. Standard errors are corrected analytically for the two-stage structure (the second stage uses generated regressors), avoiding the naive understatement a plug-in would produce.

3 Installation and setup

# From CRAN install.packages("did2s")[cite: 23] # Development version # remotes::install_github("kylebutts/did2s") library(did2s)[cite: 23] library(fixest)[cite: 23] library(ggplot2)[cite: 23] # did2s is built on fixest's fast FE machinery

4 A minimal working example

We simulate a staggered-adoption panel with heterogeneous, dynamic effects, then estimate the overall ATT and an event study. did2s ships a simulated dataset, df_het, ideal for a first pass.

data("df_het", package = "did2s")[cite: 23] # Static overall ATT static <- did2s([cite: 23] data = df_het,[cite: 23] yname = "dep_var",[cite: 23] first_stage = ~ 0 | unit + year, # FE model for Y(0), no treated obs used second_stage = ~ i(treat, ref = FALSE), # effect of the binary treatment indicator treatment = "treat",[cite: 23] cluster_var = "state"[cite: 23] )[cite: 23] summary(static)[cite: 23]

The first_stage formula specifies the model for untreated potential outcomes here just unit and year fixed effects. The package automatically restricts first-stage estimation to untreated/not-yet-treated rows using the treatment indicator. The second_stage formula specifies which treatment terms to estimate.

For an event study, replace the second stage with relative-time indicators:

# Event study (dynamic effects by time since-treatment) es <- did2s([cite: 23] data = df_het,[cite: 23] yname = "dep_var",[cite: 23] first_stage = ~ 0 | unit + year,[cite: 23] second_stage = ~ i(rel_year, ref = c(-1, Inf)), # omit k=-1 and never-treated treatment = "treat",[cite: 23] cluster_var = "state"[cite: 23] )[cite: 23] # fixest's iplot draws the event study coefficients with CIs iplot(es, main = "Two-stage DiD event study", xlab = "Years relative to treatment")[cite: 23]

The reference categories relative period -1 and the never-treated (Inf) define the baseline against which dynamic effects are measured. Pre-treatment coefficients near zero support the parallel-trends assumption; post-treatment coefficients trace the effect's dynamics.

5 Key options and pitfalls

  • Covariates in the first stage. Time-varying controls enter the first stage formula, e.g. ~ x1 + x2 | unit + year. Be careful: a control that is itself affected by treatment is a "bad control" and biases the estimate include only covariates whose paths are unaffected by the policy [Caetano et al., 2022].
  • Never-treated vs. not-yet-treated. Identification needs a clean control group. If every unit is eventually treated, the first stage leans entirely on not-yet-treated timing variation; a pure never-treated group strengthens the design.
  • Standard errors. did2s implements the analytic two-stage correction; do not substitute a naive clustered SE from a hand-rolled two-step, which ignores the generated-regressor problem and understates uncertainty.
  • Anticipation. If units respond before the official adoption date, those periods are effectively treated and must be coded as such, or the first stage is contaminated.

6 Comparison to alternatives

did2s sits in a family of robust estimators, and in practice they agree far more with each other than any of them agrees with naive TWFE [Roth et al., 2023]. Table 1 sketches the landscape.

Choose did2s when you want a fast, transparent imputation estimator whose assumptions (a two-way model for untreated outcomes and clean controls) are easy to state and whose event-study output plugs directly into fixest's plotting tools.[cite: 23] When conditional parallel trends require flexible covariate adjustment, pair the intuition here with the doubly robust did package; when efficiency is paramount, compare against staggered.[cite: 23] The healthy habit, as always, is to run two or three and report that they agree.[cite: 23]

References

  • Borusyak, K., Jaravel, X., and Spiess, J. (2024). Revisiting event-study designs: Robust and efficient estimation. Review of Economic Studies, 91(6), 3253-3285.[cite: 23]
  • Butts, K., and Gardner, J. (2022). did2s: Two-stage difference-in-differences. The R Journal, 14(3), 162-173.[cite: 23]
  • Caetano, C., Callaway, B., Payne, S., and Rodrigues, H. S. (2022). Difference in differences with time-varying covariates. arXiv preprint arXiv:2202.02903.[cite: 23]
  • de Chaisemartin, C., and D'Haultfœuille, X. (2020). Two-way fixed effects estimators with heterogeneous treatment effects. American Economic Review, 110(9), 2964-2996.[cite: 23]
  • Gardner, J. (2022). Two-stage differences in differences. arXiv preprint arXiv:2207.05943.[cite: 23]
  • Goodman-Bacon, A. (2021). Difference-in-differences with variation in treatment timing. Journal of Econometrics, 225(2), 254-277.[cite: 23]
  • Roth, J., Sant'Anna, P. H. C., Bilinski, A., and Poe, J. (2023). What's trending in difference-in-differences? A synthesis of the recent econometrics literature. Journal of Econometrics, 235(2), 2218-2244.[cite: 23]

    Continue Reading

    Browse All Sections →
    Home
    This is some text inside of a div block.
    This is some text inside of a div block.
    This is some text inside of a div block.

    Article Title