|
1 | 1 |
|
2 |
| -# create S3 class for each approach |
3 |
| - |
4 |
| -#' @rdname strategy |
5 |
| -#' |
6 |
| -#' @section Matching-adjusted indirect comparison (MAIC): |
7 |
| -#' |
8 |
| -#' MAIC is a form of non-parametric likelihood reweighting method |
9 |
| -#' which allows the propensity score logistic |
10 |
| -#' regression model to be estimated without IPD in the _AC_ population. |
11 |
| -#' The mean outcomes \eqn{\mu_{t(AC)}} on treatment \eqn{t = A,B} in the _AC_ |
12 |
| -#' target population are estimated by taking a weighted average of the |
13 |
| -#' outcomes \eqn{Y} of the \eqn{N} individuals in arm \eqn{t} of the _AB_ population |
14 |
| -#' |
15 |
| -#' Used to compare marginal treatment effects where there are cross-trial |
16 |
| -#' differences in effect modifiers and limited patient-level data. |
17 |
| -#' |
18 |
| -#' \deqn{ |
19 |
| -#' \hat{Y}_{} = \frac{\sum_{i=1}^{N} Y_{it(AB)} w_{it}}{\sum _{i=1}^{N} w_{it}} |
20 |
| -#' } |
21 |
| -#' where the weight \eqn{w_{it}} assigned to the \eqn{i}-th individual receiving treatment |
22 |
| -#' \eqn{t} is equal to the odds of being enrolled in the _AC_ trial vs the _AB_ trial. |
23 |
| -#' |
24 |
| -#' |
25 |
| -#' The default formula is |
26 |
| -#' \deqn{ |
27 |
| -#' y = X_3 + X_4 + \beta_{t}X_1 + \beta_{t}X_2 |
28 |
| -#' } |
29 |
| -#' |
30 |
| -#' @param R The number of resamples used for the non-parametric bootstrap |
31 |
| -#' @template args-ald |
32 |
| -#' |
33 |
| -#' @return `maic` class object |
34 |
| -#' @export |
35 |
| -#' |
36 |
| -strategy_maic <- function(formula = as.formula("y ~ X3 + X4 + trt*X1 + trt*X2"), |
37 |
| - R = 1000) { |
38 |
| - if (class(formula) != "formula") |
39 |
| - stop("formula argument must be of formula class.") |
40 |
| - |
41 |
| - default_args <- formals() |
42 |
| - args <- as.list(match.call())[-1] |
43 |
| - args <- modifyList(default_args, args) |
44 |
| - do.call(new_strategy, c(strategy = "maic", args)) |
45 |
| -} |
46 |
| - |
47 |
| -#' @rdname strategy |
48 |
| -#' |
49 |
| -#' @section Simulated treatment comparison (STC): |
50 |
| -#' Outcome regression-based method which targets a conditional treatment effect. |
51 |
| -#' STC is a modification of the covariate adjustment method. |
52 |
| -#' An outcome model is fitted using IPD in the _AB_ trial |
53 |
| -#' |
54 |
| -#' \deqn{ |
55 |
| -#' g(\mu_{t(AB)}(X)) = \beta_0 + \beta_1^T X + (\beta_B + \beta_2^T X^{EM}) I(t=B) |
56 |
| -#' } |
57 |
| -#' where \eqn{\beta_0} is an intercept term, \eqn{\beta_1} is a vector of coefficients for |
58 |
| -#' prognostic variables, \eqn{\beta_B} is the relative effect of treatment _B_ compared |
59 |
| -#' to _A_ at \eqn{X=0}, \eqn{\beta_2} is a vector of coefficients for effect |
60 |
| -#' modifiers \eqn{X^{EM}} subvector of the full covariate vector \eqn{X}), and |
61 |
| -#' \eqn{\mu_{t(AB)}(X)} is the expected outcome of an individual assigned |
62 |
| -#' treatment \eqn{t} with covariate values \eqn{X} which is transformed onto a |
63 |
| -#' chosen linear predictor scale with link function \eqn{g(\cdot)}. |
64 |
| -#' |
65 |
| -#' The default formula is |
66 |
| -#' \deqn{ |
67 |
| -#' y = X_3 + X_4 + \beta_t(X_1 - \bar{X_1}) + \beta_t(X_2 - \bar{X2}) |
68 |
| -#' } |
69 |
| -#' |
70 |
| -#' @return `stc` class object |
71 |
| -#' @export |
72 |
| -# |
73 |
| -strategy_stc <- function(formula = |
74 |
| - as.formula("y ~ X3 + X4 + trt*I(X1 - mean(X1)) + trt*I(X2 - mean(X2))")) { |
75 |
| - |
76 |
| - if (class(formula) != "formula") |
77 |
| - stop("formula argument must be of formula class.") |
78 |
| - |
79 |
| - default_args <- formals() |
80 |
| - args <- as.list(match.call())[-1] |
81 |
| - args <- modifyList(default_args, args) |
82 |
| - do.call(new_strategy, c(strategy = "stc", args)) |
83 |
| -} |
84 |
| - |
85 |
| -#' @rdname strategy |
86 |
| -#' |
87 |
| -#' @section G-computation maximum likelihood: |
88 |
| -#' |
89 |
| -#' G-computation marginalizes the conditional estimates by separating the regression modelling |
90 |
| -#' from the estimation of the marginal treatment effect for _A_ versus _C_. |
91 |
| -#' First, a regression model of the observed outcome \eqn{y} on the covariates \eqn{x} and treatment \eqn{z} is fitted to the _AC_ IPD: |
92 |
| -#' |
93 |
| -#' \deqn{ |
94 |
| -#' g(\mu_n) = \beta_0 + \boldsymbol{x}_n \boldsymbol{\beta_1} + (\beta_z + \boldsymbol{x_n^{EM}} \boldsymbol{\beta_2}) \mbox{I}(z_n=1) |
95 |
| -#' } |
96 |
| -#' In the context of G-computation, this regression model is often called the “Q-model.” |
97 |
| -#' Having fitted the Q-model, the regression coefficients are treated as nuisance parameters. |
98 |
| -#' The parameters are applied to the simulated covariates \eqn{x*} to predict hypothetical outcomes |
99 |
| -#' for each subject under both possible treatments. Namely, a pair of predicted outcomes, |
100 |
| -#' also called potential outcomes, under _A_ and under _C_, is generated for each subject. |
101 |
| -#' |
102 |
| -#' By plugging treatment _C_ into the regression fit for every simulated observation, |
103 |
| -#' we predict the marginal outcome mean in the hypothetical scenario in which all units are under treatment _C_: |
104 |
| -#' |
105 |
| -#' \deqn{ |
106 |
| -#' \hat{\mu}_0 = \int_{x^*} g^{-1} (\hat{\beta}_0 + x^* \hat{\beta}_1 ) p(x^*) dx^* |
107 |
| -#' } |
108 |
| -#' To estimate the marginal or population-average treatment effect for A versus C in the linear predictor scale, |
109 |
| -#' one back-transforms to this scale the average predictions, taken over all subjects on the natural outcome scale, |
110 |
| -#' and calculates the difference between the average linear predictions: |
111 |
| -#' |
112 |
| -#' \deqn{ |
113 |
| -#' \hat{\Delta}^{(2)}_{10} = g(\hat{\mu}_1) - g(\hat{\mu}_0) |
114 |
| -#' } |
115 |
| -#' |
116 |
| -#' The default formula is |
117 |
| -#' \deqn{ |
118 |
| -#' y = X_3 + X_4 + \beta_{t}X_1 + \beta_{t}X_2 |
119 |
| -#' } |
120 |
| -#' |
121 |
| -#' @param R The number of resamples used for the non-parametric bootstrap |
122 |
| -#' |
123 |
| -#' @return `gcomp_ml` class object |
124 |
| -#' @export |
125 |
| -#' |
126 |
| -strategy_gcomp_ml <- function(formula = |
127 |
| - as.formula("y ~ X3 + X4 + trt*X1 + trt*X2"), |
128 |
| - R = 1000) { |
129 |
| - |
130 |
| - if (class(formula) != "formula") |
131 |
| - stop("formula argument must be of formula class.") |
132 |
| - |
133 |
| - default_args <- formals() |
134 |
| - args <- as.list(match.call())[-1] |
135 |
| - args <- modifyList(default_args, args) |
136 |
| - do.call(new_strategy, c(strategy = "gcomp_ml", args)) |
137 |
| -} |
138 |
| - |
139 |
| -#' @rdname strategy |
140 |
| -#' |
141 |
| -#' @section G-computation Bayesian: |
142 |
| -#' The difference between Bayesian G-computation and its maximum-likelihood |
143 |
| -#' counterpart is in the estimated distribution of the predicted outcomes. The |
144 |
| -#' Bayesian approach also marginalizes, integrates or standardizes over the |
145 |
| -#' joint posterior distribution of the conditional nuisance parameters of the |
146 |
| -#' outcome regression, as well as the joint covariate distribution. |
147 |
| -#' |
148 |
| -#' Draw a vector of size \eqn{N*} of predicted outcomes \eqn{y*z} under each set |
149 |
| -#' intervention \eqn{z* \in \{0, 1\}} from its posterior predictive distribution |
150 |
| -#' under the specific treatment. This is defined as \eqn{p(y*_{z*} | |
151 |
| -#' \mathcal{D}_{AC}) = \int_{\beta} p(y*_{z*} | \beta) p(\beta | \mathcal{D}_{AC}) d\beta} |
152 |
| -#' where \eqn{p(\beta | \mathcal{D}_{AC})} is the |
153 |
| -#' posterior distribution of the outcome regression coefficients \eqn{\beta}, |
154 |
| -#' which encode the predictor-outcome relationships observed in the _AC_ trial IPD. |
155 |
| -#' |
156 |
| -#' This is given by: |
157 |
| -#' |
158 |
| -#' \deqn{ |
159 |
| -#' p(y*_{z*} | \mathcal{D}_{AC}) = \int_{x*} p(y* | z*, x*, \mathcal{D}_{AC}) p(x* | \mathcal{D}_{AC}) dx* |
160 |
| -#' } |
161 |
| -#' |
162 |
| -#' \deqn{ |
163 |
| -#' = \int_{x*} \int_{\beta} p(y* | z*, x*, \beta) p(x* | \beta) p(\beta | \mathcal{D}_{AC}) d\beta dx* |
164 |
| -#' } |
165 |
| -#' In practice, the integrals above can be approximated numerically, using full Bayesian |
166 |
| -#' estimation via Markov chain Monte Carlo (MCMC) sampling. |
167 |
| -#' |
168 |
| -#' The default formula is |
169 |
| -#' \deqn{ |
170 |
| -#' y = X_3 + X_4 + \beta_{t}X_1 + \beta_{t}X_2 |
171 |
| -#' } |
172 |
| -#' |
173 |
| -#' @return `gcomp_stan` class object |
174 |
| -#' @export |
175 |
| -#' |
176 |
| -strategy_gcomp_stan <- function(formula = |
177 |
| - as.formula("y ~ X3 + X4 + trt*X1 + trt*X2")) { |
178 |
| - |
179 |
| - if (class(formula) != "formula") |
180 |
| - stop("formula argument must be of formula class.") |
181 |
| - |
182 |
| - default_args <- formals() |
183 |
| - args <- as.list(match.call())[-1] |
184 |
| - args <- modifyList(default_args, args) |
185 |
| - do.call(new_strategy, c(strategy = "gcomp_stan", args)) |
186 |
| -} |
187 |
| - |
188 |
| -#' @name strategy |
189 |
| -#' @title New strategy objects |
190 |
| -#' |
191 |
| -#' @description |
192 |
| -#' Create a type of strategy class for each modelling approach. |
193 |
| -#' |
194 |
| -#' @param strategy Class name from `strategy_maic`, `strategy_stc`, `strategy_gcomp_ml`, `strategy_gcomp_stan` |
195 |
| -#' @param formula Linear regression `formula` object |
196 |
| -#' @param ... Additional arguments |
197 |
| -#' |
198 |
| -#' @export |
199 |
| -#' |
200 |
| -new_strategy <- function(strategy, ...) { |
201 |
| - structure(list(...), class = c(strategy, "strategy", "list")) |
202 |
| -} |
203 |
| - |
204 |
| - |
205 |
| -#' @title Calculate the difference between treatments using all evidence |
206 |
| -#' |
207 |
| -#' @description |
208 |
| -#' This is the main, top-level wrapper for `hat_Delta_stats()`. |
209 |
| -#' Methods taken from |
210 |
| -#' \insertCite{RemiroAzocar2022}{mimR}. |
211 |
| -#' |
212 |
| -#' @param AC.IPD Individual-level patient data. Suppose between studies _A_ and _C_. |
213 |
| -#' @param BC.ALD Aggregate-level data. Suppose between studies _B_ and _C_. |
214 |
| -#' @param strategy Computation strategy function. These can be |
215 |
| -#' `strategy_maic()`, `strategy_stc()`, `strategy_gcomp_ml()` and `strategy_gcomp_stan()` |
216 |
| -#' @param CI Confidence interval; between 0,1 |
217 |
| -#' @param ... Additional arguments |
218 |
| -#' @return List of length 3 of statistics as a `mimR` class object. |
219 |
| -#' Containing statistics between each pair of treatments. |
220 |
| -#' These are the mean contrasts, variances and confidence intervals, |
221 |
| -#' respectively. |
222 |
| -#' @importFrom Rdpack reprompt |
223 |
| -#' |
224 |
| -#' @references |
225 |
| -#' \insertRef{RemiroAzocar2022}{mimR} |
226 |
| -#' |
227 |
| -#' @export |
228 |
| -#' @examples |
229 |
| -#' |
230 |
| -#' data(AC_IPD) # AC patient-level data |
231 |
| -#' data(BC_ALD) # BC aggregate-level data |
232 |
| -#' |
233 |
| -#' # matching-adjusted indirect comparison |
234 |
| -#' hat_Delta_stats_maic <- hat_Delta_stats(AC_IPD, BC_ALD, strategy = strategy_maic()) |
235 |
| -#' |
236 |
| -#' # simulated treatment comparison |
237 |
| -#' hat_Delta_stats_stc <- hat_Delta_stats(AC_IPD, BC_ALD, strategy = strategy_stc()) |
238 |
| -#' |
239 |
| -#' # G-computation with maximum likelihood |
240 |
| -#' # hat_Delta_stats_gcomp_ml <- hat_Delta_stats(AC_IPD, BC_ALD, strategy = strategy_gcomp_ml()) |
241 |
| -#' |
242 |
| -#' # G-computation with Bayesian inference |
243 |
| -#' hat_Delta_stats_gcomp_stan <- hat_Delta_stats(AC_IPD, BC_ALD, strategy = strategy_gcomp_stan()) |
244 |
| -#' |
245 |
| -hat_Delta_stats <- function(AC.IPD, BC.ALD, strategy, CI = 0.95, ...) { |
246 |
| - |
247 |
| - if (CI <= 0 || CI >= 1) stop("CI argument must be between 0 and 1.") |
248 |
| - |
249 |
| - ##TODO: as method instead? |
250 |
| - if (!inherits(strategy, "strategy")) |
251 |
| - stop("strategy argument must be of a class strategy.") |
252 |
| - |
253 |
| - AC_hat_Delta_stats <- IPD_stats(strategy, ipd = AC.IPD, ald = BC.ALD, ...) |
254 |
| - BC_hat_Delta_stats <- ALD_stats(ald = BC.ALD) |
255 |
| - |
256 |
| - upper <- 0.5 + CI/2 |
257 |
| - ci_range <- c(1-upper, upper) |
258 |
| - |
259 |
| - contrasts <- list( |
260 |
| - AB = AC_hat_Delta_stats$mean - BC_hat_Delta_stats$mean, |
261 |
| - AC = AC_hat_Delta_stats$mean, |
262 |
| - BC = BC_hat_Delta_stats$mean) |
263 |
| - |
264 |
| - contrast_variances <- list( |
265 |
| - AB = AC_hat_Delta_stats$var + BC_hat_Delta_stats$var, |
266 |
| - AC = AC_hat_Delta_stats$var, |
267 |
| - BC = BC_hat_Delta_stats$var) |
268 |
| - |
269 |
| - contrast_ci <- list( |
270 |
| - AB = contrasts$AB + qnorm(ci_range)*as.vector(sqrt(contrast_variances$AB)), |
271 |
| - AC = contrasts$AC + qnorm(ci_range)*as.vector(sqrt(contrast_variances$AC)), |
272 |
| - BC = contrasts$BC + qnorm(ci_range)*as.vector(sqrt(contrast_variances$BC))) |
273 |
| - |
274 |
| - stats <- list(contrasts = contrasts, |
275 |
| - variances = contrast_variances, |
276 |
| - CI = contrast_ci) |
277 |
| - |
278 |
| - structure(stats, |
279 |
| - CI = CI, |
280 |
| - class = c("mimR", class(stats))) |
281 |
| -} |
282 |
| - |
283 |
| - |
284 | 2 | #' @name IPD_stats
|
285 | 3 | #' @title Calculate individual-level patient data statistics
|
286 | 4 | #'
|
|
0 commit comments