`vignettes/intro_txshift.Rmd`

`intro_txshift.Rmd`

Stochastic treatment regimes present a relatively simple manner in which to assess the effects of continuous treatments by way of parameters that examine the effects induced by the counterfactual shifting of the observed values of a treatment of interest. Here, we present an implementation of a new algorithm for computing targeted minimum loss-based estimates of treatment shift parameters defined based on a shifting function \(d(A,W)\). For a technical presentation of the algorithm, the interested reader is invited to consult Díaz and van der Laan (2018). For additional background on Targeted Learning and previous work on stochastic treatment regimes, please consider consulting van der Laan and Rose (2011), van der Laan and Rose (2018), and Díaz and van der Laan (2012).

To start, let’s load the packages we’ll use and set a seed for simulation:

`library(tidyverse)`

`## ── Attaching packages ────────────────────────────────── tidyverse 1.2.1 ──`

```
## ✔ ggplot2 3.2.0 ✔ purrr 0.3.2
## ✔ tibble 2.1.3 ✔ dplyr 0.8.2
## ✔ tidyr 0.8.3 ✔ stringr 1.4.0
## ✔ readr 1.3.1 ✔ forcats 0.4.0
```

```
## ── Conflicts ───────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
```

`library(data.table)`

```
##
## Attaching package: 'data.table'
```

```
## The following objects are masked from 'package:dplyr':
##
## between, first, last
```

```
## The following object is masked from 'package:purrr':
##
## transpose
```

`library(haldensify)`

`## haldensify v0.0.3: Conditional Density Estimation with the Highly Adaptive Lasso`

`## txshift v0.2.7: Targeted Learning of the Causal Effects of Stochastic Interventions`

`set.seed(429153)`

Consider \(n\) observed units \(O_1, \ldots, O_n\), where each random variable \(O = (W, A, Y)\) corresponds to a single observational unit. Let \(W\) denote baseline covariates (e.g., age, sex, education level), \(A\) an intervention variable of interest (e.g., nutritional supplements), and \(Y\) an outcome of interest (e.g., disease status). Though it need not be the case, let \(A\) be continuous-valued, i.e. \(A \in \mathbb{R}\). Let \(O_i \sim \mathcal{P} \in \mathcal{M}\), where \(\mathcal{M}\) is the nonparametric statistical model defined as the set of continuous densities on \(O\) with respect to some dominating measure. To formalize the definition of stochastic interventions and their corresponding causal effects, we introduce a nonparametric structural equation model (NPSEM), based on (**???**), to define how the system changes under posited interventions: \[\begin{align*}\label{eqn:npsem}
W &= f_W(U_W) \\ A &= f_A(W, U_A) \\ Y &= f_Y(A, W, U_Y),
\end{align*}\] We denote the observed data structure \(O = (W, A, Y)\)

Letting \(A\) denote a continuous-valued treatment, we assume that the distribution of \(A\) conditional on \(W = w\) has support in the interval \((l(w), u(w))\) – for convenience, let this support be *a.e.* That is, the minimum natural value of treatment \(A\) for an individual with covariates \(W = w\) is \(l(w)\); similarly, the maximum is \(u(w)\). Then, a simple stochastic intervention, based on a shift \(\delta\), may be defined \[\begin{equation}\label{eqn:shift}
d(a, w) =
\begin{cases}
a - \delta & \text{if } a > l(w) + \delta \\
a & \text{if } a \leq l(w) + \delta,
\end{cases}
\end{equation}\] where \(0 \leq \delta \leq u(w)\) is an arbitrary pre-specified value that defines the degree to which the observed value \(A\) is to be shifted, where possible. For the purpose of using such a shift in practice, the present software provides estimators for a shift function that assumes that the density of treatment \(A\), conditional on the covariates \(W\), has support *a.e.*

```
# simulate simple data for tmle-shift sketch
n_obs <- 1000 # number of observations
n_w <- 1 # number of baseline covariates
tx_mult <- 2 # multiplier for the effect of W = 1 on the treatment
## baseline covariate -- simple, binary
W <- as.numeric(replicate(n_w, rbinom(n_obs, 1, 0.5)))
## create treatment based on baseline W
A <- as.numeric(rnorm(n_obs, mean = tx_mult * W, sd = 1))
# create outcome as a linear function of A, W + white noise
Y <- A + W + rnorm(n_obs, mean = 0, sd = 1)
# shift parameter
delta <- 0.5
```

The simplest way to compute the TML estimator for the stochastic treatment regime is to fit each of the major constituent parts (nuisance parameters) of the estimator with generalized linear models. To do this, one may merely call the `txshift`

function, providing the standard inputs listed below.

```
tmle_hal_shift_1 <- txshift(W = W, A = A, Y = Y, delta = delta,
fluctuation = "standard",
g_fit_args = list(fit_type = "hal",
n_bins = 5,
grid_type = "equal_mass",
lambda_seq =
exp(seq(-1, -9,
length = 300))),
Q_fit_args = list(fit_type = "glm",
glm_formula = "Y ~ .")
)
summary(tmle_hal_shift_1)
```

```
## lwr_ci param_est upr_ci param_var eif_mean estimator
## 1.9199 2.0529 2.1858 0.0046 -1.4396e-15 tmle
## n_iter
## 0
```

When computing any such TML estimator, we may, of course, vary the regressions used in fitting the nuisance parameters; however, an even simpler variation is to fit the step for the fluctuation submodels with a *weighted* method, simply weighting each observation by an auxiliary covariate (often denoted \(H_n\), and sometimes called the “clever covariate” in the literature) rather than using such a covariate directly in the submodel regression fit.

```
tmle_hal_shift_2 <- txshift(W = W, A = A, Y = Y, delta = delta,
fluctuation = "weighted",
g_fit_args = list(fit_type = "hal",
n_bins = 5,
grid_type = "equal_mass",
lambda_seq =
exp(seq(-1, -9,
length = 300))),
Q_fit_args = list(fit_type = "glm",
glm_formula = "Y ~ .")
)
summary(tmle_hal_shift_2)
```

```
## lwr_ci param_est upr_ci param_var eif_mean estimator
## 1.9195 2.0524 2.1854 0.0046 -1.2190e-16 tmle
## n_iter
## 0
```

`sl3`

To easily incorporate ensemble machine learning into the estimation procedure, we rely on the facilities provided in the `sl3`

R package (Coyle et al. 2019). For a complete guide on using the `sl3`

R package, consider consulting https://tlverse.org/sl3.

```
# SL learners to be used for most fits (e.g., IPCW, outcome regression)
lrnr_lib <- make_learner_stack("Lrnr_mean", "Lrnr_glm_fast", "Lrnr_ranger")
sl_learner <- Lrnr_sl$new(learners = lrnr_lib, metalearner = Lrnr_nnls$new())
# SL learners for conditional densities to be used for the propensity score fit
lrnr_dens_lib <- make_learner_stack(list("Lrnr_condensier", nbins = 35,
bin_estimator = Lrnr_glm_fast$new(),
bin_method = "equal.len",
pool = FALSE),
list("Lrnr_condensier", nbins = 30,
bin_estimator = Lrnr_ranger$new(),
bin_method = "equal.len",
pool = FALSE),
list("Lrnr_condensier", nbins = 25,
bin_estimator = Lrnr_ranger$new(),
bin_method = "equal.len",
pool = FALSE)
)
sl_learner_density <- Lrnr_sl$new(learners = lrnr_dens_lib,
metalearner = Lrnr_solnp_density$new())
```

Using the framework provided by the `sl3`

package, the nuisance parameters of the TML estimator may be fit with ensemble learning, using the cross-validation framework of the Super Learner algorithm of (**???**).

```
tmle_sl_shift_1 <- txshift(W = W, A = A, Y = Y, delta = delta,
fluctuation = "standard",
g_fit_args = list(fit_type = "sl",
sl_learners_density =
sl_learner_density),
Q_fit_args = list(fit_type = "sl",
sl_learners = sl_learner)
)
```

```
## Warning: `lang_tail()` is deprecated as of rlang 0.2.0.
## This warning is displayed once per session.
```

```
## Warning: `mut_node_cdr()` is deprecated as of rlang 0.2.0.
## This warning is displayed once per session.
```

```
##
## Iter: 1 fn: 3366.2548 Pars: 0.7028296205 0.0000004427 0.2971699373
## Iter: 2 fn: 3366.2548 Pars: 0.7028296984 0.0000002745 0.2971700271
## solnp--> Completed in 2 iterations
```

`summary(tmle_sl_shift_1)`

```
## lwr_ci param_est upr_ci param_var eif_mean estimator
## 2.386 2.5242 2.6623 0.005 -5.7967e-17 tmle
## n_iter
## 0
```

As before, we may vary the regression for the submodel fluctuation procedure by weighting each observation by the value of the so-called clever covariate rather than using such an auxiliary covariate directly in the regression procedure:

```
tmle_sl_shift_2 <- txshift(W = W, A = A, Y = Y, delta = delta,
fluctuation = "weighted",
g_fit_args = list(fit_type = "sl",
sl_learners_density =
sl_learner_density),
Q_fit_args = list(fit_type = "sl",
sl_learners = sl_learner)
)
```

```
##
## Iter: 1 fn: 3330.8935 Pars: 0.656132715 0.000000168 0.343867117
## Iter: 2 fn: 3330.8935 Pars: 0.65613275690 0.00000008682 0.34386715628
## solnp--> Completed in 2 iterations
```

`summary(tmle_sl_shift_2)`

```
## lwr_ci param_est upr_ci param_var eif_mean estimator
## 1.929 2.056 2.1829 0.0042 2.2170e-11 tmle
## n_iter
## 0
```

Recall that the asymptotic distribution of TML estimators has been studied thoroughly: \[\psi_n - \psi_0 = (P_n - P_0) \cdot D(\bar{Q}_n^*, g_n) + R(\hat{P}^*, P_0),\] which, provided the following two conditions:

- If \(D(\bar{Q}_n^*, g_n)\) converges to \(D(P_0)\) in \(L_2(P_0)\) norm, and
- the size of the class of functions considered for estimation of \(\bar{Q}_n^*\) and \(g_n\) is bounded (technically, \(\exists \mathcal{F}\) st \(D(\bar{Q}_n^*, g_n) \in \mathcal{F}\)
, where \(\mathcal{F}\) is a Donsker class), readily admits the conclusion that \(\psi_n - \psi_0 = (P_n - P_0) \cdot D(P_0) + R(\hat{P}^*, P_0)\).**whp**

Under the additional condition that the remainder term \(R(\hat{P}^*, P_0)\) decays as \(o_P \left( \frac{1}{\sqrt{n}} \right),\) we have that \[\psi_n - \psi_0 = (P_n - P_0) \cdot D(P_0) + o_P \left( \frac{1}{\sqrt{n}} \right),\] which, by a central limit theorem, establishes a Gaussian limiting distribution for the estimator:

\[\sqrt{n}(\psi_n - \psi) \to N(0, V(D(P_0))),\] where \(V(D(P_0))\) is the variance of the efficient influence curve (canonical gradient) when \(\psi\) admits an asymptotically linear representation.

The above implies that \(\psi_n\) is a \(\sqrt{n}\)-consistent estimator of \(\psi\), that it is asymptotically normal (as given above), and that it is locally efficient. This allows us to build Wald-type confidence intervals in a straightforward manner:

\[\psi_n \pm z_{\alpha} \cdot \frac{\sigma_n}{\sqrt{n}},\] where \(\sigma_n^2\) is an estimator of \(V(D(P_0))\). The estimator \(\sigma_n^2\) may be obtained using the bootstrap or computed directly via the following

\[\sigma_n^2 = \frac{1}{n} \sum_{i = 1}^{n} D^2(\bar{Q}_n^*, g_n)(O_i)\]

`(ci_shift <- confint(tmle_sl_shift_1))`

```
## lwr_ci est upr_ci
## 2.386045 2.524193 2.662342
```

In some special cases it may be useful for the experienced user to compute the treatment mechanism and outcome regressions separately (i.e., outside of the `tmle_txshift`

wrapper function), instead applying this user-facing wrapper only to invoke the *targeting* steps involved in computing the TML estimator for the treatment shift parameter. In such cases, the optional arguments `gn_fit_spec`

and `Qn_fit_spec`

may be utilized. We present a case of using these here:

```
# compute treatment mechanism (propensity score) externally
## first, produce the down-shifted treatment data
gn_downshift <- dnorm(A - delta, mean = tx_mult * W, sd = 1)
## next, initialize and produce the up-shifted treatment data
gn_upshift <- dnorm(A + delta, mean = tx_mult * W, sd = 1)
## now, initialize and produce the up-up-shifted (2 * delta) treatment data
gn_upupshift <- dnorm(A + 2 * delta, mean = tx_mult * W, sd = 1)
## then, initialize and produce the un-shifted treatment data
gn_noshift <- dnorm(A, mean = tx_mult * W, sd = 1)
## finally, put it all together into an object like what's produced internally
gn_out <- as.data.table(cbind(gn_downshift, gn_noshift, gn_upshift,
gn_upupshift))
setnames(gn_out, c("downshift", "noshift", "upshift", "upupshift"))
# compute outcome regression externally
Qn_noshift <- (W + A - min(Y)) / diff(range(Y))
Qn_upshift <- (W + A + delta - min(Y)) / diff(range(Y))
Qn_noshift[Qn_noshift < 0] <- .Machine$double.neg.eps
Qn_noshift[Qn_noshift > 1] <- 1 - .Machine$double.neg.eps
Qn_upshift[Qn_upshift < 0] <- .Machine$double.neg.eps
Qn_upshift[Qn_upshift > 1] <- 1 - .Machine$double.neg.eps
Qn_out <- as.data.table(cbind(Qn_noshift, Qn_upshift))
setnames(Qn_out, c("noshift", "upshift"))
# invoke the wrapper function only to apply the targeting step
tmle_shift_spec <- txshift(W = W, A = A, Y = Y, delta = delta,
fluctuation = "standard",
ipcw_fit_args = NULL,
g_fit_args = list(fit_type = "fit_spec"),
Q_fit_args = list(fit_type = "fit_spec"),
gn_fit_spec = gn_out,
Qn_fit_spec = Qn_out)
summary(tmle_shift_spec)
```

```
## lwr_ci param_est upr_ci param_var eif_mean estimator
## 1.933 2.0689 2.2047 0.0048 1.9022e-11 tmle
## n_iter
## 0
```

Coyle, Jeremy R, Nima S Hejazi, Ivana Malenica, and Oleg Sofrygin. 2019. “sl3: Modern Pipelines for Machine Learning and Super Learning.” https://github.com/tlverse/sl3. https://doi.org/10.5281/zenodo.3251138.

Díaz, Iván, and Mark J van der Laan. 2012. “Population Intervention Causal Effects Based on Stochastic Interventions.” *Biometrics* 68 (2). Wiley Online Library: 541–49.

———. 2018. “Stochastic Treatment Regimes.” In *Targeted Learning in Data Science: Causal Inference for Complex Longitudinal Studies*, 167–80. Springer Science & Business Media.

van der Laan, Mark J, and Sherri Rose. 2011. *Targeted Learning: Causal Inference for Observational and Experimental Data*. Springer Science & Business Media.

———. 2018. *Targeted Learning in Data Science: Causal Inference for Complex Longitudinal Studies*. Springer Science & Business Media.