My checklist for an observational effect: match, prove balance with cobalt, estimate on the matched sample, then quantify hidden-confounding risk with sensemakr.
Input · what goes in
A binary treatment, the covariates to adjust for, and an outcome (e.g. the Lalonde job-training data).
Show data format & exampleHide example
Format — one row per unit: treatment W ∈ {0,1}, covariates X, outcome Y.
W age educ race re74 re78
1 37 11 black 0 9930
0 30 12 white 4100 4400
Pipeline · the recipe ⑂ has parallel branches
↑ Click any step in the diagram to read its logic, code, assumptions & discussion.
Treatment, covariates, outcome
Data preparation — shapes the raw inputs into what the estimator expects.
Assemble the design matrix; keep the outcome sealed until matching is done.
data("lalonde", package = "MatchIt")
- No comments on this step yet — be the first.
Log in to comment on this step.
matchit() — nearest-neighbour matching
Data preparation — shapes the raw inputs into what the estimator expects.
Match on the propensity score — the outcome-blind design stage.
m <- matchit(treat ~ age + educ + race + re74 + re75, lalonde, method="nearest")
- No comments on this step yet — be the first.
Log in to comment on this step.
bal.tab() / love.plot() — cobalt
A pre-flight check — run this before trusting any estimate downstream.
Prove the matching worked: SMDs adjusted vs unadjusted, plus the Love plot.
bal.tab(m, un = TRUE); love.plot(m, thresholds = c(m = .1))
- No comments on this step yet — be the first.
Log in to comment on this step.
Estimate the ATT on matched data
The core estimate — where the causal quantity itself is computed.
Outcome model on match.data() with cluster-robust SEs.
fit <- lm(re78 ~ treat, data = match.data(m), weights = weights)
- No comments on this step yet — be the first.
Log in to comment on this step.
sensemakr() — robustness value + contours
Reporting — turn the numbers into a figure or table a reader can act on.
Report the robustness value + contour plots — how wrong could unconfoundedness be?
s <- sensemakr(fit, treatment="treat", benchmark_covariates="re74", kd=1:3)
plot(s)
- No comments on this step yet — be the first.
Log in to comment on this step.
Output · what you get 2 figures
Figures reproduced from the package's official documentation — unofficial community showcase; all credit to the original authors.
Personal recipe — figures are from each package's public docs; this is my own composition, not affiliated with the package authors.
Selection-on-observables is an assumption, not a fact. This is the pipeline I actually run so the estimate survives review: design first (matching, outcome-blind), show balance, estimate, then state how strong an unobserved confounder would have to be to overturn it.
Discussion (0)
Log in to join the discussion.