Title: | Bayesian Information Borrowing with Propensity Score Matching |
---|---|
Description: | Hybrid control design is a way to borrow information from external controls to augment concurrent controls in a randomized controlled trial and is expected to overcome the feasibility issue when adequate randomized controlled trials cannot be conducted. A major challenge in the hybrid control design is its inability to eliminate a prior-data conflict caused by systematic imbalances in measured or unmeasured confounding factors between patients in the concurrent treatment/control group and external controls. To prevent the prior-data conflict, a combined use of propensity score matching and Bayesian commensurate prior has been proposed in the context of hybrid control design. The propensity score matching is first performed to guarantee the balance in baseline characteristics, and then the Bayesian commensurate prior is constructed while discounting the information based on the similarity in outcomes between the concurrent and external controls. 'psBayesborrow' is a package to implement the propensity score matching and the Bayesian analysis with commensurate prior, as well as to conduct a simulation study to assess operating characteristics of the hybrid control design, where users can choose design parameters in flexible and straightforward ways depending on their own application. |
Authors: | Yusuke Yamaguchi [aut, cre], Jun Takeda [aut], Kentaro Takeda [aut] |
Maintainer: | Yusuke Yamaguchi <[email protected]> |
License: | MIT + file LICENSE |
Version: | 1.1.0 |
Built: | 2024-10-26 06:44:39 UTC |
Source: | CRAN |
A DESCRIPTION OF THE PACKAGE
Maintainer: Yusuke Yamaguchi [email protected]
Authors:
Jun Takeda
Kentaro Takeda
Stan Development Team (NA). RStan: the R interface to Stan. R package version 2.26.13. https://mc-stan.org
Bayesian analysis for binary outcome is implemented via MCMC, where a commensurate prior is used for incorporating data from external controls. No borrowing and full borrowing are also applicable.
commensurate.bin( formula, data, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, seed=sample.int(.Machine$integer.max,1))
commensurate.bin( formula, data, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, seed=sample.int(.Machine$integer.max,1))
formula |
Object of class |
data |
Data frame, which must have variables named |
method.borrow |
List of information borrowing method. |
chains |
Number of Markov chains in MCMC sampling. The default value is
|
iter |
Number of iterations for each chain (including warmup) in MCMC
sampling. The default value is |
warmup |
Number of warmup (aka burnin) iterations per chain in MCMC
sampling. The default value is |
thin |
Period for saving samples in MCMC sampling. The default value
is |
alternative |
Alternative hypothesis to be tested ("greater" or "less").
The default value is |
sig.level |
Significance level. The default value is
|
seed |
Setting a seed for MCMC sampling. |
The binary outcome is assumed to follow a binomial distribution. Given more than one covariates, a logistic regression model is built and its Bayesian estimation is performed via MCMC. Commensurate prior is used to dynamically discount the information to be borrowed from external control based on the similarity between the current trial and external controls, where the commensurability parameter determines the extent of borrowing. The commensurability parameter is assumed to follow a half-cauchy or a half-normal distribution, and its scale parameter needs to be carefully specified. No borrowing approach is to perform the analysis without incorporating the external controls. Full borrowing approach is just to pool the concurrent and external controls, which is used as a comparator in the analysis.
The commensurate.cont
returns a list containing the following objects:
reject |
Data frame containing results of Bayesian one-sided hypothesis
testing (whether or not the posterior probability that the log odds ratio
is greater or less than 0 exceeds 1 minus significance level): |
theta |
Data frame containing posterior mean, median, and sd of log odds ratio. |
stan.obj |
Stanfit object. |
Hobbs BP, Carlin BP, Mandrekar SJ, Sargent DJ. Hierarchical commensurate and power prior models for adaptive incorporation of historical information in clinical trials. Biometrics 2011; 67:1047-1056.
Hobbs BP, Sargent DJ, Carlin BP. Commensurate priors for incorporating historical information in clinical trials using general and generalized linear models. Bayesian Analysis 2012; 7:639-674.
n.CT <- 100 n.CC <- 50 n.ECp <- 200 out.prob.CT <- 0.2 out.prob.CC <- 0.2 driftOR <- 1.0 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.9,0.9) indata <- trial.simulation.bin( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, out.prob.CT=out.prob.CT, out.prob.CC=out.prob.CC, driftOR=driftOR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect) n.EC <- 50 method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL out.psmatch <- psmatch( study~cov1+cov2, data=indata, n.EC=n.EC, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder) indata.match <- rbind(indata[indata$study==1,],indata[out.psmatch$subjid.EC,]) method.borrow <- list(list(prior="cauchy",scale=2.0), list(prior="normal",scale=0.5)) commensurate.bin(y~cov1,data=indata.match,method.borrow=method.borrow,chains=1,iter=100)
n.CT <- 100 n.CC <- 50 n.ECp <- 200 out.prob.CT <- 0.2 out.prob.CC <- 0.2 driftOR <- 1.0 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.9,0.9) indata <- trial.simulation.bin( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, out.prob.CT=out.prob.CT, out.prob.CC=out.prob.CC, driftOR=driftOR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect) n.EC <- 50 method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL out.psmatch <- psmatch( study~cov1+cov2, data=indata, n.EC=n.EC, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder) indata.match <- rbind(indata[indata$study==1,],indata[out.psmatch$subjid.EC,]) method.borrow <- list(list(prior="cauchy",scale=2.0), list(prior="normal",scale=0.5)) commensurate.bin(y~cov1,data=indata.match,method.borrow=method.borrow,chains=1,iter=100)
Bayesian analysis for continuous outcome is implemented via MCMC, where a commensurate prior is used for incorporating data from external controls. No borrowing and full borrowing are also applicable.
commensurate.cont( formula, data, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, seed=sample.int(.Machine$integer.max,1))
commensurate.cont( formula, data, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, seed=sample.int(.Machine$integer.max,1))
formula |
Object of class |
data |
Data frame, which must have variables named |
method.borrow |
List of information borrowing method. |
chains |
Number of Markov chains in MCMC sampling. The default value is
|
iter |
Number of iterations for each chain (including warmup) in MCMC
sampling. The default value is |
warmup |
Number of warmup (aka burnin) iterations per chain in MCMC
sampling. The default value is |
thin |
Period for saving samples in MCMC sampling. The default value
is |
alternative |
Alternative hypothesis to be tested ("greater" or "less").
The default value is |
sig.level |
Significance level. The default value is
|
seed |
Setting a seed for MCMC sampling. |
The continuous outcome is assumed to follow a normal distribution. Given more than one covariates, a normal linear regression model is built and its Bayesian estimation is performed via MCMC. Commensurate prior is used to dynamically discount the information to be borrowed from external control based on the similarity between the current trial and external controls, where the commensurability parameter determines the extent of borrowing. The commensurability parameter is assumed to follow a half-cauchy or a half-normal distribution, and its scale parameter needs to be carefully specified. No borrowing approach is to perform the analysis without incorporating the external controls. Full borrowing approach is just to pool the concurrent and external controls, which is used as a comparator in the analysis.
The commensurate.cont
returns a list containing the following objects:
reject |
Data frame containing results of Bayesian one-sided hypothesis
testing (whether or not the posterior probability that the mean difference
is greater or less than 0 exceeds 1 minus significance level): |
theta |
Data frame containing posterior mean, median, and sd of mean difference. |
stan.obj |
Stanfit object. |
Hobbs BP, Carlin BP, Mandrekar SJ, Sargent DJ. Hierarchical commensurate and power prior models for adaptive incorporation of historical information in clinical trials. Biometrics 2011; 67:1047-1056.
Hobbs BP, Sargent DJ, Carlin BP. Commensurate priors for incorporating historical information in clinical trials using general and generalized linear models. Bayesian Analysis 2012; 7:639-674.
n.CT <- 100 n.CC <- 50 n.ECp <- 200 out.mean.CT <- 0 out.sd.CT <- 1 out.mean.CC <- 0 out.sd.CC <- 1 driftdiff <- 0 out.sd.EC <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.1,0.1) indata <- trial.simulation.cont( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, out.mean.CT=out.mean.CT, out.sd.CT=out.sd.CT, out.mean.CC=out.mean.CC, out.sd.CC=out.sd.CC, driftdiff=driftdiff, out.sd.EC=out.sd.EC, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect) n.EC <- 50 method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL out.psmatch <- psmatch( study~cov1+cov2, data=indata, n.EC=n.EC, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder) indata.match <- rbind(indata[indata$study==1,],indata[out.psmatch$subjid.EC,]) method.borrow <- list(list(prior="cauchy",scale=2.0), list(prior="normal",scale=0.5)) commensurate.cont(y~cov1,data=indata.match,method.borrow=method.borrow,chains=1,iter=100)
n.CT <- 100 n.CC <- 50 n.ECp <- 200 out.mean.CT <- 0 out.sd.CT <- 1 out.mean.CC <- 0 out.sd.CC <- 1 driftdiff <- 0 out.sd.EC <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.1,0.1) indata <- trial.simulation.cont( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, out.mean.CT=out.mean.CT, out.sd.CT=out.sd.CT, out.mean.CC=out.mean.CC, out.sd.CC=out.sd.CC, driftdiff=driftdiff, out.sd.EC=out.sd.EC, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect) n.EC <- 50 method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL out.psmatch <- psmatch( study~cov1+cov2, data=indata, n.EC=n.EC, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder) indata.match <- rbind(indata[indata$study==1,],indata[out.psmatch$subjid.EC,]) method.borrow <- list(list(prior="cauchy",scale=2.0), list(prior="normal",scale=0.5)) commensurate.cont(y~cov1,data=indata.match,method.borrow=method.borrow,chains=1,iter=100)
Bayesian analysis for time-to-event outcome is implemented via MCMC, where a commensurate prior is used for incorporating data from external controls. No borrowing and full borrowing are also applicable.
commensurate.t2e( formula, data, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, seed=sample.int(.Machine$integer.max,1))
commensurate.t2e( formula, data, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, seed=sample.int(.Machine$integer.max,1))
formula |
Object of class |
data |
Data frame, which must have variables named |
method.borrow |
List of information borrowing method. |
chains |
Number of Markov chains in MCMC sampling. The default value is
|
iter |
Number of iterations for each chain (including warmup) in MCMC
sampling. The default value is |
warmup |
Number of warmup (burnin) iterations per chain in MCMC
sampling. The default value is |
thin |
Period for saving samples in MCMC sampling. The default value
is |
alternative |
Alternative hypothesis to be tested ("greater" or "less").
The default value is |
sig.level |
Significance level. The default value is
|
seed |
Setting a seed for MCMC sampling. |
The time to event outcome is assumed to follow a Weibull distribution. Given more than one covariates, a Weibull proportional hazards model is built and its Bayesian estimation is performed via MCMC. Commensurate prior is used to dynamically discount the information to be borrowed from external control based on the similarity between the current trial and external controls, where the commensurability parameter determines the extent of borrowing. The commensurability parameter is assumed to follow a half-cauchy or a half-normal distribution, and its scale parameter needs to be carefully specified. No borrowing approach is to perform the analysis without incorporating the external controls. Full borrowing approach is just to pool the concurrent and external controls, which is used as a comparator in the analysis.
The commensurate.t2e
returns a list containing the following objects:
reject |
Data frame containing results of Bayesian one-sided hypothesis
testing (whether or not the posterior probability that the log hazard ratio
is greater or less than 0 exceeds 1 minus significance level): |
theta |
Data frame containing posterior mean, median, and sd of log hazard ratio. |
stan.obj |
Stanfit object. |
Hobbs BP, Carlin BP, Mandrekar SJ, Sargent DJ. Hierarchical commensurate and power prior models for adaptive incorporation of historical information in clinical trials. Biometrics 2011; 67:1047-1056.
Hobbs BP, Sargent DJ, Carlin BP. Commensurate priors for incorporating historical information in clinical trials using general and generalized linear models. Bayesian Analysis 2012; 7:639-674.
n.CT <- 100 n.CC <- 50 nevent.C <- 100 n.ECp <- 200 nevent.ECp <- 180 accrual <- 16 out.mevent.CT <- 6 out.mevent.CC <- 6 driftHR <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.9,0.9) indata <- trial.simulation.t2e( n.CT=n.CT, n.CC=n.CC, nevent.C=nevent.C, n.ECp=n.ECp, nevent.ECp=nevent.ECp, accrual=accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect) n.EC <- 50 method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL out.psmatch <- psmatch( study~cov1+cov2, data=indata, n.EC=n.EC, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder) indata.match <- rbind(indata[indata$study==1,],indata[out.psmatch$subjid.EC,]) method.borrow <- list(list(prior="cauchy",scale=2.0), list(prior="normal",scale=0.5)) commensurate.t2e( survival::Surv(time,status)~cov1+cov2,data=indata.match, method.borrow=method.borrow,chains=1,iter=100)
n.CT <- 100 n.CC <- 50 nevent.C <- 100 n.ECp <- 200 nevent.ECp <- 180 accrual <- 16 out.mevent.CT <- 6 out.mevent.CC <- 6 driftHR <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.9,0.9) indata <- trial.simulation.t2e( n.CT=n.CT, n.CC=n.CC, nevent.C=nevent.C, n.ECp=n.ECp, nevent.ECp=nevent.ECp, accrual=accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect) n.EC <- 50 method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL out.psmatch <- psmatch( study~cov1+cov2, data=indata, n.EC=n.EC, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder) indata.match <- rbind(indata[indata$study==1,],indata[out.psmatch$subjid.EC,]) method.borrow <- list(list(prior="cauchy",scale=2.0), list(prior="normal",scale=0.5)) commensurate.t2e( survival::Surv(time,status)~cov1+cov2,data=indata.match, method.borrow=method.borrow,chains=1,iter=100)
Multivariate correlated data are generated. Gaussian copula is used to specify the correlation between variables. Any probability distributions available in R STAT is applicable.
datagen(margdist, corvec, nsim)
datagen(margdist, corvec, nsim)
margdist |
List of distributions to be used for the data generation. |
corvec |
Vector of Gaussian copula correlation parameter. |
nsim |
Number of simulation. |
Data drawn from a multivariate distribution specified.
Simulation study is conducted to assess operating characteristics of hybrid control design with Bayesian dynamic borrowing, where the concurrent control is augmented by external control. The external controls are selected from external control pool using a propensity score matching. Commensurate power prior is used for Bayesian dynamic borrowing. The binary outcome is applicable.
psborrow.bin( n.CT, n.CC, n.ECp, n.EC, out.prob.CT, out.prob.CC, driftOR, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, psmatch.cov, method.psest="glm", method.pslink="logit", method.whomatch, method.matching, method.psorder, n.boot=100, analysis.cov, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, nsim)
psborrow.bin( n.CT, n.CC, n.ECp, n.EC, out.prob.CT, out.prob.CC, driftOR, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, psmatch.cov, method.psest="glm", method.pslink="logit", method.whomatch, method.matching, method.psorder, n.boot=100, analysis.cov, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, nsim)
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
n.EC |
Number of patients in external control. |
out.prob.CT |
True rate of outcome in treatment group in the current trial. |
out.prob.CC |
True rate of outcome in concurrent control group in the current trial. |
driftOR |
Odds ratio between concurrent and external control for which the bias should be plotted (odds in external control divided by odds in concurrent control). |
cov.C |
List of covariate distributions for treatment and concurrent
control group in the current trial. Continuous and binary covariate are
applicable. The continuous covariate is assumed to follow a normal
distribution; for example, specified as
|
cov.cor.C |
Matrix of correlation coefficients for each pair of covariate for treatment and concurrent control group in the current trial, specified as Gaussian copula parameter. |
cov.EC |
List of covariate distributions for external control. The
continuous covariate is assumed to follow a normal distribution; for example,
specified as |
cov.cor.EC |
Matrix of correlation coefficients for each pair of covariate for external control, specified as Gaussian copula parameter. |
cov.effect |
Vector of covariate effects on the outcome, specified as odds ratio per one unit increase in continuous covariates or as odds ratio between categories for binary covariates. |
psmatch.cov |
Vector of names of covariates which are used for the
propensity score matching. The names of covariates must be included in
|
method.psest |
Method of estimating the propensity score. Allowable
options include, for example, |
method.pslink |
Link function used in estimating the propensity score.
Allowable options depend on the specific |
method.whomatch |
Options of who to match. Allowable options include
|
method.matching |
Matching method. Allowable options include
|
method.psorder |
Order that the matching takes place when a nearest
neighbor matching is used. Allowable options include |
n.boot |
Number of bootstrap sampling, which must be specified when
|
analysis.cov |
Vector of names of covariates which are used for the
Bayesian analysis with commensurate prior. The names of covariates must be
included in |
method.borrow |
List of information borrowing method. |
chains |
Number of Markov chains in MCMC sampling. The default value is
|
iter |
Number of iterations for each chain (including warmup) in MCMC
sampling. The default value is |
warmup |
Number of warmup (burnin) iterations per chain in MCMC
sampling. The default value is |
thin |
Period for saving samples in MCMC sampling. The default value
is |
alternative |
Alternative hypothesis to be tested ("greater" or "less").
The default value is |
sig.level |
Significance level. The default value is
|
nsim |
Number of simulated trials. |
The simulation study consists of three part: data generation
conducted by trial.simulation.bin
function, propensity score matching
conducted by psmatch
function, and Bayesian analysis with commensurate
prior conducted by commensurate.bin
function. Users can specify
different sets of covariates for the propensity score matching and the
Bayesian analysis.
The psborrow.bin
returns a list containing the following objects:
reject |
Data frame containing results of Bayesian one-sided hypothesis
testing (whether or not the posterior probability that the log odds ratio
is greater or less than 0 exceeds 1 minus significance level): |
theta |
Data frame containing posterior mean, median, and sd of log odds ratio. |
ov |
Data frame containing (1) overlapping coefficient of propensity score densities between treatment versus concurrent control plus external control and between concurrent control versus external control, (2) overlapping coefficient of continuous covariate densities between treatment versus concurrent control plus external control and between concurrent control versus external control, and (3) rate difference of binary covariate between treatment versus concurrent control plus external control and between concurrent control versus external control. |
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
n.EC |
Number of patients in external control. |
drift |
Odds ratio between concurrent and external control. |
true.theta |
True log odds ratio |
method.psest |
Method of estimating the propensity score. |
method.pslink |
Link function used in estimating the propensity score. |
method.whomatch |
Option of who to match. |
method.matching |
Propensity score matching method. |
method.psorder |
Order that the matching takes place when a nearest neighbor matching is used. |
n.CT <- 100 n.CC <- 50 n.ECp <- 200 n.EC <- 50 out.prob.CT <- 0.2 out.prob.CC <- 0.2 driftOR <- 1.0 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.9,0.9) psmatch.cov <- c("cov1","cov2") method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL analysis.cov <- c("cov1") method.borrow <- list(list(prior="noborrow"), list(prior="normal",scale=0.5)) nsim <- 5 psborrow.bin( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, n.EC=n.EC, out.prob.CT=out.prob.CT, out.prob.CC=out.prob.CC, driftOR=driftOR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, psmatch.cov=psmatch.cov, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder, analysis.cov=analysis.cov, method.borrow=method.borrow, chains=1, iter=100, nsim=nsim)
n.CT <- 100 n.CC <- 50 n.ECp <- 200 n.EC <- 50 out.prob.CT <- 0.2 out.prob.CC <- 0.2 driftOR <- 1.0 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.9,0.9) psmatch.cov <- c("cov1","cov2") method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL analysis.cov <- c("cov1") method.borrow <- list(list(prior="noborrow"), list(prior="normal",scale=0.5)) nsim <- 5 psborrow.bin( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, n.EC=n.EC, out.prob.CT=out.prob.CT, out.prob.CC=out.prob.CC, driftOR=driftOR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, psmatch.cov=psmatch.cov, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder, analysis.cov=analysis.cov, method.borrow=method.borrow, chains=1, iter=100, nsim=nsim)
Simulation study is conducted to assess operating characteristics of hybrid control design with Bayesian dynamic borrowing, where the concurrent control is augmented by external control. The external controls are selected from external control pool using a propensity score matching. Commensurate power prior is used for Bayesian dynamic borrowing. The continuous outcome is applicable.
psborrow.cont( n.CT, n.CC, n.ECp, n.EC, out.mean.CT, out.sd.CT, out.mean.CC, out.sd.CC, driftdiff, out.sd.EC, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, psmatch.cov, method.psest="glm", method.pslink="logit", method.whomatch, method.matching, method.psorder, n.boot=100, analysis.cov, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, nsim)
psborrow.cont( n.CT, n.CC, n.ECp, n.EC, out.mean.CT, out.sd.CT, out.mean.CC, out.sd.CC, driftdiff, out.sd.EC, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, psmatch.cov, method.psest="glm", method.pslink="logit", method.whomatch, method.matching, method.psorder, n.boot=100, analysis.cov, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, nsim)
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
n.EC |
Number of patients in external control. |
out.mean.CT |
True mean of outcome in treatment group in the current trial. |
out.sd.CT |
True sd of outcome in treatment group in the current trial. |
out.mean.CC |
True mean of outcome in concurrent control group in the current trial. |
out.sd.CC |
True as of outcome in concurrent control group in the current trial. |
driftdiff |
Mean difference between concurrent and external control for which the bias should be plotted (mean in external control minus mean in concurrent control). |
out.sd.EC |
True as of outcome in external control. |
cov.C |
List of covariate distributions for treatment and concurrent
control group in the current trial. Continuous and binary covariate are
applicable. The continuous covariate is assumed to follow a normal
distribution; for example specified as
|
cov.cor.C |
Matrix of correlation coefficients for each pair of covariate for treatment and concurrent control group in the current trial, specified as Gaussian copula parameter. |
cov.EC |
List of covariate distributions for external control. The
continuous covariate is assumed to follow a normal distribution; for example,
specified as |
cov.cor.EC |
Matrix of correlation coefficients for each pair of covariate for external control, specified as Gaussian copula parameter. |
cov.effect |
Vector of covariate effects on the outcome, specified as mean change per one unit increase in continuous covariates or as mean change between categories for binary covariates. |
psmatch.cov |
Vector of names of covariates which are used for the
propensity score matching. The names of covariates must be included in
|
method.psest |
Method of estimating the propensity score. Allowable
options include, for example, |
method.pslink |
Link function used in estimating the propensity score.
Allowable options depend on the specific |
method.whomatch |
Options of who to match. Allowable options include
|
method.matching |
Matching method. Allowable options include
|
method.psorder |
Order that the matching takes place when a nearest
neighbor matching is used. Allowable options include |
n.boot |
Number of bootstrap sampling, which must be specified when
|
analysis.cov |
Vector of names of covariates which are used for the
Bayesian analysis with commensurate prior. The names of covariates must be
included in |
method.borrow |
List of information borrowing method. |
chains |
Number of Markov chains in MCMC sampling. The default value is
|
iter |
Number of iterations for each chain (including warmup) in MCMC
sampling. The default value is |
warmup |
Number of warmup (burnin) iterations per chain in MCMC
sampling. The default value is |
thin |
Period for saving samples in MCMC sampling. The default value
is |
alternative |
Alternative hypothesis to be tested ("greater" or "less").
The default value is |
sig.level |
Significance level. The default value is
|
nsim |
Number of simulated trials. |
The simulation study consists of three part: data generation
conducted by trial.simulation.cont
function, propensity score matching
conducted by psmatch
function, and Bayesian analysis with commensurate
prior conducted by commensurate.cont
function. Users can specify
different sets of covariates for the propensity score matching and the
Bayesian analysis.
The psborrow.cont
returns a list containing the following objects:
reject |
Data frame containing results of Bayesian one-sided hypothesis
testing (whether or not the posterior probability that the mean difference
is greater or less than 0 exceeds 1 minus significance level): |
theta |
Data frame containing posterior mean, median, and sd of mean difference. |
ov |
Data frame containing (1) overlapping coefficient of propensity score densities between treatment versus concurrent control plus external control and between concurrent control versus external control, (2) overlapping coefficient of continuous covariate densities between treatment versus concurrent control plus external control and between concurrent control versus external control, and (3) rate difference of binary covariate between treatment versus concurrent control plus external control and between concurrent control versus external control. |
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
n.EC |
Number of patients in external control. |
drift |
Mean difference between concurrent and external control. |
true.theta |
True mean difference |
method.psest |
Method of estimating the propensity score. |
method.pslink |
Link function used in estimating the propensity score. |
method.whomatch |
Option of who to match. |
method.matching |
Propensity score matching method. |
method.psorder |
Order that the matching takes place when a nearest neighbor matching is used. |
n.CT <- 100 n.CC <- 50 n.ECp <- 200 n.EC <- 50 out.mean.CT <- 0 out.sd.CT <- 1 out.mean.CC <- 0 out.sd.CC <- 1 driftdiff <- 0 out.sd.EC <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.1,0.1) psmatch.cov <- c("cov1","cov2") method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL analysis.cov <- c("cov1") method.borrow <- list(list(prior="noborrow"), list(prior="normal",scale=0.5)) nsim <- 5 psborrow.cont( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, n.EC=n.EC, out.mean.CT=out.mean.CT, out.sd.CT=out.sd.CT, out.mean.CC=out.mean.CC, out.sd.CC=out.sd.CC, driftdiff=driftdiff, out.sd.EC=out.sd.EC, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, psmatch.cov=psmatch.cov, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder, analysis.cov=analysis.cov, method.borrow=method.borrow, chains=1, iter=100, nsim=nsim)
n.CT <- 100 n.CC <- 50 n.ECp <- 200 n.EC <- 50 out.mean.CT <- 0 out.sd.CT <- 1 out.mean.CC <- 0 out.sd.CC <- 1 driftdiff <- 0 out.sd.EC <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.1,0.1) psmatch.cov <- c("cov1","cov2") method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL analysis.cov <- c("cov1") method.borrow <- list(list(prior="noborrow"), list(prior="normal",scale=0.5)) nsim <- 5 psborrow.cont( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, n.EC=n.EC, out.mean.CT=out.mean.CT, out.sd.CT=out.sd.CT, out.mean.CC=out.mean.CC, out.sd.CC=out.sd.CC, driftdiff=driftdiff, out.sd.EC=out.sd.EC, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, psmatch.cov=psmatch.cov, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder, analysis.cov=analysis.cov, method.borrow=method.borrow, chains=1, iter=100, nsim=nsim)
Simulation study results are summarized.
psborrow.summary(object)
psborrow.summary(object)
object |
List of simulation results. |
The psborrow.summary
returns a list containing the following objects:
res.out |
Data frame containing (1) rate that the null hypothesis is
rejected in Bayesian one-sided hypothesis testing, (2) bias in posterior mean
of treatment effect (log hazard ratio, log odds ratio, or mean difference),
(3) empirical standard deviation ( |
res.cov |
Data frame containing (1) mean, median, and standard deviation of overlapping coefficients of propensity score densities between treatment versus concurrent control plus external control and between concurrent control versus external control, (2) mean, median, and standard deviation of overlapping coefficients of continuous covariate densities between treatment versus concurrent control plus external control and between concurrent control versus external control, and (3) mean, median, and standard deviation of rate differences of binary covariate between treatment versus concurrent control plus external control and between concurrent control versus external control. |
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
n.EC |
Number of patients in external control. |
drift |
Hazard ratio, odds ratio, or mean difference between concurrent and external control for which the bias should be plotted. The measure depends on the outcome type. |
method.psest |
Method of estimating the propensity score. |
method.pslink |
Link function used in estimating the propensity score. |
method.whomatch |
Options of who to match. |
method.matching |
Matching method. |
method.psorder |
Order that the matching takes place when a nearest neighbor matching is used. |
Simulation study is conducted to assess operating characteristics of hybrid control design with Bayesian dynamic borrowing, where the concurrent control is augmented by external control. The external controls are selected from external control pool using a propensity score matching. Commensurate power prior is used for Bayesian dynamic borrowing. The time-to-event outcome is applicable.
psborrow.t2e( n.CT, n.CC, nevent.C, n.ECp, nevent.ECp, n.EC, accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, psmatch.cov, method.psest="glm", method.pslink="logit", method.whomatch, method.matching, method.psorder, n.boot=100, analysis.cov, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, nsim)
psborrow.t2e( n.CT, n.CC, nevent.C, n.ECp, nevent.ECp, n.EC, accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, psmatch.cov, method.psest="glm", method.pslink="logit", method.whomatch, method.matching, method.psorder, n.boot=100, analysis.cov, method.borrow, chains=2, iter=4000, warmup=floor(iter/2), thin=1, alternative="greater", sig.level=0.025, nsim)
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
nevent.C |
Number of events in treatment and concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
nevent.ECp |
Number of events in external control pool. |
n.EC |
Number of patients in external control. |
accrual |
Accrual rate, defined as the number of enrolled patients per month. |
out.mevent.CT |
True median time to event in treatment group in the current trial. |
out.mevent.CC |
True median time to event in concurrent control group in the current trial. |
driftHR |
Hazard ratio between concurrent and external control for which the bias should be plotted (hazard in external control divided by hazard in concurrent control). |
cov.C |
List of covariate distributions for treatment and concurrent
control group in the current trial. Continuous and binary covariate are
applicable. The continuous covariate is assumed to follow a normal
distribution; for example, specified as
|
cov.cor.C |
Matrix of correlation coefficients for each pair of covariate for treatment and concurrent control group in the current trial, specified as Gaussian copula parameter. |
cov.EC |
List of covariate distributions for external control. The
continuous covariate is assumed to follow a normal distribution; for example,
specified as |
cov.cor.EC |
Matrix of correlation coefficients for each pair of covariate for external control, specified as Gaussian copula parameter. |
cov.effect |
Vector of covariate effects on the outcome, specified as hazard ratio per one unit increase in continuous covariate or as hazard ratio between categories for binary covariate. |
psmatch.cov |
Vector of names of covariates which are used for the
propensity score matching. The names of covariates must be included in
|
method.psest |
Method of estimating the propensity score. Allowable
options include, for example, |
method.pslink |
Link function used in estimating the propensity score.
Allowable options depend on the specific |
method.whomatch |
Options of who to match. Allowable options include
|
method.matching |
Matching method. Allowable options include
|
method.psorder |
Order that the matching takes place when a nearest
neighbor matching is used. Allowable options include |
n.boot |
Number of bootstrap sampling, which must be specified when
|
analysis.cov |
Vector of names of covariates which are used for the
Bayesian analysis with commensurate prior. The names of covariates must be
included in |
method.borrow |
List of information borrowing method. |
chains |
Number of Markov chains in MCMC sampling. The default value is
|
iter |
Number of iterations for each chain (including warmup) in MCMC
sampling. The default value is |
warmup |
Number of warmup (burnin) iterations per chain in MCMC
sampling. The default value is |
thin |
Period for saving samples in MCMC sampling. The default value
is |
alternative |
Alternative hypothesis to be tested ("greater" or "less").
The default value is |
sig.level |
Significance level. The default value is
|
nsim |
Number of simulated trials. |
The simulation study consists of three part: data generation
conducted by trial.simulation.t2e
function, propensity score matching
conducted by psmatch
function, and Bayesian analysis with commensurate
prior conducted by commensurate.t2e
function. Users can specify
different sets of covariates for the propensity score matching and the
Bayesian analysis.
The psborrow.t2e
returns a list containing the following objects:
reject |
Data frame containing results of Bayesian one-sided hypothesis
testing (whether or not the posterior probability that the log hazard ratio
is greater or less than 0 exceeds 1 minus significance level): |
theta |
Data frame containing posterior mean, median, and sd of log hazard ratio. |
ov |
Data frame containing (1) overlapping coefficient of propensity score densities between treatment versus concurrent control plus external control and between concurrent control versus external control, (2) overlapping coefficient of continuous covariate densities between treatment versus concurrent control plus external control and between concurrent control versus external control, and (3) rate difference of binary covariate between treatment versus concurrent control plus external control and between concurrent control versus external control. |
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
n.EC |
Number of patients in external control. |
drift |
Hazard ratio between concurrent and external control. |
true.theta |
True log hazard ratio |
method.psest |
Method of estimating the propensity score. |
method.pslink |
Link function used in estimating the propensity score. |
method.whomatch |
Option of who to match. |
method.matching |
Propensity score matching method. |
method.psorder |
Order that the matching takes place when a nearest neighbor matching is used. |
n.CT <- 100 n.CC <- 50 nevent.C <- 100 n.ECp <- 200 nevent.ECp <- 180 n.EC <- 50 accrual <- 16 out.mevent.CT <- 6 out.mevent.CC <- 6 driftHR <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.9,0.9) psmatch.cov <- c("cov1","cov2") method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL analysis.cov <- c("cov1") method.borrow <- list(list(prior="noborrow"), list(prior="normal",scale=0.5)) nsim <- 5 psborrow.t2e( n.CT=n.CT, n.CC=n.CC, nevent.C=nevent.C, n.ECp=n.ECp, nevent.ECp=nevent.ECp, n.EC=n.EC, accrual=accrual, out.mevent.CT=out.mevent.CT, out.mevent.CC=out.mevent.CC, driftHR=driftHR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, psmatch.cov=psmatch.cov, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder, analysis.cov=analysis.cov, method.borrow=method.borrow, chains=1, iter=100, nsim=nsim)
n.CT <- 100 n.CC <- 50 nevent.C <- 100 n.ECp <- 200 nevent.ECp <- 180 n.EC <- 50 accrual <- 16 out.mevent.CT <- 6 out.mevent.CC <- 6 driftHR <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.9,0.9) psmatch.cov <- c("cov1","cov2") method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL analysis.cov <- c("cov1") method.borrow <- list(list(prior="noborrow"), list(prior="normal",scale=0.5)) nsim <- 5 psborrow.t2e( n.CT=n.CT, n.CC=n.CC, nevent.C=nevent.C, n.ECp=n.ECp, nevent.ECp=nevent.ECp, n.EC=n.EC, accrual=accrual, out.mevent.CT=out.mevent.CT, out.mevent.CC=out.mevent.CC, driftHR=driftHR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, psmatch.cov=psmatch.cov, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder, analysis.cov=analysis.cov, method.borrow=method.borrow, chains=1, iter=100, nsim=nsim)
Propensity score matching is implemented to select external controls who are more relevant to patients in the current trial with respect to covariates of interest.
psmatch( formula, data, n.EC, method.psest="glm", method.pslink="logit", method.whomatch, method.matching, method.psorder, n.boot=100)
psmatch( formula, data, n.EC, method.psest="glm", method.pslink="logit", method.whomatch, method.matching, method.psorder, n.boot=100)
formula |
Object of class |
data |
Data frame, which must contain variables named |
n.EC |
Number of patients in external control to be selected, which must be smaller than the number of patients in external control pool. |
method.psest |
Method of estimating the propensity score. Allowable
options include, for example, |
method.pslink |
Link function used in estimating the propensity score.
Allowable options depend on the specific |
method.whomatch |
Options of who to match. Allowable options include
|
method.matching |
Propensity score matching method. Allowable options include
|
method.psorder |
Order that the matching takes place when a nearest
neighbor matching is used. Allowable options include |
n.boot |
Number of bootstrap sampling, which must be specified when
|
The propensity score is defined as the conditional probability of
having been included in the current trial given observed covariates. There
are four options applicable for to whom the patients in external control
pool are matched, including (i) concurrent control versus external control
pool ("conc.contl"
), (ii) treatment versus external control pool
("conc.treat"
), (iii) treatment plus concurrent control versus
external control pool ("conc.all"
), and (iv) treatment versus
concurrent control plus external control pool ("treat2contl"
).
Along with method.whomatch="conc.contl"
, two 1:1 matching methods are
applicable: (1) optimal matching ("optimal"
), and (2) nearest neighbor
matching without caliper ("nearest"
). Along with
method.whomatch="conc.treat"
or method.whomatch="conc.all"
,
ten matching methods are applicable: (1) optimal matching, where 1:1
matching is first done, followed by random sampling ("optimal"
),
(2) nearest neighbor matching, where caliper is tuned iteratively
to obtain the fixed number of external controls ("nearest"
), (3)
equally splitting patients in the current trial and taking the median of
each subset, followed by 1:1 optimal matching ("medm.optimal"
), (4)
equally splitting patients in the current trial and taking the median of
each subset, followed by 1:1 nearest neighbor matching matching
("med.nearest"
), (5) k-means clustering of patients in the current
trial, followed by 1:1 optimal matching ("km.optimal"
), (6) k-means
clustering of patients in the current trial, followed by 1:1 nearest neighbor
matching ("km.nearest"
), (7) fuzzy c-means clustering of patients in
the current trial, followed by 1:1 optimal matching ("cm.optimal"
),
(8) fuzzy c-means of patients in the current trial, followed by 1:1 nearest
neighbor matching ("cm.nearest"
), (9) bootstrap sampling from patients
in the current trial, followed by 1:1 optimal matching
("boot.nearest"
), and (10) bootstrap sampling from patient in the
current trial, followed by 1:1 nearest neighbor matching
("boot.nearest"
). Along with method.whomatch="treat2contl"
,
two matching methods are applicable: (1) optimal matching, followed by
random sampling ("optimal"
), and (2) nearest neighbor matching, where
caliper is tuned iteratively to obtain the fixed number of external controls
("nearest"
).
The psmatch
returns a list containing the following objects:
subjid.EC |
Vector of subject ID of external control. |
data.ps |
Data frame with estimated propensity score. |
Austin PC. A comparison of 12 algorithms for matching on the propensity score. Statistics in Medicine 2014; 33:1057-1069.
Lin J, Gamalo-Siebers M, Tiwari R. Propensity score matched augmented controls in randomized clinical trials: A case study. Pharmaceutical Statistics 2018; 17:629-647.
Lin J, Gamalo-Siebers M, Tiwari R. Propensity-score-based priors for Bayesian augmented control design. Pharmaceutical Statistics 2019; 18:223-238.
Rosenbaum PR. Optimal matching for observational studies. Journal of the American Statistical Association 1989; 84:1024-1032.
Sawamoto R, Oba K, Matsuyama Y. Bayesian adaptive randomization design incorporating propensity score-matched historical controls. Pharmaceutical Statistics 2022; 21:1074-1089.
n.CT <- 100 n.CC <- 50 nevent.C <- 100 n.ECp <- 1000 nevent.ECp <- 800 accrual <- 16 out.mevent.CT <- 6 out.mevent.CC <- 6 driftHR <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.1,0.1) indata <- trial.simulation.t2e( n.CT=n.CT, n.CC=n.CC, nevent.C=nevent.C, n.ECp=n.ECp, nevent.ECp=nevent.ECp, accrual=accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect) n.EC <- 50 method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL psmatch( study~cov1+cov2, data=indata, n.EC=n.EC, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder)
n.CT <- 100 n.CC <- 50 nevent.C <- 100 n.ECp <- 1000 nevent.ECp <- 800 accrual <- 16 out.mevent.CT <- 6 out.mevent.CC <- 6 driftHR <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.1,0.1) indata <- trial.simulation.t2e( n.CT=n.CT, n.CC=n.CC, nevent.C=nevent.C, n.ECp=n.ECp, nevent.ECp=nevent.ECp, accrual=accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect) n.EC <- 50 method.whomatch <- "conc.treat" method.matching <- "optimal" method.psorder <- NULL psmatch( study~cov1+cov2, data=indata, n.EC=n.EC, method.whomatch=method.whomatch, method.matching=method.matching, method.psorder=method.psorder)
A two-arm randomized clinical trial with a binary outcome, which is augmented by external control data, is simulated.
trial.simulation.bin( n.CT, n.CC, n.ECp, out.prob.CT, out.prob.CC, driftOR, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, seed=sample.int(.Machine$integer.max,1))
trial.simulation.bin( n.CT, n.CC, n.ECp, out.prob.CT, out.prob.CC, driftOR, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, seed=sample.int(.Machine$integer.max,1))
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
out.prob.CT |
True rate of outcome in treatment group in the current trial. |
out.prob.CC |
True rate of outcome in concurrent control group in the current trial. |
driftOR |
Odds ratio between concurrent and external control for which the bias should be plotted (odds in external control divided by odds in concurrent control). |
cov.C |
List of covariate distributions for treatment and concurrent
control group in the current trial. Continuous and binary covariate are
applicable. The continuous covariate is assumed to follow a normal
distribution; for example, specified as
|
cov.cor.C |
Matrix of correlation coefficients for each pair of covariate for treatment and concurrent control in the current trial, specified as Gaussian copula parameter. |
cov.EC |
List of covariate distributions for external control. The
continuous covariate is assumed to follow a normal distribution; for example,
specified as |
cov.cor.EC |
Matrix of correlation coefficients for each pair of covariate for external control, specified as Gaussian copula parameter. |
cov.effect |
Vector of covariate effects on the outcome, specified as odds ratio per one unit increase in continuous covariates or as odds ratio between categories for binary covariates. |
seed |
Setting a seed. |
The binary outcome is assumed to follow a binomial distribution.
Given more than one covariates with their effects on the outcome, a logistic
regression model is constructed for data generation. The data frame
generated include the binary outcome data and covariates for n.CT
and n.CC
patients in treatment and concurrent control group in the
current trial respectively, and n.ECp
patients in external control
pool. One record per patient. More than one covariates must be specified.
The trial.simulation.bin
returns a data frame containing the
following variables:
study |
Study indicator (0 for external control, and 1 for current trial) |
treat |
Treatment indicator (0 for concurrent and external control, and 1 for treatment) |
y |
Binary outcome |
column name specified |
Covariate of interest |
n.CT <- 100 n.CC <- 50 n.ECp <- 1000 out.prob.CT <- 0.2 out.prob.CC <- 0.2 driftOR <- 1.0 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.8,0.8) trial.simulation.bin( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, out.prob.CT=out.prob.CT, out.prob.CC=out.prob.CC, driftOR=driftOR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, seed=100)
n.CT <- 100 n.CC <- 50 n.ECp <- 1000 out.prob.CT <- 0.2 out.prob.CC <- 0.2 driftOR <- 1.0 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.8,0.8) trial.simulation.bin( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, out.prob.CT=out.prob.CT, out.prob.CC=out.prob.CC, driftOR=driftOR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, seed=100)
A two-arm randomized clinical trial with a continuous outcome, which is augmented by external control data, is simulated.
trial.simulation.cont( n.CT, n.CC, n.ECp, out.mean.CT, out.sd.CT, out.mean.CC, out.sd.CC, driftdiff, out.sd.EC, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, seed=sample.int(.Machine$integer.max,1))
trial.simulation.cont( n.CT, n.CC, n.ECp, out.mean.CT, out.sd.CT, out.mean.CC, out.sd.CC, driftdiff, out.sd.EC, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, seed=sample.int(.Machine$integer.max,1))
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
out.mean.CT |
True mean of outcome in treatment group in the current trial. |
out.sd.CT |
True sd of outcome in treatment group in the current trial. |
out.mean.CC |
True mean of outcome in concurrent control group in the current trial. |
out.sd.CC |
True sd of outcome in concurrent control group in the current trial. |
driftdiff |
Mean difference between concurrent and external control for which the bias should be plotted (mean in external control minus mean in concurrent control). |
out.sd.EC |
True sd of outcome in external control. |
cov.C |
List of covariate distributions for treatment and concurrent
control group in the current trial. Continuous and binary covariate are
applicable. The continuous covariate is assumed to follow a normal
distribution; for example specified as
|
cov.cor.C |
Matrix of correlation coefficients for each pair of covariate for treatment and concurrent control group in the current trial, specified as Gaussian copula parameter. |
cov.EC |
List of covariate distributions for external control. The
continuous covariate is assumed to follow a normal distribution; for example,
specified as |
cov.cor.EC |
Matrix of correlation coefficients for each pair of covariate for external control, specified as Gaussian copula parameter. |
cov.effect |
Vector of covariate effects on the outcome, specified as mean change per one unit increase in continuous covariates or as mean change between categories for binary covariates. |
seed |
Setting a seed. |
The continuous outcome is assumed to follow a normal distribution.
Given more than one covariates with their effects on the outcome, a normal
linear regression model is constructed for data generation. The data frame
generated include the continuous outcome data and covariates for n.CT
and n.CC
patients in treatment and concurrent control group in the
current trial respectively, and n.ECp
patients in external control
pool. One record per patient. More than one covariates must be specified.
The trial.simulation.cont
returns a data frame containing the
following variables:
study |
Study indicator (0 for external control, and 1 for current trial) |
treat |
Treatment indicator (0 for concurrent and external control, and 1 for treatment) |
y |
Continuous outcome |
column name specified |
Covariate of interest |
n.CT <- 100 n.CC <- 50 n.ECp <- 1000 out.mean.CT <- 0 out.sd.CT <- 1 out.mean.CC <- 0 out.sd.CC <- 1 driftdiff <- 0 out.sd.EC <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.1,0.1) trial.simulation.cont( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, out.mean.CT=out.mean.CT, out.sd.CT=out.sd.CT, out.mean.CC=out.mean.CC, out.sd.CC=out.sd.CC, driftdiff=driftdiff, out.sd.EC=out.sd.EC, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, seed=100)
n.CT <- 100 n.CC <- 50 n.ECp <- 1000 out.mean.CT <- 0 out.sd.CT <- 1 out.mean.CC <- 0 out.sd.CC <- 1 driftdiff <- 0 out.sd.EC <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.1,0.1) trial.simulation.cont( n.CT=n.CT, n.CC=n.CC, n.ECp=n.ECp, out.mean.CT=out.mean.CT, out.sd.CT=out.sd.CT, out.mean.CC=out.mean.CC, out.sd.CC=out.sd.CC, driftdiff=driftdiff, out.sd.EC=out.sd.EC, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, seed=100)
A two-arm randomized clinical trial with a time-to-event outcome, which is augmented by external control data, is simulated.
trial.simulation.t2e( n.CT, n.CC, nevent.C, n.ECp, nevent.ECp, accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, seed=sample.int(.Machine$integer.max,1))
trial.simulation.t2e( n.CT, n.CC, nevent.C, n.ECp, nevent.ECp, accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C, cov.cor.C, cov.EC, cov.cor.EC, cov.effect, seed=sample.int(.Machine$integer.max,1))
n.CT |
Number of patients in treatment group in the current trial. |
n.CC |
Number of patients in concurrent control group in the current trial. |
nevent.C |
Number of events in treatment and concurrent control group in the current trial. |
n.ECp |
Number of patients in external control pool. |
nevent.ECp |
Number of events in external control pool. |
accrual |
Accrual rate, defined as the number of enrolled patients per month. |
out.mevent.CT |
True median time to event in treatment group in the current trial. |
out.mevent.CC |
True median time to event in concurrent control group in the current trial. |
driftHR |
Hazard ratio between concurrent and external control for which the bias should be plotted (hazard in external control divided by hazard in concurrent control). |
cov.C |
List of covariate distributions for treatment and concurrent
control group in the current trial. Continuous and binary covariate are
applicable. The continuous covariate is assumed to follow a normal
distribution; for example, specified as
|
cov.cor.C |
Matrix of correlation coefficients for each pair of covariate for treatment and concurrent control group in the current trial, specified as Gaussian copula parameter. |
cov.EC |
List of covariate distributions for external control. The
continuous covariate is assumed to follow a normal distribution; for example,
specified as |
cov.cor.EC |
Matrix of correlation coefficients for each pair of covariate for external control, specified as Gaussian copula parameter. |
cov.effect |
Vector of covariate effects on the outcome , specified as hazard ratio per one unit increase in continuous covariates or as hazard ratio between categories for binary covariates. |
seed |
Setting a seed. |
The time to event outcome is assumed to follow a Weibull
distribution. Given more than one covariates with their effects on the
outcome, a Weibull proportional hazards model is constructed for data
generation. The data frame generated include the time-to-event outcome data
and covariates for n.CT
and n.CC
patients in treatment and
concurrent control group in the current trial respectively, and n.ECp
patients in external control pool. One record per patient. More than one
covariates must be specified.
The trial.simulation.t2e
returns a data frame containing the
following variables:
study |
Study indicator (0 for external control, and 1 for current trial) |
treat |
Treatment indicator (0 for concurrent and external control, and 1 for treatment) |
time |
Time to event or censoring |
status |
Censoring (0 for censored, and 1 for event occurred) |
column name specified |
Covariate of interest |
n.CT <- 100 n.CC <- 50 nevent.C <- 100 n.ECp <- 1000 nevent.ECp <- 800 accrual <- 16 out.mevent.CT <- 6 out.mevent.CC <- 6 driftHR <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.8,0.8) trial.simulation.t2e( n.CT=n.CT, n.CC=n.CC, nevent.C=nevent.C, n.ECp=n.ECp, nevent.ECp=nevent.ECp, accrual=accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, seed=100)
n.CT <- 100 n.CC <- 50 nevent.C <- 100 n.ECp <- 1000 nevent.ECp <- 800 accrual <- 16 out.mevent.CT <- 6 out.mevent.CC <- 6 driftHR <- 1 cov.C <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.C <- rbind(c( 1,0.1), c(0.1, 1)) cov.EC <- list(list(dist="norm",mean=0,sd=1,lab="cov1"), list(dist="binom",prob=0.4,lab="cov2")) cov.cor.EC <- rbind(c( 1,0.1), c(0.1, 1)) cov.effect <- c(0.8,0.8) trial.simulation.t2e( n.CT=n.CT, n.CC=n.CC, nevent.C=nevent.C, n.ECp=n.ECp, nevent.ECp=nevent.ECp, accrual=accrual, out.mevent.CT, out.mevent.CC, driftHR, cov.C=cov.C, cov.cor.C=cov.cor.C, cov.EC=cov.EC, cov.cor.EC=cov.cor.EC, cov.effect=cov.effect, seed=100)