Title: | Bayesian Analysis of Heterogeneous Treatment Effect |
---|---|
Description: | It is vital to assess the heterogeneity of treatment effects (HTE) when making health care decisions for an individual patient or a group of patients. Nevertheless, it remains challenging to evaluate HTE based on information collected from clinical studies that are often designed and conducted to evaluate the efficacy of a treatment for the overall population. The Bayesian framework offers a principled and flexible approach to estimate and compare treatment effects across subgroups of patients defined by their characteristics. This package allows users to explore a wide range of Bayesian HTE analysis models, and produce posterior inferences about HTE. See Wang et al. (2018) <DOI:10.18637/jss.v085.i07> for further details. |
Authors: | Chenguang Wang [aut, cre], Ravi Varadhan [aut], Trustees of Columbia University [cph] (tools/make_cpp.R, R/stanmodels.R) |
Maintainer: | Chenguang Wang <[email protected]> |
License: | GPL (>= 3) |
Version: | 3.1 |
Built: | 2024-12-25 07:11:07 UTC |
Source: | CRAN |
This package contains the functions for running Bayesian models implemented in
STAN
for HTE analysis.
Consider a randomized two-arm clinical trial. Let denote the response
and
denote treatment arm assignment. For subgroup analysis,
assume there are
baseline covariates,
, of
interest. The covariates can be binary, ordinal with numerical values, or
nominal variables. Let
denote the
collection of subgroups defined by the covariates. Let
denote the treatment effect in subgroup
, and let
be the estimated
in subgroup
with
the estimated variance
associated with
.
We approximate the distribution of by
and assign an informative prior to .
We consider two options in the software: log-normal or uniform prior. The uniform prior is specified as:
and the log-normal prior is specified as:
where is a parameter specified
by the users.
We consider a set of models together with the priors for :
This model assumes that patients in all the subgroups are exchangeable. That is, all the subgroups are statistically identical with regard to the treatment effect and there is no subgroup effect. Information about treatment effects can be directly combined from all subgroups for inference. The model is specified as follows:
where should be set to 0 in most cases, and
is large in relation to the magnitude of the treatment effect size
so that the prior for
is essentially non-informative.
The subgroups are fully distinguished from each other with regard to the treatment effect. There is no information about treatment effects shared between any subgroups. The model is specified as follows:
The model introduces a first-order, linear regression structure. This model takes into account the information that the subgroups are formulated based on the set of baseline covariates. The coefficients are assumed to be exchangeable among subgroups. Information about treatment effects are shared between subgroups with similar baseline covariates through these coefficients. The model is specified as follows:
This approach assumes all subgroups are exchangeable with regards to the treatment effect. The model is specified as follows:
This model combines basic regression with shrinkage, with a linear regression structure and a random effect term. Direct estimates are shrunken towards the regression surface. The model is specified as follows:
This model assumes that the elements in coefficient are exchangeable with each other, which allows information sharing among covariate effects. Similar to the simple regression model, only the first-order interactions are considered. The model is specified as follows:
This approach extends the Dixon and Simon model by introducing the higher-order interactions, with the interaction effects exchangeable. The model is specified as follows:
where denotes the set of
th order interaction terms
This package provides a web-based Shiny GUI. See bzShiny
for
details.
Jones HE, Ohlssen DI, Neuenschwander B, Racine A, Branson M (2011). Bayesian models for subgroup analysis in clinical trials. Clinical Trials, 8(2), 129-143.
Dixon DO, Simon R (1991). Bayesian subset analysis. Biometrics, 47(3), 871-881.
Wang C, Louis TA, Henderson NC, Weiss CO, Varadhan R (2018). beanz: An R Package for Bayesian Analysis of Heterogeneous Treatment Effects with a Graphical User Interface. Journal of Statistical Software, 85(7), 1-31.
Call STAN to draw posterior samples for Bayesian HTE models.
bzCallStan( mdls = c("nse", "fs", "sr", "bs", "srs", "ds", "eds"), dat.sub, var.estvar, var.cov, par.pri = c(B = 1000, C = 1000, D = 1, MU = 0), var.nom = NULL, delta = 0, prior.sig = 1, chains = 4, ... )
bzCallStan( mdls = c("nse", "fs", "sr", "bs", "srs", "ds", "eds"), dat.sub, var.estvar, var.cov, par.pri = c(B = 1000, C = 1000, D = 1, MU = 0), var.nom = NULL, delta = 0, prior.sig = 1, chains = 4, ... )
mdls |
name of the Bayesian HTE model. The options are:
|
dat.sub |
dataset with subgroup treatment effect summary data |
var.estvar |
column names in dat.sub that corresponds to treatment effect estimation and the estimated variance |
var.cov |
array of column names in dat.sub that corresponds to binary or ordinal baseline covariates |
par.pri |
vector of prior parameters for each model. See
|
var.nom |
array of column names in dat.sub that corresponds to nominal baseline covariates |
delta |
parameter for specifying the informative priors of |
prior.sig |
option for the informative prior on |
chains |
STAN options. Number of chains. |
... |
options to call STAN sampling. These options include
|
A class beanz.stan
list containing
name of the Bayesian HTE model
raw rstan
sampling
results
matrix of the posterior samples
method to return the posterior sample of the subgroup treatment effects
DIC value
leave-one-out cross-validation information criterion
Gelman and Rubin potential scale reduction statistic
option for the informative prior on
parameter for specifying the informative priors of
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; var.estvar <- c("Estimate", "Variance"); subgrp.effect <- bzGetSubgrpRaw(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); rst.nse <- bzCallStan("nse", dat.sub=subgrp.effect, var.estvar = var.estvar, var.cov = var.cov, par.pri = c(B=1000, MU = 0), chains=4, iter=600, warmup=200, thin=2, seed=1000); rst.sr <- bzCallStan("sr", dat.sub=subgrp.effect, var.estvar=var.estvar, var.cov = var.cov, par.pri=c(B=1000, C=1000), chains=4, iter=600, warmup=200, thin=2, seed=1000); ## End(Not run)
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; var.estvar <- c("Estimate", "Variance"); subgrp.effect <- bzGetSubgrpRaw(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); rst.nse <- bzCallStan("nse", dat.sub=subgrp.effect, var.estvar = var.estvar, var.cov = var.cov, par.pri = c(B=1000, MU = 0), chains=4, iter=600, warmup=200, thin=2, seed=1000); rst.sr <- bzCallStan("sr", dat.sub=subgrp.effect, var.estvar=var.estvar, var.cov = var.cov, par.pri=c(B=1000, C=1000), chains=4, iter=600, warmup=200, thin=2, seed=1000); ## End(Not run)
Present the difference in the posterior treatment effects between subgroups
bzSummaryComp(stan.rst, sel.grps = NULL, cut = 0, digits = 3, seed = NULL) bzPlotComp(stan.rst, sel.grps = NULL, ..., seed = NULL) bzForestComp( stan.rst, sel.grps = NULL, ..., quants = c(0.025, 0.975), seed = NULL )
bzSummaryComp(stan.rst, sel.grps = NULL, cut = 0, digits = 3, seed = NULL) bzPlotComp(stan.rst, sel.grps = NULL, ..., seed = NULL) bzForestComp( stan.rst, sel.grps = NULL, ..., quants = c(0.025, 0.975), seed = NULL )
stan.rst |
a class |
sel.grps |
an array of subgroup numbers to be included in the summary results |
cut |
cut point to compute the probabiliby that the posterior subgroup treatment effects is below |
digits |
number of digits in the summary result table |
seed |
random seed |
... |
options for |
quants |
lower and upper quantiles of the credible intervals in the forest plot |
bzSummaryComp
generates a data frame with summary statistics
of the difference of treatment effects between the selected subgroups.
bzPlotComp
generates the density plot of the difference in the
posterior treatment effects between subgroups. bzForestComp
generates the forest plot of the difference in the posterior treatment
effects between subgroups.
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; var.estvar <- c("Estimate", "Variance"); subgrp.effect <- bzGetSubgrpRaw(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); rst.sr <- bzCallStan("sr", dat.sub=subgrp.effect, var.estvar=var.estvar, var.cov = var.cov, par.pri=c(B=1000, C=1000), chains=4, iter=500, warmup=100, thin=2, seed=1000); sel.grps <- c(1,4,5); tbl.sub <- bzSummaryComp(rst.sr, sel.grps=sel.grps); bzPlot(rst.sr, sel.grps = sel.grps); bzForest(rst.sr, sel.grps = sel.grps); ## End(Not run)
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; var.estvar <- c("Estimate", "Variance"); subgrp.effect <- bzGetSubgrpRaw(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); rst.sr <- bzCallStan("sr", dat.sub=subgrp.effect, var.estvar=var.estvar, var.cov = var.cov, par.pri=c(B=1000, C=1000), chains=4, iter=500, warmup=100, thin=2, seed=1000); sel.grps <- c(1,4,5); tbl.sub <- bzSummaryComp(rst.sr, sel.grps=sel.grps); bzPlot(rst.sr, sel.grps = sel.grps); bzForest(rst.sr, sel.grps = sel.grps); ## End(Not run)
Gail-Simon qualitative interaction test.
bzGailSimon(effects, sderr, d = 0)
bzGailSimon(effects, sderr, d = 0)
effects |
subgroup treatment effects |
sderr |
standard deviation of the estimated treatment effects |
d |
clinically meaningful difference |
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; subgrp.effect <- bzGetSubgrp(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); gs.pval <- bzGailSimon(subgrp.effect$Estimate, subgrp.effect$Variance); ## End(Not run)
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; subgrp.effect <- bzGetSubgrp(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); gs.pval <- bzGailSimon(subgrp.effect$Estimate, subgrp.effect$Variance); ## End(Not run)
Compute subgroup treatment effect estimation and variance for subgroup effect summary data. The estimation and variance are combined if there are multiple record of the same subgroup, defined by the covariates, in the data.
bzGetSubgrp(data.all, var.ey, var.variance, var.cov)
bzGetSubgrp(data.all, var.ey, var.variance, var.cov)
data.all |
subject level dataset |
var.ey |
column name in |
var.variance |
column name in |
var.cov |
array of column names in |
A dataframe with treatment effect estimation and variance for each subgroup
Compute subgroup treatment effect estimation and variance from subject level data.
bzGetSubgrpRaw( data.all, var.resp, var.trt, var.cov, var.censor, resptype = c("continuous", "binary", "survival") )
bzGetSubgrpRaw( data.all, var.resp, var.trt, var.cov, var.censor, resptype = c("continuous", "binary", "survival") )
data.all |
subject level dataset |
var.resp |
column name in |
var.trt |
column name in |
var.cov |
array of column names in |
var.censor |
column name in |
resptype |
type of response. The options are |
A dataframe with treatment effect estimation and variance for each subgroup
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; subgrp.effect <- bzGetSubgrpRaw(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); ## End(Not run)
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; subgrp.effect <- bzGetSubgrpRaw(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); ## End(Not run)
Get the predictive distribution of the subgroup treatment effects
bzPredSubgrp(stan.rst, dat.sub, var.estvar)
bzPredSubgrp(stan.rst, dat.sub, var.estvar)
stan.rst |
a class |
dat.sub |
dataset with subgroup treatment effect summary data |
var.estvar |
column names in dat.sub that corresponds to treatment effect estimation and the estimated variance |
A dataframe of predicted subgroup treament effects. That is, the distribution of
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; var.estvar <- c("Estimate", "Variance"); subgrp.effect <- bzGetSubgrp(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); rst.nse <- bzCallStan("nse", dat.sub=subgrp.effect, var.estvar = var.estvar, var.cov = var.cov, par.pri = c(B=1000), chains=4, iter=4000, warmup=2000, thin=2, seed=1000); pred.effect <- bzPredSubgrp(rst.nes, dat.sub = solvd.sub, var.estvar = var.estvar); ## End(Not run)
## Not run: var.cov <- c("sodium", "lvef", "any.vasodilator.use"); var.resp <- "y"; var.trt <- "trt"; var.censor <- "censor"; resptype <- "survival"; var.estvar <- c("Estimate", "Variance"); subgrp.effect <- bzGetSubgrp(solvd.sub, var.resp = var.resp, var.trt = var.trt, var.cov = var.cov, var.censor = var.censor, resptype = resptype); rst.nse <- bzCallStan("nse", dat.sub=subgrp.effect, var.estvar = var.estvar, var.cov = var.cov, par.pri = c(B=1000), chains=4, iter=4000, warmup=2000, thin=2, seed=1000); pred.effect <- bzPredSubgrp(rst.nes, dat.sub = solvd.sub, var.estvar = var.estvar); ## End(Not run)
Compare the DIC from different models and report the summary of treatment effects based on the model with the smallest DIC value
bzRptTbl(lst.stan.rst, dat.sub, var.cov, cut = 0, digits = 3)
bzRptTbl(lst.stan.rst, dat.sub, var.cov, cut = 0, digits = 3)
lst.stan.rst |
list of class |
dat.sub |
dataset with subgroup treatment effect summary data |
var.cov |
array of column names in dat.sub that corresponds to binary or ordinal baseline covariates |
cut |
cut point to compute the probabiliby that the posterior subgroup treatment effects is below |
digits |
number of digits in the summary result table |
A dataframe with summary statistics of the model selected by DIC
Call Shiny to run beanz
as a web-based application
bzShiny()
bzShiny()
Present the posterior subgroup treatment effects
bzSummary( stan.rst, sel.grps = NULL, ref.stan.rst = NULL, ref.sel.grps = 1, cut = 0, digits = 3 ) bzPlot(stan.rst, sel.grps = NULL, ref.stan.rst = NULL, ref.sel.grps = 1, ...) bzForest( stan.rst, sel.grps = NULL, ref.stan.rst = NULL, ref.sel.grps = 1, ..., quants = c(0.025, 0.975) )
bzSummary( stan.rst, sel.grps = NULL, ref.stan.rst = NULL, ref.sel.grps = 1, cut = 0, digits = 3 ) bzPlot(stan.rst, sel.grps = NULL, ref.stan.rst = NULL, ref.sel.grps = 1, ...) bzForest( stan.rst, sel.grps = NULL, ref.stan.rst = NULL, ref.sel.grps = 1, ..., quants = c(0.025, 0.975) )
stan.rst |
a class |
sel.grps |
an array of subgroup numbers to be included in the summary results |
ref.stan.rst |
a class |
ref.sel.grps |
subgroups from the reference model to be included in the summary table |
cut |
cut point to compute the probabiliby that the posterior subgroup treatment effects is below |
digits |
number of digits in the summary result table |
... |
options for |
quants |
lower and upper quantiles of the credible intervals in the forest plot |
bzSummary
generates a dataframe with summary statistics
of the posterior treatment effect for the selected subgroups.
bzPlot
generates the density plot of the posterior treatment
effects for the selected subgroups. bzForest
generates the forest plot of the posterior treatment
effects.
## Not run: sel.grps <- c(1,4,5); tbl.sub <- bzSummary(rst.sr, ref.stan.rst=rst.nse, ref.sel.grps=1); bzPlot(rst.sr, sel.grps = sel.grps, ref.stan.rst=rst.nse, ref.sel.grps=1); bzForest(rst.sr, sel.grps = sel.grps, ref.stan.rst=rst.nse, ref.sel.grps=1); ## End(Not run)
## Not run: sel.grps <- c(1,4,5); tbl.sub <- bzSummary(rst.sr, ref.stan.rst=rst.nse, ref.sel.grps=1); bzPlot(rst.sr, sel.grps = sel.grps, ref.stan.rst=rst.nse, ref.sel.grps=1); bzForest(rst.sr, sel.grps = sel.grps, ref.stan.rst=rst.nse, ref.sel.grps=1); ## End(Not run)
Dataset for use in beanz examples and vignettes.
A dataframe with 6 variables:
treatment assignment
time to death or first hospitalization
censoring status
level of sodium
level of lvef
level of use of vasodilator
Subject level data from SOLVD trial. SOLVD is a randomized controlled trial of the effect of an Angiotensin-converting-enzyme inhibitor (ACE inhibitor) called enalapril on survival in patients with reduced left ventricular ejection fraction and congestive heart failure (CHF).
Solvd Investigators and others, Effect of enalapril on survival in patients with reduced left ventricular ejection fraction and congestive heart failure. N Engl J Med. 1991, 325:293-302