Eval=FALSE# set to TRUE for recompilation
knitr::opts_chunk$set(
    eval=Eval, 
    collapse = TRUE,
    comment = "#>",
    fig.width = 9,
    fig.height = 5,
    width=100
)

This vignette allows reproduction of the adaptive trial design presented in Wiesenfarth and Calderazzo (2019) similar to the design presented in Schmidli et. al (2014).

Specifically, a two arm Bayesian clinical trial design is considered, where it is assumed that prior information on the control arm exists. In this situation it is desirable to make use of this prior information to reduce the final sample size in the control group, while keeping operating characteristics close to an analysis with full sample size and without prior information. At the same time, robustness with respect to deviations from prior beliefs is aimed for.

With this in mind, the following adaptive randomization scheme has been proposed for designs which aims at adapting the final sample size in the control arm according to the information contained in the prior distribution, as measured at an interim analysis. Variants of this design have been studied by several authors. All of them consider some version of the EHSS as a measure of prior informativeness with priors which adapt to prior-data conflict.

In this context, we argue that the ECSS is intuitively more appropriate than the EHSS as it answers the question of how many control samples are offset by the prior after stage two, i.e. how many control patients are added or subtracted from the analysis by inclusion of prior information. In contrast, the prior ESS is independent of the currently observed control samples, while the data-dependent EHSS depends on the currently observed control samples according to a measure which may be problematic in situations of moderate conflict and is not among the trial's targets.

We simulate a two arm trial assuming normal outcomes $y_{control}\sim N(\mu_0,1)$ and $y_{treat}\sim N(\mu_0+\tau,1)$ for varying control means $\mu_0$ and effect sizes $\tau\in{0,0.28}$.

The following priors are considered: An informative prior $N(0,1/50)$, a baseline prior $N(0,10^2)$, a mixture of the two with equal component weights $0.5 N(0,1/50)+0.5 N(0,10^2)$ and power prior based on the informative prior $N(0,1/(\delta\cdot 50))$ where $\delta$ is estimated by empirical Bayes. Note that results for empirical Bayes power prior are equivalent to those under an empirical Bayes commensurate prior (see Wiesenfarth and Calderazzo, 2019). Variances are assumed to be known.

We conduct an interim analysis after 100 samples in each arm have been collected and compute the ESS in the control arm according to the different approaches. Then, additional 100 patients are recruited in the treatment arm while in the control arm we subtract from the target stage-two sample size of 100 a number of patients equal to the prior ESS measures.

At the end of the trial, we evaluate the MSE of $\tau$ and frequentist type I error and power for hypotheses $H_0: \tau\leq 0\mbox{ versus }H_1: \tau> 0$, as based on the posterior probability with decision threshold $c$, $P(\tau>0 | y_{treat},y_{control})> c$. We consider a common fixed decision threshold $c=0.975$. Thus, using the baseline prior, frequentist type I error is controlled at $2.5\%$ and power for $\tau=0.28$ is $80\%$.

A Monte Carlo simulation approach is used to allow visualization of variability in supplementary figures of the paper. Numerical integration may improve speed. Reproduction of results for binomial outcomes in Schmidli et. al (2014) can be achieved by replacing adaptiveDesign_normal() by adaptiveDesign_binomial() and appropriate adjustment of design settings.

Settings

library(foreach)
library(ESS)
library(ggplot2)
library(RBesT)
# Specify list of priors
  prior <- list()
  prior$inf  <- mixnorm(inf=c(1.0, 0,1/sqrt(50))) 
  prior$mix50 <-mixnorm(inf=c(0.5, 0,1/sqrt(50)), rob=c(0.5, 0,10))
  # if unit information prior as baseline prior should also be evaluated
  #prior$mix50unitInfo <-mixnorm(inf=c(0.5, 0,1/sqrt(50)), rob=c(0.5, 0,1))
  prior$vague  <- mixnorm(rob= c(1.0, 0,10))

# Specify vector of true control group means \mu_0
  muc.vec=(-33:33)/30 #(-44:44)/40 in paper
# Vector of effect sizes
  tau.vec=c(0,.28)

# number of patients enrolled to control and treatment in stage 1
  N1 = M1=100
# minimum of patients enrolled in control in stage 2
  Nmin <- 0#10
# target number of patients in control group
  Ntarget = 200
# target number of patients in treatment group (fixed)
  M =200

# Specify whether standard deviations in control (sc) and treatment group (st) 
#  are assumed to be known and their magnitudes
  sc.known=st.known=TRUE
  st=1
  sc=1

# decision function: P(x1 - x2 > 0) > 0.975
  dec <- decision2S(0.975, 0, lower.tail=FALSE)

# number of parallel CPUs
  cores=1
# number of Monte Carlo iterations (10,000 in paper)
  nsim=10


design=expand.grid(muc=muc.vec, delta=tau.vec)
cases.fix <- grep("mix", names(prior), value=TRUE, invert=TRUE)[-2]
cases.mix <- grep("mix", names(prior), value=TRUE, invert=F)

Computation

Compute the adaptive design for different EHSS approaches and store results as list objects.

obj.resEHSS.mix=list()
for (i in c(cases.fix,cases.mix,"vague")){
#  print(i)
  obj.resEHSS.mix[[i]]<-   
    adaptiveDesign_normal(
      ess = "ehss", ehss.method = "mix.moment", 
      ctl.prior=prior[[i]], treat.prior=prior$vague,
      N1=N1, Ntarget=Ntarget, Nmin=Nmin, M=M, 
      muc=design$muc, mut=design$muc+design$delta,
      sc=sc,st=st,sc.known=sc.known,st.known=st.known,
      discard.prior = TRUE,
      vague = prior$vague,
      decision=dec,
      nsim=nsim,cores=cores, seed = 123, progress = "none"
    )
}

obj.resEHSS.morita=list()
for (i in cases.mix ){
#  print(i)
  obj.resEHSS.morita[[i]]<-
    adaptiveDesign_normal(
      ess = "ehss", ehss.method = "morita", 
      ctl.prior=prior[[i]], treat.prior=prior$vague,
      N1=N1, Ntarget=Ntarget, Nmin=Nmin, M=M, 
      muc=design$muc, mut=design$muc+design$delta,
      sc=sc,st=st,sc.known=sc.known,st.known=st.known,
      discard.prior = TRUE,
      vague = prior$vague,
      decision=dec,
      nsim=nsim,cores=cores, seed = 123, progress = "none"
    )
}

obj.resEHSS.pp=list()
for (i in cases.fix){
 #   print(i)
    obj.resEHSS.pp[[i]]<-   
      adaptiveDesign_normal(
        ess = "ehss", ehss.method = "moment", 
        ctl.prior=as.powerprior(prior[[i]]), treat.prior=prior$vague,
        N1=N1, Ntarget=Ntarget, Nmin=Nmin, M=M, 
        muc=design$muc, mut=design$muc+design$delta,
        sc=sc,st=st,sc.known=sc.known,st.known=st.known,
        discard.prior = TRUE,
        vague = prior$vague,
        decision=dec,
        nsim=nsim,cores=cores, seed = 123, progress = "none"
      )

}

Compute the design using ECSS and store results.

obj.resECSS=list()
for (i in c(cases.fix,cases.mix)){
  obj.resECSS[[i]]<- suppressMessages(  
      adaptiveDesign_normal(
        ess = "ecss", min.ecss=-110, D=MSE, 
        ctl.prior=prior[[i]], treat.prior=prior$vague,
        N1=N1, Ntarget=Ntarget, Nmin=Nmin, M=M, 
        muc=design$muc, mut=design$muc+design$delta,
        sc=sc,st=st,sc.known=sc.known,st.known=st.known,
        discard.prior = TRUE,
        vague = prior$vague,
        decision=dec,
        nsim=nsim,cores=cores, seed = 123, progress = "none"
      ))
}

obj.resECSS.pp=list()
for (i in cases.fix){
  obj.resECSS.pp[[i]]<-   
      adaptiveDesign_normal(
        ess = "ecss", min.ecss=-40, D=MSE,
        ctl.prior=as.powerprior(prior[[i]]), treat.prior=prior$vague,
        N1=N1, Ntarget=Ntarget, Nmin=Nmin, M=M, 
        muc=design$muc, mut=design$muc+design$delta,
        sc=sc,st=st,sc.known=sc.known,st.known=st.known,
        discard.prior = TRUE,
        vague = prior$vague,
        decision=dec,
        nsim=nsim,cores=cores, seed = 123, progress = "none"
      )

}

Results

Collect results and reformat as appropriate for ggplot2.

gatherResults=function(priors,name.extension,obj){
  res=foreach(i=priors, .combine=rbind) %do% {
    data.frame(prior=paste0(i,name.extension),muc=design$muc,delta=design$delta, 
               t(sapply(obj[[i]]$list,rowMeans)[-(1:2),]))
  }
  colnames(res)[5]="samp"
  res
}

resEHSS.morita=gatherResults(priors=cases.mix,name.extension =".morita",
                             obj=obj.resEHSS.morita )
resEHSS.mix=gatherResults(priors=c(cases.fix,cases.mix,"vague"),name.extension =".mix",
                          obj=obj.resEHSS.mix )
resEHSS.pp=gatherResults(priors=cases.fix,name.extension =".pp",
                         obj=obj.resEHSS.pp )
resECSS.pp=gatherResults(priors=cases.fix,name.extension =".ecss.pp",
                         obj=obj.resECSS.pp )
resECSS=gatherResults(priors=c(cases.fix,cases.mix),name.extension =".ecss",
                      obj=obj.resECSS )

colnames(resEHSS.morita)[which(colnames(resEHSS.morita)=="ESS.ess")]=
colnames(resEHSS.mix)[which(colnames(resEHSS.mix)=="ESS.ess")]=
colnames(resEHSS.pp)[which(colnames(resEHSS.pp)=="ESS.ess")]=
colnames(resECSS.pp)[which(colnames(resECSS.pp)=="ESS.ess")]=
colnames(resECSS)[which(colnames(resECSS)=="ESS.ess")]="ESS"

results <- rbind(resEHSS.morita, resEHSS.mix, resEHSS.pp, resECSS.pp, resECSS)
results$prior= ordered(results$prior,c( "vague.mix" ,
                                              "inf.mix" , "inf.ecss" , 
                                              "mix50.morita","mix50.mix"  , "mix50.ecss",
                                              "inf.pp","inf.ecss.pp"
                                                ))
levels(results$prior)=c( "vague (prior ESS=ECSS)" ,
                            "informative (prior ESS)" ,
                            "informative (ECSS)" ,
                            "EHSS (MTM)",
                            "mixture (EHSS (mix))" , 
                            "mixture (ECSS)",
                            "power prior (EHSS)" , 
                            "power prior (ECSS)"
                              )

Plot results for reproduction of Figures in Section 4 of Wiesenfarth and Calderazzo (2019).

if (!Eval) load(file.path(system.file("exdata", package = "ESS"), "vignetteDesign.RData"))
lightbrown="#CD5B45"
darkbrown="#8B3E2F"
lightblue="#6CA6CD"
darkblue="#27408B"
lightpurple="#AB82FF"
darkpurple="#7D26CD"

colors=c(
  "vague (prior ESS=ECSS)"= "black",                   
  "informative (prior ESS)"= lightpurple,        
  "informative (ECSS)"=darkpurple ,        
  "mixture (EHSS (mix))"=lightbrown ,     
  "EHSS (MTM)"="orange",
  "mixture (ECSS)"=darkbrown ,            
  "power prior (EHSS)"=lightblue ,  
  "power prior (ECSS)"=darkblue
)
ltys=c(
  "vague (prior ESS=ECSS)"= "dotted",                   
  "informative (prior ESS)"= "dotted",        
  "informative (ECSS)"="dotted" ,        
  "mixture (EHSS (mix))"="dashed" ,
  "EHSS (MTM)"="dashed",
  "mixture (ECSS)"="dashed" ,            
  "power prior (EHSS)"="solid" ,  
  "power prior (ECSS)"="solid"      
)

theme=ggplot()+
      xlab("mu0")+
      geom_vline(xintercept=0,colour="grey")+
      scale_colour_manual(values=colors)+scale_linetype_manual(values=ltys)


results.trunc=subset(results,muc>=0)

theme+geom_line(aes(muc, ESS, colour=prior,linetype=prior),
                data=subset(results.trunc,delta==0))+
  ylab("ESS")+ylim(c(-100,100))+
  theme(legend.position = "left")

theme+geom_line(aes(muc, samp, colour=prior,linetype=prior),
                data=subset(results.trunc,delta==0))+
  ylab("Expected final sample size")+
  theme(legend.position = "left")


theme+geom_line(aes(muc, biasSq.mean, colour=prior,linetype=prior),
                data=subset(results.trunc,delta==0))+
  ylab("MSE")+ylim(c(0.005,.025))+
  theme(legend.position = "left")


theme+geom_line(aes(muc, power,  colour=prior,linetype=prior),
                data=subset(results,delta==0))+
  ylab("Type I error")+ylim(c(0.0,.14))+
  theme(legend.position = "left")

theme+geom_line(aes(muc, power,  colour=prior,linetype=prior),
                data=subset(results,delta==tau.vec[2]))+
  ylab(paste0("Power for tau=",tau.vec[2]))+ylim(c(0.0,1))+
  theme(legend.position = "left")

References

Schmidli, H., Gsteiger, S., Roychoudhury, S., O'Hagan, A., Spiegelhalter, D., and Neuenschwander, B. (2014). Robust meta-analytic-predictive priors in clinical trials with historical control information. Biometrics, 70(4):1023-103

Wiesenfarth, M., Calderazzo, S. (2019). Quantification of Prior Impact in Terms of Effective Current Sample Size. Submitted.

sessionInfo

sessionInfo()


wiesenfa/ESS documentation built on June 19, 2019, 4:19 p.m.