Conditional Average Treatment Effect estimation with cross-fitting.
Usage
cate(
response.model,
treatment.model,
cate.model = ~1,
calibration.model = NULL,
missing.model = NULL,
data,
contrast,
nfolds = 1,
rep = 1,
id = NULL,
silent = FALSE,
stratify = FALSE,
mc.cores = NULL,
var.type = "IC",
second.order = TRUE,
response_model = deprecated,
cate_model = deprecated,
propensity_model = deprecated,
propensity.model = deprecated,
treatment = deprecated,
...
)Arguments
- response.model
formula or learner object (formula => learner_glm)
- treatment.model
formula or learner object (formula => learner_glm)
- cate.model
formula specifying regression design for conditional average treatment effects
- calibration.model
linear calibration model. Specify covariates in addition to predicted potential outcomes to include in the calibration.
- missing.model
formula or learner object (formula => learner_glm(family = binomial); default
NULL. Model for the missingness mechanism \(P(R=1 \mid X, A)\). Required when the outcome inresponse.modelcontains NAs. If the formula LHS is omitted, the observation indicator is used automatically. Whenstratify = TRUEthe missing model is fit separately per treatment arm. When supplied, the AIPW score is inverse-probability-of-observation weighted and (ifsecond.order = TRUE) an additional second-order term is added to the influence function.- data
data.frame
- contrast
treatment contrast (default 1 vs 0)
- nfolds
number of folds (positive integer), or a pre-specified list of fold indices where each element is an integer vector of observation indices forming a partition of
1:nrow(data).- rep
number of replications of cross-fitting procedure by averaging estimates and influence functions from each replication
- id
(integer or character) optional subject id vector of length
nrow(data). Theidcan also be specified as part of thecate.modelargument with a formula syntax:~ 1 + cluster(id).- silent
suppress all messages and progressbars
- stratify
if TRUE the response.model and missing.model (if provided) will be stratified by treatment
- mc.cores
(optional) number of cores. parallel::mcmapply used instead of future
- var.type
when equal to "IC" the asymptotic variance is derived from the influence function. Otherwise, based on expressions in Bannick et al. (2025) valid under different covariate-adaptive randomization schemes (only available for ATE and when
calibration.modelis also specified)- second.order
add seconder order term to IF to handle misspecification of outcome models
- response_model
Deprecated. Use response.model instead.
- cate_model
Deprecated. Use cate.model instead.
- propensity_model
Deprecated. Use treatment.model instead.
- propensity.model
Deprecated. Use treatment.model instead.
- treatment
Deprecated. Use cate.model instead.
- ...
additional arguments to future.apply::future_mapply
Details
We have observed data \((Y,A,W)\) where \(Y\) is the response variable, \(A\) the binary treatment, and \(W\) covariates. We further let \(V\) be a subset of the covariates. Define the conditional potential mean outcome $$\psi_{a}(P)(V) = E_{P}[E_{P}(Y\mid A=a, W)|V]$$ and let \(m(V; \beta)\) denote a parametric working model, then the target parameter is the mean-squared error $$\beta(P) = \operatorname{argmin}_{\beta} E_{P}[\{\Psi_{1}(P)(V)-\Psi_{0}(P)(V)\} - m(V; \beta)]^{2}$$
Missing data is handled under a Missing At Random assumption (MAR). Let \(R\) denote the indicator for data not being missing, \(R\perp Y|W,A\). The nuisance models are \(Q(w,a) = E(Y|W=w, A=a)\), \(g_a(w) = P(A=a|W=w)\), and \(\rho(w, a) = P(R=1|W=w, A=a)\). For the expected potential outcome \(E[Y(a)]\), the AIPW estimator then takes the form $$\frac{1}{n}\sum_{i=1}^n R_i I(A_i=a) / \{g_a(W_i) \rho(W_i, a)\} (Y_i - Q(W_i,a)) + Q(W_i, a)$$.
References
Mark J. van der Laan (2006) Statistical Inference for Variable Importance, The International Journal of Biostatistics.
Bannick, Shao & Liu et al. (2025) A General Form of Covariate Adjustment in Clinical Trials under Covariate-Adaptive Randomization, Biometrika.
Examples
sim1 <- function(n=1000, ...) {
w1 <- rnorm(n)
w2 <- rnorm(n)
a <- rbinom(n, 1, plogis(-1 + w1))
y <- cos(w1) + w2*a + 0.2*w2^2 + a + rnorm(n)
data.frame(y, a, w1, w2)
}
d <- sim1(5000)
## ATE
cate(cate.model=~1,
response.model=y~a*(w1+w2),
treatment.model=a~w1+w2,
data=d)
#> Estimate Std.Err 2.5% 97.5% P-value
#> E[y(1)] 1.8047 0.04831 1.7100 1.8994 2.099e-305
#> E[y(0)] 0.8308 0.01984 0.7919 0.8697 0.000e+00
#> ───────────
#> (Intercept) 0.9740 0.05337 0.8694 1.0786 2.054e-74
## CATE
cate(cate.model=~1+w2,
response.model=y~a*(w1+w2),
treatment.model=a~w1+w2,
data=d)
#> Estimate Std.Err 2.5% 97.5% P-value
#> E[y(1)] 1.8047 0.04831 1.7100 1.8994 2.099e-305
#> E[y(0)] 0.8308 0.01984 0.7919 0.8697 0.000e+00
#> ───────────
#> (Intercept) 0.9502 0.05280 0.8467 1.0536 2.093e-72
#> w2 1.0377 0.04756 0.9445 1.1309 1.586e-105
if (FALSE) { # \dontrun{
# superlearner
mod1 <- list(
glm = learner_glm(y~w1+w2),
gam = learner_gam(y~s(w1) + s(w2))
)
s1 <- learner_sl(mod1, nfolds=5)
cate(cate.model=~1,
response.model=s1,
treatment.model=learner_glm(a~w1+w2, family=binomial),
data=d,
stratify=TRUE)
} # }
## Missing data
sim_missing_cate <- function(n = 5000, seed = 1) {
set.seed(seed)
w1 <- rnorm(n)
w2 <- rnorm(n)
a <- rbinom(n, 1, 0.5) # randomized trial
y_full <- 1 + a + w1 + 0.5 * w2 + rnorm(n)
pR <- plogis(0.5 - 1 * w2 * a + 0.5 * a)
R <- rbinom(n, 1, pR)
y <- ifelse(R == 1, y_full, NA_real_)
data.frame(y0 = y_full, y = y, a = a, w1 = w1, w2 = w2)
}
d <- sim_missing_cate()
# ignoring missing data (complete-case analysis)
cate(cate.model = ~1,
response.model = y ~ a * w2, # wrong outcome model
treatment.model = a ~ 1,
data = na.omit(d), nfolds = 1L)
#> Estimate Std.Err 2.5% 97.5% P-value
#> E[y(1)] 1.9271 0.03483 1.8588 1.9953 0.000e+00
#> E[y(0)] 0.9076 0.03607 0.8370 0.9783 9.391e-140
#> ───────────
#> (Intercept) 1.0194 0.04879 0.9238 1.1150 6.127e-97
# MAR analysis
fit <- cate(cate.model = ~1,
response.model = y ~ a * w2,
treatment.model = a ~ 1,
missing.model = ~ a * (w1 + w2),
data = d, nfolds = 1L)
fit
#> Estimate Std.Err 2.5% 97.5% P-value
#> E[y(1)] 1.9807 0.03372 1.9146 2.047 0.000e+00
#> E[y(0)] 0.9725 0.03237 0.9091 1.036 2.485e-198
#> ───────────
#> (Intercept) 1.0082 0.04573 0.9186 1.098 1.033e-107
