Skip to content

Commit b9de6f3

Browse files
committed
rename hat_Delta_stats() as mimR()
1 parent 5ee5c37 commit b9de6f3

File tree

9 files changed

+320
-322
lines changed

9 files changed

+320
-322
lines changed

Basic_example.R

+12-12
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,24 @@ head(AC.IPD)
2727
BC.ALD
2828

2929

30-
## ----hat_Delta_stats_maic-------------------------------------------------
31-
hat_Delta_stats_maic <- hat_Delta_stats(AC.IPD, BC.ALD, strategy = strategy_maic())
30+
## ----mimR_maic-------------------------------------------------
31+
mimR_maic <- mimR(AC.IPD, BC.ALD, strategy = strategy_maic())
3232

3333

34-
## ----hat_Delta_stats_maic-print-------------------------------------------
35-
hat_Delta_stats_maic
34+
## ----mimR_maic-print-------------------------------------------
35+
mimR_maic
3636

3737

38-
## ----hat_Delta_stats_stc--------------------------------------------------
39-
hat_Delta_stats_stc <- hat_Delta_stats(AC.IPD, BC.ALD, strategy = strategy_stc())
40-
hat_Delta_stats_stc
38+
## ----mimR_stc--------------------------------------------------
39+
mimR_stc <- mimR(AC.IPD, BC.ALD, strategy = strategy_stc())
40+
mimR_stc
4141

4242

43-
## ----hat_Delta_stats_gcomp_ml---------------------------------------------
44-
# hat_Delta_stats_gcomp_ml <- hat_Delta_stats(AC.IPD, BC.ALD, strategy = strategy_gcomp_ml())
43+
## ----mimR_gcomp_ml---------------------------------------------
44+
# mimR_gcomp_ml <- mimR(AC.IPD, BC.ALD, strategy = strategy_gcomp_ml())
4545

4646

47-
## ----hat_Delta_stats_gcomp_stan-------------------------------------------
48-
hat_Delta_stats_gcomp_stan <- hat_Delta_stats(AC.IPD, BC.ALD, strategy = strategy_gcomp_stan())
49-
hat_Delta_stats_gcomp_stan
47+
## ----mimR_gcomp_stan-------------------------------------------
48+
mimR_gcomp_stan <- mimR(AC.IPD, BC.ALD, strategy = strategy_gcomp_stan())
49+
mimR_gcomp_stan
5050

NAMESPACE

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export(IPD_stats)
1010
export(gcomp_ml.boot)
1111
export(gcomp_ml_log_odds_ratio)
1212
export(gcomp_stan)
13-
export(hat_Delta_stats)
1413
export(marginal_treatment_effect)
1514
export(marginal_variance)
15+
export(mimR)
1616
export(new_strategy)
1717
export(strategy_gcomp_ml)
1818
export(strategy_gcomp_stan)

R/IPD_stats.R

-282
Original file line numberDiff line numberDiff line change
@@ -1,286 +1,4 @@
11

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-
2842
#' @name IPD_stats
2853
#' @title Calculate individual-level patient data statistics
2864
#'

0 commit comments

Comments
 (0)