Tools for building stacked difference-in-differences samples in staggered-adoption settings. The package labels valid treated and control candidates, performs cross-sectional matching, expands matched units into event-time stacks, and returns diagnostics for balance assessment and visualization.
Flexible matching for stacked difference-in-differences panels with staggered or repeated treatment events.
library(flexMatch)
data("flexmatch_example")
d <- flexmatch_example[flexmatch_example$unit_id <= 100, ]
r <- flexmatch(d, "unit_id", "year", "event",
k_pre = 1, k_post = 1, k_freeze = 1, match_vars = c("size", "leverage"),
method = "nearest", assess_quality = TRUE, plot_events = TRUE, verbose = FALSE)
r$quality_stats$balance_table
print(r$event_plot)
vignette("introduction", package = "flexMatch")
The three stages are label_candidates(), match_candidates() and expand_matched_stacks(). Matching is exact on the event cohort period, with optional exact covariates and additional MatchIt options. Each matched set has a cohort_id; each unit within the set has a stack_id, including reused controls. assess_match_quality() produces numeric and categorical balance plots.
The example data are entirely synthetic and contain 65,000 unit-year observations. The HTML vignette shows a small runnable example. Use help(package = "flexMatch") or ?flexmatch for the R help index and reference pages.
The illustrative fit_event_study() uses matching weights, unit-within-set fixed effects, matched-set-specific calendar-period effects, and original-unit clustering. Sample screening and balance do not prove parallel trends or identify a causal effect. Repeated events require a justified cooldown assumption. Retaining full histories with include_all_years = TRUE also retains observations outside the screened window.
Time distances refer to the ordered periods observed in the input. Entirely missing calendar periods cannot be inferred. control_type = "all" and "nt" currently select the same clean-window pool.