1 What Problem Does This Tool Solve?
When treatment is staggered—different units adopt treatment at different times—the two-way fixed effects (TWFE) DiD estimator does not estimate a simple average treatment effect. Goodman-Bacon [2021] shows that the TWFE estimator is a weighted average of all possible2x2 DiD comparisons in the data, and that some of those comparisons use already-treated units as controls for later-treated units. These "contaminated comparisons" have negative weights when treatment effects are heterogeneous, producing a TWFE estimate that can beseverely biased—even pointing in the wrong direction.
The bacondecomp package, written by Goodman-Bacon et al. [2021], implements the Goodman-Bacon decomposition in R. It decomposes the TWFE coefficient into its con-stituent 2x2 estimates and their associated weights, allowing the researcher to:
- See how many 2x2 comparisons go into the TWFE estimate.
- Identify which comparisons receive large negative weights.
- Assess whether the TWFE estimate is likely to be biased.
- Decide whether a heterogeneity-robust estimator is needed.
2 Installation and Setup
# Install from CRAN
install.packages("bacondecomp")
library (bacondecomp)
# For the plot, also load ggplot2
library(ggplot2)
3 The Goodman-Bacon Decomposition: A Brief Re-fresher
Consider a balanced panel with N units and T periods.
Suppose units are divided into
groups by timing: an early group treated at time gₑ and a late group treated at time gₗ > gₑ,
plus a never-treated group.
Goodman-Bacon [2021] shows:
where δ̂ₖₗ are the 2x2 DiD estimates for each pair of timing groups (k, l), and ŝₖₗ are weights proportional to the variance of the treatment indicator within each 2x2 comparison. The three types of 2x2 comparisons are:
- Timing vs. never-treated: Early or late-treated units compared to never-treated
- units. These are the "clean" comparisons.
- Earlier vs. later: Early-treated units compared to later-treated units (using late-
- treated as control).
- This is the problematic comparison: the control group is not yet
- treated when the DiD is computed, but it will be treated later.
- Later vs. earlier (reverse): Later-treated units compared to already-treated early-treated units. These can receive negative weights.
4 Simulating a Staggered Panel
set.seed(2026)
n_units <- 50
n_periods <- 12
# Assign treatment timing: 1/3 never, 1/3 early (period 4), 1/3 late (period 8)
unit_ids <- 1:n_units
treat_time <- c(rep (NA, 17), rep (4, 17), rep (8, 16))
df <- expand.grid(unit = unit_ids, period = 1:n_periods)
df <- merge (df, data.frame (unit = unit_ids, treat_year = treat_time))
# Create treatment indicator
df$treated <- as.integer(!is.na(df$treat_year) & df$period >= df$treat_year)
# Generate potential outcomes with heterogeneous TE
# Early group: TE = 2; Late group: TE = 0.5
df$te <- ifelse (df$treated == 1 & !is.na(df$treat_year) & df$treat_year == 4, 2,
ifelse (df$treated == 1 & !is.na(df$treat_year) & df$treat_year == 8, 0.5, 0))
df$y <- 5 + 0.3 * df$period + rnorm(nrow (df), 0, 0.5) + df$te
# Replace NA treat_year with 0 for bacon (convention)
df$treat_year_bacon <- ifelse (is.na(df$treat_year), 0, df$treat_year)
5 Running the Decomposition
# Run the Bacon decomposition
bacon_out <- bacon (y ~ treated, data = df, id_var = "unit", time_var = "period")
# View the decomposition table
print(bacon_out)
# Compute the TWFE weighted average manually
twfe_manual <- sum (bacon_out$weight * bacon_out$estimate)
cat ("Manual TWFE:", round (twfe_manual, 4), "\n")
6 Visualising the Decomposition
# Bacon decomposition plot
ggplot(bacon_out, aes (x = weight, y = estimate, shape = type, colour = type)) +
geom_point (size = 3) +
geom_hline(yintercept = 0, linetype = "dashed") +
labs (title = "Goodman-Bacon Decomposition", x = "Weight", y = "2x2 DiD Estimate") +
theme_bw()
7 Interpreting the Output
- Early vs never-treated: 2x2 estimate near 2 (the early group's true effect).
- Late vs never-treated: 2x2 estimate near 0.5 (the late group's true effect).
- Early vs later-treated (later as control): The estimate will be near 2 here as well.
- Later vs earlier (already-treated as control): The early group serves as control for the late group. The estimated 2x2 effect will be near 0.5 - 2 = -1.5. with negative or small weight. This is the contaminated comparison.
The TWFE estimate blends these together. If the contaminated comparisons have large weight, the TWFE estimate can be far from any unit’s actual treatment effect.
8 Key Options and Pitfalls
- Treatment variable must be binary (0/1). bacon() requires a binary treatment indicator, not a continuous dose.
- Never-treated group coded as 0 (not NA). Units that are never treated should have treat year = 0 (or a period beyond the sample), not NA, in the treatment timing variable passed to bacon().
- Balanced panel preferred. The decomposition is designed for balanced panels. With unbalanced panels, use with caution and check that the decomposition weights sum to approximately 1.
- Decomposition vs. alternative estimators: The bacondecomp package is a diagnostic, not a solution. If contaminated comparisons have large negative weight, switch to a heterogeneity-robust estimator such as Callaway–Sant’Anna (did package) or deChaisemartin–D’Haultfoeuille (didmultiplegt).
9 Comparison to Alternatives
10 Conclusion
The bacondecomp package makes the Goodman-Bacon decomposition immediately accessible in R. Running bacon() before estimating any staggered DiD should be standard practice: it takes seconds, and it tells you whether your TWFE estimate is a reliable summary of treatment effects or a contaminated amalgam of clean and dirty comparisons. When contaminated comparisons receive substantial weight, the next step is to switch to a heterogeneity-robust estimator.
References
- Callaway, B. and Sant'Anna, P. H. C. Difference-in-differences with multiple time periods.
- Journal of Econometrics, 225(2):200-230, 2021.
- de Chaisemartin, C. and D'Haultfœuille, X. Two-way fixed effects estimators with hetero-
- geneous treatment effects. American Economic Review, 110(9):2964-2996, 2020.
- Goodman-Bacon, A. Difference-in-differences with variation in treatment timing. Journal
- of Econometrics, 225(2):254-277, 2021.
- Goodman-Bacon, A., Goldring, T., and Nichols, A. bacondecomp: Goodman-Bacon decom-
- position. R package version 0.1.1, 2021.
- Sun, L. and Abraham, S. Estimating dynamic treatment effects in event studies with het-erogeneous treatment effects.Journal of Econometrics, 225(2):175-199, 2021.