Matches treated unit-periods to controls with identical recent treatment histories, then applies a difference-in-differences estimator for TSCS data.
Input · what goes in
A long-format panel with unit ID, time ID, a binary treatment, an outcome, and time-varying covariates.
Show data format & exampleHide example
| unit | year | treat | outcome | gdp |
|---|---|---|---|---|
| A | 2001 | 0 | 12.4 | 3.1 |
| A | 2002 | 1 | 13.0 | 3.4 |
| B | 2001 | 0 | 9.8 | 2.2 |
| B | 2002 | 0 | 10.1 | 2.5 |
Pipeline · the recipe
↑ Click any step in the diagram to read its logic, code, assumptions & discussion.
Inspect treatment distribution
A pre-flight check — run this before trusting any estimate downstream.
Use DisplayTreatment() to visualize when democratization (dem) turns on across countries and years.
# Install: install.packages("PanelMatch")
library(PanelMatch)
DisplayTreatment(unit.id = "wbcode2", time.id = "year",
treatment = "dem", data = dem,
legend.position = "none", xlab = "year", ylab = "Country Code")
- No comments on this step yet — be the first.
Log in to comment on this step.
Build matched sets
The core estimate — where the causal quantity itself is computed.
Run PanelMatch() with a 4-period lag and propensity-score weighting to match treated to control histories.
PM.results <- PanelMatch(lag = 4, time.id = "year", unit.id = "wbcode2",
treatment = "dem", refinement.method = "ps.weight",
data = dem, match.missing = FALSE, listwise.delete = TRUE,
covs.formula = ~ I(lag(tradewb, 1:4)) + I(lag(y, 1:4)),
size.match = 5, qoi = "att", outcome.var = "y",
lead = 0:4, forbid.treatment.reversal = FALSE)
- No comments on this step yet — be the first.
Log in to comment on this step.
Check covariate balance
A pre-flight check — run this before trusting any estimate downstream.
Use get_covariate_balance() to confirm the matched sets balance the lagged covariates.
get_covariate_balance(PM.results$att, data = dem,
covariates = c("tradewb", "y"), plot = FALSE)
- No comments on this step yet — be the first.
Log in to comment on this step.
Estimate the ATT (DiD)
The core estimate — where the causal quantity itself is computed.
PanelEstimate() applies a difference-in-differences estimator with bootstrap standard errors.
PE.results <- PanelEstimate(sets = PM.results, data = dem)
- No comments on this step yet — be the first.
Log in to comment on this step.
Summarize and plot leads
Reporting — turn the numbers into a figure or table a reader can act on.
summary() and plot() report the dynamic ATT for each lead period with confidence intervals.
summary(PE.results)
plot(PE.results)
- No comments on this step yet — be the first.
Log in to comment on this step.
Output · what you get
Result figure rendered by StatsOtter from the package's documented example — unofficial community showcase; all credit to the original authors.
Result · the numbers
⚠️ Unofficial community showcase of PanelMatch (docs). Not affiliated with the authors — all credit to Kosuke Imai & coauthors; this summarizes public documentation.
What it does: PanelMatch implements the Imai-Kim-Wang matching framework for causal inference with time-series cross-sectional (panel) data and binary treatments. How it works: for each treated observation it builds a matched set of control units that share an identical treatment history over a user-specified number of lags. The matched set is then refined by Mahalanobis distance, propensity-score matching, or propensity-score weighting on time-varying covariates. Treatment effects are estimated with a difference-in-differences estimator that nets out unit and time effects, yielding short- and long-term ATTs with block-bootstrap standard errors. Assumptions: a parallel-trends/limited-carryover assumption conditional on treatment history and covariates, plus no unobserved time-varying confounding. The package also provides covariate-balance diagnostics and visualizations of treatment-variation and matched sets so users can assess match quality before estimation.
What you get — Short- and long-term ATTs (point estimates at multiple lead periods) with bootstrapped confidence intervals, plus covariate-balance and matched-set diagnostics.
Example output
Weighted Difference-in-Differences with Propensity Score
Matches created with 4 lags
Standard errors computed with 1000 Weighted bootstrap samples
Estimate of Average Treatment Effect on the Treated (ATT) by Period:
estimate std.error 2.5% 97.5%
t+0 0.2475 0.633 -0.9410 1.554
t+1 -0.7800 1.144 -3.0426 1.430
t+2 -1.4290 1.700 -4.7917 1.832
t+3 -1.7770 2.187 -6.0908 2.448
t+4 -1.3450 2.567 -6.4096 3.715

Discussion (0)
Log in to join the discussion.