rmorie’s quasi-experimental stack
is fully native: no did, fixest,
did2s, didimputation, rdrobust,
AER, WeightIt, or CBPS at
runtime. Each estimator is cross-validated against its reference package
in tests/ and the canonical replication suite
(tests/testthat/test-quasiex-replication.R) reproduces the
published estimates on the bundled real datasets (LaLonde, Basque
Country, Lee 2008 incumbency, CigarettesSW).
morie_did() inspects the treatment-timing structure:
with a single adoption cohort it runs the native TWFE estimator; with
staggered adoption it warns that a naive TWFE would be contaminated by
forbidden comparisons (Goodman-Bacon 2021) and switches to the
Callaway-Sant’Anna group-time estimator.
df <- expand.grid(id = 1:60, t = 1:8)
df$g <- ifelse(df$id <= 20, 4L, ifelse(df$id <= 40, 6L, NA))
df$y <- rnorm(nrow(df), sd = 0.5) +
ifelse(!is.na(df$g) & df$t >= df$g, 2, 0)
fit <- suppressWarnings(morie_did(df, "y", "id", "t", "g",
n_bootstrap = 49L))
fit
#> Difference-in-differences -- Callaway-Sant'Anna (2021) group-time ATT, overall (post cells)
#> ATT: 2.1464 (SE 0.0647) 95% CI [2.0195, 2.2732] p = 3.51e-241
#> Units: 60 Periods: 8The modern estimators are available directly when you want a specific
one: morie_did_sun_abraham() (interaction-weighted event
study), morie_did_borusyak() (imputation), and
morie_did_did2s() (Gardner two-stage).
es <- morie_did_sun_abraham(df, "y", "id", "t", "g",
leads = 2L, lags = 2L)
es
#> rel_time estimate std.error conf.low conf.high n
#> 1 -2 0.3438788 0.1686772 0.0132775 0.6744801 2
#> 2 0 2.2578746 0.1372652 1.9888397 2.5269095 2
#> 3 1 2.1475388 0.1516355 1.8503386 2.4447390 2
#> 4 2 2.0387359 0.1584486 1.7281822 2.3492895 2morie_iv_2sls() refuses to report a 2SLS point estimate
when the first-stage F is below the Staiger-Stock threshold of 10 and
returns the identification-robust Anderson-Rubin confidence set
instead.
n <- 300
z <- rnorm(n); u <- rnorm(n)
d <- 1.2 * z + 0.5 * u + rnorm(n)
y <- 2 * d + u + rnorm(n)
morie_iv_2sls(data.frame(y, d, z), "y", "d", "z")
#> Two-stage least squares -- 2SLS (native k-class, HC1) with Staiger-Stock gate
#> Estimate: 1.9209 (SE 0.0692) 95% CI [1.7846, 2.0571]
#> First-stage F = 312.93 (Stock-Yogo 10% crit = 16.38)morie_rdd() returns the bias-corrected estimate together
with the McCrary manipulation check and placebo-cutoff estimates – the
robustness steps applied papers routinely forget.
The morie_weight_* family produces a
morie_weight object the rest of the package composes with:
logistic scores, entropy balancing, CBPS, overlap weights,
stabilization, trimming, a native SuperLearner stack, and balance
diagnostics.
dw <- data.frame(t = rbinom(300, 1, 0.4),
x1 = rnorm(300), x2 = rnorm(300))
w <- morie_weight_ps(dw, "t", c("x1", "x2"), estimand = "ATT")
w
#> morie_weight: logistic propensity (estimand ATT)
#> n = 300 ESS = 280.6 weight range [0.530, 1.000]
head(morie_weight_diagnostic(w, dw, "t", c("x1", "x2")))
#> covariate mean_treated mean_control smd abs_smd variance_ratio
#> 1 x1 -0.06944165 -0.06866672 -0.0008164644 0.0008164644 1.0499323
#> 2 x2 -0.13495195 -0.13655584 0.0015225926 0.0015225926 0.8981806
#> ks_stat ks_p_value
#> 1 0.08054711 0.7526660
#> 2 0.07408815 0.8357571The composition test
(tests/testthat/test-composition-pipeline.R) chains DAG
construction, backdoor identification, matching, weighting, estimation,
refutation, and the MRM publication table on the bundled LaLonde data –
one class system across every module.