Math for Causal Inference

Day 70. Staggered Adoption: the Goodman-Bacon Decomposition

When units adopt a policy at different times, the TWFE coefficient is a weighted average of every possible 2×2 DiD, including comparisons that use already-treated units as controls. With effects that change over time those comparisons are contaminated, and TWFE can be far from, or even opposite in sign to, every true effect.

Video coming soon
Learning outcomes
  • ●List the 2×2 comparisons hidden inside a staggered TWFE regression.
  • ●Explain the decomposition weights and why units treated in the middle of the panel get the most weight.
  • ●Prove that TWFE is unbiased with constant effects and biased with dynamic effects through "forbidden" comparisons.
  • ●Compute a decomposition and compare TWFE with the true average effect.
2-HOUR SESSION PLAN
Theory 25′Warm-up (1–5) 20′Proofs (6–10) 35′Applied (11–15) 25′Python & Lab 15′
Colab notebook (.ipynb) Jump to the simulator

Theory

Staggered adoption

Units adopt treatment at different dates and stay treated. Write kk for an early group (adopts at tkt_k), ll for a late group (tl>tkt_l > t_k), and UU for never-treated units. The common practice was to run the TWFE regression Yit=αi+λt+βDit+εitY_{it} = \alpha_i + \lambda_t + \beta D_{it} + \varepsilon_{it} and call β^\hat\beta "the effect".

The decomposition

Goodman-Bacon (2021) showed that, in a balanced panel,

β^TWFE=∑2×2 comparisons jsj β^j2×2,∑jsj=1,  sj≥0.\hat\beta_{TWFE} = \sum_{\text{2×2 comparisons } j} s_j\,\hat\beta^{2\times2}_j, \qquad \sum_j s_j = 1,\; s_j \ge 0.

With one early group, one late group and a never-treated group there are four comparisons:

ComparisonTreatedControlWindow
β^kU\hat\beta_{kU}earlyneverall periods
β^lU\hat\beta_{lU}lateneverall periods
β^klk\hat\beta^{k}_{kl}earlylate (not yet treated)before tlt_l
β^kll\hat\beta^{l}_{kl}lateearly (already treated)from tkt_k on

The weights

Each weight grows with the size of the two groups and with the variance of treatment in the comparison, Dˉ(1−Dˉ)\bar D(1 - \bar D), where Dˉ\bar D is the share of the window in which the treated group is treated. Groups treated in the middle of the panel (Dˉ\bar D near 0.5) get the most weight; this weighting is a property of OLS, not of the policy question.

When it goes wrong

  • Constant effects: every 2×2 equals the effect; TWFE is fine.
  • Effects differing across groups but constant over time: TWFE is a convex, variance-weighted average of group effects; not the ATT, but between them.
  • Effects that change over time: the comparison β^kll\hat\beta^{l}_{kl} uses the early group as a control after it was treated, so its still-evolving effect is subtracted. TWFE can be biased and even have the wrong sign. In the equivalent ATT language (de Chaisemartin and D'Haultfœuille), some group-time effects receive negative weights.

Diagnostics and fixes

Plot the 2×2 estimates against their weights (a "Bacon plot"), check how much weight falls on already-treated controls, and use heterogeneity-robust estimators that never use treated units as controls (Day 71).

Part 1 · Warm-up

Exercise 1 · Count the comparisons

With an early group, a late group and never-treated units, list the 2×2 comparisons. How many are there with three timing groups and a never-treated group?

Show solution

Step 1. Two groups: each timing group against never-treated (2), and each ordered pair of timing groups with the later or earlier one as control (2). Total 4.

Step 2. Three timing groups: 3 against never-treated, plus 2 for each of the 3 pairs = 6. Total 9 (K2K^2 with KK timing groups).

Exercise 2 · Treatment variance

In a 10-period panel, the early group is treated from period 4, the late group from period 7. Compute Dˉ(1−Dˉ)\bar D(1 - \bar D) for each against the never-treated group.

Show solution

Step 1. Early: treated 7 of 10 periods, Dˉk=0.7\bar D_k = 0.7, variance 0.210.21.

Step 2. Late: treated 4 of 10, Dˉl=0.4\bar D_l = 0.4, variance 0.240.24.

Answer: the late group's comparison gets slightly more weight per unit, being closer to the middle of the panel.

Exercise 3 · Constant effects

If treatment raises outcomes by exactly 2 for every unit in every treated period, what does each 2×2 estimate and TWFE equal?

Show solution

Step 1. Each 2×2 compares changes; untreated trends are parallel and every post-period difference is 2.

Answer: every comparison equals 2, so TWFE = 2 whatever the weights.

Exercise 4 · The forbidden comparison

Explain why the late-versus-early comparison is problematic when the early group's effect grows over time.

Show solution

Step 1. In the window from tkt_k, the early group is always treated, so it serves as the "control".

Step 2. Its outcomes keep changing because its treatment effect keeps growing, not because of a common trend.

Answer: that growth is subtracted from the late group's change, biasing the comparison downward.

Exercise 5 · Which units identify what?

In the 2×2 that compares early with late before tlt_l, why is the late group a legitimate control?

Show solution

Step 1. Before tlt_l, the late group is untreated: its changes reflect untreated trends.

Answer: under parallel trends (and no anticipation by the late group), it is a valid "not-yet-treated" control.

Part 2 · Proofs

Exercise 6 · Constant effects mean no bias

Assume parallel trends and a constant effect τ\tau for all units and periods. Prove each 2×2 estimand equals τ\tau, and hence βTWFE=τ\beta_{TWFE} = \tau.

Show solution

Step 1. In any 2×2, the treated group's change is (common trend) + τ\tau × (change in its treatment status between pre and post windows) = trend + τ\tau.

Step 2. The control group's change is the common trend: for not-yet-treated controls nothing changes; for already-treated controls the effect τ\tau is present in both windows and cancels.

Step 3. Each 2×2 equals τ\tau; the weights sum to 1. ■\blacksquare

Exercise 7 · The contaminated comparison

Let the early group's effect be τk(e)\tau_k(e) at event time ee and the late group's τl(e)\tau_l(e). Show that, under parallel trends, βkll=τl‾ post−(τk‾ post−τk‾ pre)\beta^{l}_{kl} = \overline{\tau_l}^{\,post} - \big(\overline{\tau_k}^{\,post} - \overline{\tau_k}^{\,pre}\big), where the bars average over the windows' periods.

Show solution

Step 1. Late group: its change between the window's pre part (tk≤t<tlt_k \le t < t_l, untreated) and post part (t≥tlt \ge t_l) is trend + average τl\tau_l over the post part.

Step 2. Early group: treated throughout; its change is trend + (average τk\tau_k in the post part − average τk\tau_k in the pre part).

Step 3. Subtract. ■\blacksquare If τk\tau_k grows over time, the bracket is positive and the comparison is biased downwards.

Exercise 8 · Group-specific constant effects

Suppose effects differ across groups but not over time (τk\tau_k, τl\tau_l). Show βTWFE=(skU+sklk)τk+(slU+skll)τl\beta_{TWFE} = (s_{kU} + s^{k}_{kl})\tau_k + (s_{lU} + s^{l}_{kl})\tau_l, a convex combination that generally differs from the ATT.

Show solution

Step 1. βkU=τk\beta_{kU} = \tau_k, βlU=τl\beta_{lU} = \tau_l, βklk=τk\beta^{k}_{kl} = \tau_k (late group untreated in that window).

Step 2. By Exercise 7 with constant τk\tau_k, the bracket is 0, so βkll=τl\beta^{l}_{kl} = \tau_l.

Step 3. Collect terms; weights are non-negative and sum to 1. ■\blacksquare The ATT weights groups by their number of treated unit-periods instead.

Exercise 9 · A wrong sign

Construct an example (early effect growing, late effect small) in which βkll<0\beta^{l}_{kl} < 0 although every unit's effect is non-negative.

Show solution

Step 1. Let τk(e)=e\tau_k(e) = e (zero on impact, growing by 1 per period) and τl(e)=0.5\tau_l(e) = 0.5.

Step 2. With the early group adopting at period 4 and the late at 7 in a 10-period panel, the window pre part is periods 4–6 (e=0,1,2e = 0, 1, 2; mean 1) and post part 7–10 (e=3,…,6e = 3, \dots, 6; mean 4.5).

Step 3. By Exercise 7: βkll=0.5−(4.5−1)=−3\beta^{l}_{kl} = 0.5 - (4.5 - 1) = -3.

Answer: a negative comparison from non-negative effects; with enough weight it can make TWFE negative. ■\blacksquare

Exercise 10 · Weights favour the middle

For a timing group compared with never-treated units of equal size, the weight is proportional to Dˉ(1−Dˉ)\bar D(1 - \bar D). Show this is maximised when treatment covers half the panel.

Show solution

Step 1. f(Dˉ)=Dˉ−Dˉ2f(\bar D) = \bar D - \bar D^2 has derivative 1−2Dˉ1 - 2\bar D.

Step 2. Zero at Dˉ=0.5\bar D = 0.5; second derivative −2<0-2 < 0. ■\blacksquare Groups adopting near the start or end of the panel get little weight, regardless of how policy-relevant they are.

Part 3 · Applied

Exercise 11 · Divorce law reforms with dynamic effects

States adopt a reform in period 4 (early) or 7 (late) of a 10-period panel; a third of states never adopt; groups are equal in size. Effects grow: 1 on impact, +0.5 per year. The 2×2 estimates are 2.5 (early vs never), 1.75 (late vs never), 1.5 (early vs not-yet-treated late) and 0 (late vs already-treated early), with weights 0.318, 0.364, 0.136, 0.182. Compute TWFE and compare with the ATT over all treated state-years.

Show solution

Step 1. β^TWFE=0.318(2.5)+0.364(1.75)+0.136(1.5)+0.182(0)=0.795+0.637+0.204+0≈1.64\hat\beta_{TWFE} = 0.318(2.5) + 0.364(1.75) + 0.136(1.5) + 0.182(0) = 0.795 + 0.637 + 0.204 + 0 \approx 1.64.

Step 2. ATT: early cells (periods 4–10, e=0,…,6e = 0, \dots, 6) average 1+0.5×3=2.51 + 0.5 \times 3 = 2.5; late cells (7–10, e=0,…,3e = 0, \dots, 3) average 1.751.75.

Step 3. Weighted by treated cells: (7×2.5+4×1.75)/11=24.5/11≈2.23(7 \times 2.5 + 4 \times 1.75)/11 = 24.5/11 \approx 2.23.

Answer: TWFE (1.64) understates the ATT (2.23) by about a quarter; the forbidden comparison contributes 0 with 18% weight.

Exercise 12 · Changing the group sizes

Repeat Exercise 11 with group sizes 2 (early) : 1 (late) : 3 (never), which give weights 0.525, 0.300, 0.075, 0.100. Compute TWFE.

Show solution

Step 1. 0.525(2.5)+0.300(1.75)+0.075(1.5)+0.100(0)=1.3125+0.525+0.1125=1.950.525(2.5) + 0.300(1.75) + 0.075(1.5) + 0.100(0) = 1.3125 + 0.525 + 0.1125 = 1.95.

Answer: 1.95, against an ATT of 2.33 with these group sizes: more never-treated units shift weight to clean comparisons, but bias remains.

Exercise 13 · Diagnosing a published estimate

A paper's TWFE estimate of a hospital-merger effect on prices is 1%; a Bacon decomposition shows 40% of the weight on comparisons with already-merged hospitals as controls, whose 2×2 estimates are −4%. What would you conclude?

Show solution

Step 1. The clean comparisons must average about (1−0.4×(−4))/0.6=2.6/0.6≈4.3%(1 - 0.4 \times (-4))/0.6 = 2.6/0.6 \approx 4.3\%.

Step 2. The negative forbidden comparisons pull TWFE down, consistent with price effects that grow after mergers.

Answer: the true effect is likely several times larger than 1%; re-estimate with a heterogeneity-robust method (Day 71).

Exercise 14 · Electronic health records

Hospitals adopted electronic health records between 2008 and 2016, with incentives starting in 2011; almost all had adopted by 2016. A study wants the effect on medication errors. What design concerns does staggered adoption raise?

Show solution

Step 1. Few never-treated hospitals: most comparisons in TWFE would use earlier adopters as controls for later ones.

Step 2. Learning effects make the impact grow over time, the case where those comparisons are biased.

Step 3. Better: group-time ATTs with not-yet-treated controls, restricted to periods before almost everyone adopted, and event-study plots by cohort.

Exercise 15 · What to report

List what a staggered-adoption DiD paper should report alongside (or instead of) a single TWFE coefficient.

Show solution

Step 1. The adoption timeline (how many units adopt when; any never-treated units).

Step 2. A Bacon decomposition: estimates and weights by comparison type.

Step 3. Heterogeneity-robust estimates (group-time ATTs and event-study aggregations) and their pre-trends.

Step 4. A discussion of which average effect is reported and for which units.

Verify in Python

import numpy as np

def panel(T, tk, tl, eff, eff_late=None):
    eff_late = eff_late or eff
    t = np.arange(1, T + 1)
    D = np.array([(t >= tk), (t >= tl), np.zeros(T, bool)]).astype(float)
    base = np.array([1.0, 2.0, 0.5])[:, None] + 0.3 * t[None, :]
    E = np.array([eff(t - tk), eff_late(t - tl), np.zeros(T)])
    return base + D * E, D, t

def twfe_weighted(Y, D, w):
    w = w / w.sum()
    dm = lambda M: M - M.mean(1, keepdims=True) - (w[:, None] * M).sum(0) + (w[:, None] * M.mean(1, keepdims=True)).sum()
    Dd = dm(D)
    return (w[:, None] * Dd * Y).sum() / (w[:, None] * Dd ** 2).sum()

def bacon(Y, t, tk, tl, w):
    did = lambda a, b, pre, post: (Y[a, post].mean() - Y[a, pre].mean()) - (Y[b, post].mean() - Y[b, pre].mean())
    pk, pl = t >= tk, t >= tl
    b = np.array([did(0, 2, ~pk, pk), did(1, 2, ~pl, pl), did(0, 1, ~pk & ~pl, pk & ~pl), did(1, 0, pk & ~pl, pl)])
    nk, nl, nu = w / w.sum(); Dk, Dl = pk.mean(), pl.mean()
    sh = lambda a, c: a / (a + c)
    s = np.array([(nk + nu) ** 2 * sh(nk, nu) * (1 - sh(nk, nu)) * Dk * (1 - Dk),
                  (nl + nu) ** 2 * sh(nl, nu) * (1 - sh(nl, nu)) * Dl * (1 - Dl),
                  ((nk + nl) * (1 - Dl)) ** 2 * sh(nk, nl) * (1 - sh(nk, nl)) * (Dk - Dl) / (1 - Dl) * (1 - Dk) / (1 - Dl),
                  ((nk + nl) * Dk) ** 2 * sh(nk, nl) * (1 - sh(nk, nl)) * Dl / Dk * (Dk - Dl) / Dk])
    return b, s / s.sum()

for label, eff in [("constant effect 2", lambda e: 2 + 0 * e), ("dynamic 1 + 0.5e", lambda e: 1 + .5 * e)]:
    for w in (np.array([1., 1, 1]), np.array([2., 1, 3])):
        Y, D, t = panel(10, 4, 7, eff)
        b, s = bacon(Y, t, 4, 7, w)
        att = (w[0] * eff(np.arange(7)).sum() + w[1] * eff(np.arange(4)).sum()) / (7 * w[0] + 4 * w[1])
        print(f"{label:18s} sizes {w.astype(int)}: 2x2s {b.round(2)} weights {s.round(3)} "
              f"sum {(s * b).sum():.3f} TWFE {twfe_weighted(Y, D, w):.3f} ATT {att:.3f}")

# Exercise 9: early effect = e (growing), late effect = 0.5
Y, D, t = panel(10, 4, 7, lambda e: e * 1.0, lambda e: 0.5 + 0 * e)
b, s = bacon(Y, t, 4, 7, np.ones(3))
print("late vs already-treated early:", round(b[3], 2))

Key takeaways

  • Staggered TWFE averages all 2×2 DiDs, with OLS weights that favour groups treated mid-panel.
  • Comparisons that use already-treated units as controls subtract their evolving effects; with dynamic effects TWFE is biased and can flip sign.
  • Report the adoption pattern and a decomposition, and use estimators that only compare with not-yet- or never-treated units.

Simulation Lab: The Goodman-Bacon Decomposition

Open full screen →

Staggered adoption as four weighted 2×2 DiDs, including the forbidden comparison with already-treated units.

2468246810periodmean outcome2.5032%1.7536%1.5014%0.0018%
early vs neverlate vs neverearly vs not-yet-treated latelate vs already-treated earlyTWFEATT
TWFE = Σ weight × 2×2
1.636
ATT (treated unit-periods)
2.227
weight on forbidden comparison
18.2%
bias
-0.591

Three groups: early adopters, late adopters and never-treated, with a common trend. The TWFE coefficient equals the weighted sum of four 2×2 DiDs (bar heights; bar widths are the weights). With effects that grow over time, the comparison that uses already-treated early adopters as controls is biased, and TWFE drifts away from the average effect on treated unit-periods.

Day 69Day 71