Modern Difference-in-Differences Estimators

Simon Mueller

2026-10-09

Introduction

Traditional two-way fixed effects (TWFE) estimation of event studies can produce biased estimates when treatment effects are heterogeneous across cohorts and time. The EventStudy package supports five panel event study estimators:

Method Package Key Property
TWFE Base R Standard two-way fixed effects
Sun-Abraham fixest Interaction-weighted estimator
Callaway-Sant’Anna did Group-time ATTs with doubly-robust estimation
de Chaisemartin-D’Haultfoeuille DIDmultiplegt Fuzzy DiD, robust to heterogeneous effects
Borusyak-Jaravel-Spiess didimputation Imputation-based estimator

Data Setup

All estimators use the PanelEventStudyTask:

library(EventStudy)
library(tibble)

# Create panel data
panel_data <- tibble(
  unit_id = rep(1:100, each = 20),
  time_id = rep(1:20, times = 100),
  # Units 1-50 are first treated in period 11; units 51-100 are never treated.
  treatment_time = ifelse(unit_id <= 50, 11, NA_integer_),
  treatment = ifelse(unit_id <= 50 & time_id >= 11, 1, 0),
  outcome = rnorm(2000) + 2 * treatment  # true effect = 2
)

task <- PanelEventStudyTask$new(
  panel_data = panel_data,
  unit_id = "unit_id",
  time_id = "time_id",
  outcome = "outcome",
  treatment = "treatment",
  treatment_time = "treatment_time"
)

TWFE (Default)

The default "static_twfe" method estimates a single average treatment effect on the treated (ATT) and has no per-period dynamic coefficients, so it is printed as a table rather than plotted (use "dynamic_twfe" or "sun_abraham" below for an event-time plot).

result <- estimate_panel_event_study(task, method = "static_twfe", leads = 5, lags = 5)
result$results$coefficients

Sun-Abraham

The interaction-weighted estimator of Sun and Abraham (2021) avoids negative weighting problems in TWFE by computing cohort-specific estimates. Requires fixest.

result <- estimate_panel_event_study(
  task,
  method = "sun_abraham",
  leads = 5,
  lags = 5
)
plot_panel_event_study(result)

Callaway-Sant’Anna

The doubly-robust estimator of Callaway and Sant’Anna (2021) estimates group-time average treatment effects and aggregates them into dynamic effects. Requires did.

result <- estimate_panel_event_study(
  task,
  method = "callaway_santanna",
  leads = 5,
  lags = 5
)
plot_panel_event_study(result)

Key features: - Doubly-robust (consistent if either outcome or propensity score model is correct) - Handles staggered treatment adoption - Provides group-time specific estimates

de Chaisemartin-D’Haultfoeuille

The estimator of de Chaisemartin and D’Haultfoeuille (2020) is robust to heterogeneous treatment effects and can handle fuzzy designs. Requires DIDmultiplegt.

result <- estimate_panel_event_study(
  task,
  method = "dechaisemartin_dhaultfoeuille",
  leads = 5,
  lags = 5
)
plot_panel_event_study(result)

Borusyak-Jaravel-Spiess

The imputation estimator of Borusyak, Jaravel, and Spiess (2024) imputes untreated potential outcomes and computes treatment effects as the difference. Requires didimputation.

result <- estimate_panel_event_study(
  task,
  method = "borusyak_jaravel_spiess",
  leads = 5,
  lags = 5
)
plot_panel_event_study(result)

Key features: - Efficient imputation-based approach - Handles staggered treatment timing - Provides horizon-specific estimates

Comparing Estimators

All estimators produce the same output format (relative_time, estimate, std.error, statistic, p.value), making it easy to compare:

methods <- c("static_twfe", "sun_abraham", "callaway_santanna")

results <- lapply(methods, function(m) {
  tryCatch(
    estimate_panel_event_study(task, method = m, leads = 5, lags = 5),
    error = function(e) NULL
  )
})
names(results) <- methods

When to Use Which?

References