This vignette mirrors the Python experimental.ipynb test
notebook, demonstrating the design objects and experimental estimators
in CausalModel.
CausalModel provides two randomization designs: completely randomized design (CRD) and Bernoulli randomization.
Rerandomization to ensure covariate balance (Morgan & Rubin, 2012). The design draws assignments until Mahalanobis balance falls below a threshold:
Generate experimental data with a known treatment effect \(\tau = 10\):
The default estimator under a CRD:
Weighted average of within-stratum difference-in-means. Strata are defined by the user — here we use a simple median split on the first covariate:
strata <- as.integer(data$X[, 1] > median(data$X[, 1]))
est_via_strata(exp_obj, strata = strata)
#> Causal Model Estimation Result
#> ------------------------------
#> ATE: 11.088742
#> SE: 0.030043
#> z: 369.0955
#> p-value: 0.0000
#> 95% CI: [11.029859, 11.147626]With random strata (less informative):
Adjusts for covariates via \(Y \sim 1 + Z + X + Z \cdot X\) with HC0 robust standard errors. Achieves efficiency gains when covariates are predictive:
Tests the sharp null hypothesis of zero individual treatment effects by comparing the observed test statistic to its randomization distribution:
pval <- test_via_fisher(exp_obj, n_draws = 1000)
cat("Fisher p-value:", pval, "\n")
#> Fisher p-value: 0With \(\tau = 10\), the Fisher test rejects decisively (p-value \(\approx 0\)).
Under a CRD with predictive covariates, ANCOVA should achieve substantially smaller standard errors than DM while both remain unbiased:
results <- data.frame(
Estimator = c("DM", "Strata (median split)", "ANCOVA"),
ATE = NA, SE = NA
)
r <- est_via_dm(exp_obj)
results[1, c("ATE", "SE")] <- c(r$ate, r$se)
r <- est_via_strata(exp_obj, strata = strata)
results[2, c("ATE", "SE")] <- c(r$ate, r$se)
r <- est_via_ancova(exp_obj)
results[3, c("ATE", "SE")] <- c(r$ate, r$se)
knitr::kable(results, digits = 4,
caption = "Estimator comparison (N=10000, tau=10)")| Estimator | ATE | SE |
|---|---|---|
| DM | 11.4837 | 0.0313 |
| Strata (median split) | 11.0887 | 0.0300 |
| ANCOVA | 10.0298 | 0.0234 |
crd(),
bernoulli()) generate treatment assignments via
draw(). CRD with balance = TRUE ensures
covariate balance through rerandomization.