Interactive Regression Model DML on OTIS data (ATE, ATTE, ATC).
Source:R/otis_causal.R
morie_otis_irm_dml.RdComputes the doubly-robust ATE / ATTE / ATC via the Chernozhukov et
al. (2018) IRM score with cross-fitted nuisance models. Delegates
to DoubleML's DoubleMLIRM when the package (with
mlr3 + mlr3learners) is installed; otherwise falls back
to a self-contained cross-fit using .otis_logit_fit for the
propensity and OLS for the per-arm outcome regressions (mirroring
the python module's ml_outcome="ols", ml_propensity="logit"
branch).
Usage
morie_otis_irm_dml(
df,
treatment,
outcome,
covariates,
cluster_cols = NULL,
n_folds = 3L,
seed = 123L,
eps = 0.02,
match_first = FALSE,
match_caliper_sd = 0.2
)Arguments
- df
A data frame.
- treatment
Binary treatment column name.
- outcome
Outcome column name.
- covariates
Character vector of covariate names.
- cluster_cols
NULL, a single column name, or a length-2 character vector for two-way clustering.- n_folds
Number of cross-fitting folds (default 3).
- seed
Integer seed (default 123).
- eps
Propensity clip bound (default 0.02).
- match_first
Logical; if
TRUE, pre-match the sample with 1:1 NN PSM before fitting (default FALSE).- match_caliper_sd
Caliper width (default 0.2 * SD of logit-e).
Value
Named list with ate, ate_se, ate_pval,
ate_ci95, atte, atte_se, atte_pval,
atte_ci95, atc, atc_se, atc_pval,
atc_ci95, n, n_treated, p_treat,
se_kind.
Details
Cluster-robust SE: pass cluster_cols as the name (one-way)
or character vector (multi-way Cameron-Gelbach-Miller 2011, up to
2-way). cluster_cols = NULL gives the heteroskedasticity-
consistent SE.
Optional match_first = TRUE runs 1:1 nearest-neighbour
propensity-score matching on logit(e(X)) with caliper
match_caliper_sd * SD(logit(e)) first, then fits IRM-DML on
the matched subset. Mirrors the MatchIt-then-DML pipeline of
OTIS-RC/notez1a.qmd.
References
Chernozhukov, V. et al. (2018). Econometrics Journal 21(1), C1-C68. Cameron, A. C., Gelbach, J. B., & Miller, D. L. (2011). JBES 29(2), 238-249.
Examples
set.seed(1)
n <- 300L
x <- rnorm(n)
d <- rbinom(n, 1, plogis(0.4 * x))
y <- 0.5 * d + x + rnorm(n)
df <- data.frame(d = d, y = y, x = x, id = sample.int(50, n,
replace = TRUE))
morie_otis_irm_dml(df, treatment = "d", outcome = "y",
covariates = "x", n_folds = 3L)
#> $ate
#> [1] 0.4914376
#>
#> $ate_se
#> [1] 0.1404857
#>
#> $ate_pval
#> [1] 0.0004685302
#>
#> $ate_ci95
#> [1] 0.2160855 0.7667897
#>
#> $atte
#> [1] 0.5236131
#>
#> $atte_se
#> [1] 0.1357441
#>
#> $atte_pval
#> [1] 0.0001146204
#>
#> $atte_ci95
#> [1] 0.2575547 0.7896715
#>
#> $atc
#> [1] 0.4617371
#>
#> $atc_se
#> [1] 0.1638747
#>
#> $atc_pval
#> [1] 0.00483805
#>
#> $atc_ci95
#> [1] 0.1405428 0.7829315
#>
#> $n
#> [1] 300
#>
#> $n_treated
#> [1] 144
#>
#> $p_treat
#> [1] 0.48
#>
#> $se_kind
#> [1] "iid"
#>
#> $ml_outcome
#> [1] "ols"
#>
#> $ml_propensity
#> [1] "logit"
#>