Skip to contents

Computes 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"
#>