σ StatsDoge Causal inference workflows
5
Workflow·5 steps·branched

An observational ATE you can defend (balance → estimate → sensitivity)

Summary by StatsDoge

My checklist for an observational effect: match, prove balance with cobalt, estimate on the matched sample, then quantify hidden-confounding risk with sensemakr.

1

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
2

Pipeline · the recipe ⑂ has parallel branches

↑ Click any step in the diagram to read its logic, code, assumptions & discussion.

1
Data prep

Treatment, covariates, outcome

Data preparation — shapes the raw inputs into what the estimator expects.

What happens here

Assemble the design matrix; keep the outcome sealed until matching is done.

Reads from the input data Feeds into the final output
Key code
data("lalonde", package = "MatchIt")
Discussion on this step (0)
  • No comments on this step yet — be the first.
2
Data prep

matchit() — nearest-neighbour matching

Data preparation — shapes the raw inputs into what the estimator expects.

What happens here

Match on the propensity score — the outcome-blind design stage.

Reads from the input data Feeds into the final output
Key code
m <- matchit(treat ~ age + educ + race + re74 + re75, lalonde, method="nearest")

Reference / docs ↗

Discussion on this step (0)
  • No comments on this step yet — be the first.
3
Diagnostic / pre-tests

bal.tab() / love.plot() — cobalt

A pre-flight check — run this before trusting any estimate downstream.

What happens here

Prove the matching worked: SMDs adjusted vs unadjusted, plus the Love plot.

Reads from the input data Feeds into the final output
Key code
bal.tab(m, un = TRUE); love.plot(m, thresholds = c(m = .1))

Reference / docs ↗

Discussion on this step (0)
  • No comments on this step yet — be the first.
4
Estimation

Estimate the ATT on matched data

The core estimate — where the causal quantity itself is computed.

What happens here

Outcome model on match.data() with cluster-robust SEs.

Formula
\hat au_{\mathrm{ATT}}=\mathbb{E}\!\left[\,Y(1)-Y(0)\mid W=1\, ight]
Reads from the input data Feeds into the final output
Key code
fit <- lm(re78 ~ treat, data = match.data(m), weights = weights)
Discussion on this step (0)
  • No comments on this step yet — be the first.
5
Reporting

sensemakr() — robustness value + contours

Reporting — turn the numbers into a figure or table a reader can act on.

What happens here

Report the robustness value + contour plots — how wrong could unconfoundedness be?

Reads from the input data Feeds into the final output
Key code
s <- sensemakr(fit, treatment="treat", benchmark_covariates="re74", kd=1:3)
plot(s)

Reference / docs ↗

Discussion on this step (0)
  • No comments on this step yet — be the first.
3

Output · what you get 2 figures

A Love plot of |standardized mean difference| per covariate, adjusted vs unadjusted, against the 0.1 threshold.
Fig 1A Love plot of |standardized mean difference| per covariate, adjusted vs unadjusted, against the 0.1 threshold.
Sensitivity contour: how strong a confounder must be (vs observed covariates) to drive the estimate to zero.
Fig 2Sensitivity contour: how strong a confounder must be (vs observed covariates) to drive the estimate to zero.

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)

  • No comments yet — start the conversation.