Guiding Oncology Dose-Escalation Trials

Andrew Bean, Sebastian Weber

2019-08-28

Introduction

The OncoBayes2 package provides flexible functions for Bayesian meta-analytic modeling of the incidence of Dose Limiting Toxicities (DLTs) by dose level, under treatment regimes involving any number of combination partners. Such models may be used to support dose-escalation decisions and estimation of the Maximum Tolerated Dose (MTD) in adaptive Bayesian dose-escalation designs.

The package supports incorporation of historical data through a Meta-Analytic-Combined (MAC) framework [1], which stratifies these heterogeneous sources of information through a hierarchical model. Additionally, it allows the use of EXchangeable/Non-EXchangeable (EX/NEX) priors to manage the amount of information-sharing across subgroups of historical and/or concurrent sources of data.

Example use-case

Consider the application described in Section 3.2 of [1], in which the risk of DLT is to be studied as a function of dose for two drugs, drug A and drug B. Historical information on the toxicity profiles of these two drugs is available from single agent trials trial_A and trial_B. The historical data for this example is available in an internal data set.

kable(hist_combo2)
group_id DosesAdm1 DosesAdm2 Npat Ntox
trial_A 3.0 0.0 3 0
trial_A 4.5 0.0 3 0
trial_A 6.0 0.0 6 0
trial_A 8.0 0.0 3 2
trial_B 0.0 33.3 3 0
trial_B 0.0 50.0 3 0
trial_B 0.0 100.0 4 0
trial_B 0.0 200.0 9 0
trial_B 0.0 400.0 15 0
trial_B 0.0 800.0 20 2
trial_B 0.0 1120.0 17 4

The objective is to aid dosing and dose-escalation decisions in a future trial, trial_AB, in which the drugs will be combined. Additionally, another investigator-initiated trial IIT will study the same combination concurrently. Note that these as-yet-unobserved sources of data are included in the input data as unobserved factor levels. This mechanism allows us to specify a joint meta-analytic prior for all four sources of historical and concurrent data.

levels(hist_combo2$group_id)
## [1] "trial_A"  "trial_B"  "IIT"      "trial_AB"

Fitting the model

To fit the hierarchical model described in [4], one makes a call to the function blrm_exnex, as below.

# Design parameters ---------------------

dref <- c(3, 960)
num_comp <- 2 # two investigational drugs
num_inter <- 1 # one drug-drug interaction needs to be modeled
num_groups <- nlevels(hist_combo2$group_id) # four groups of data
num_strata <- 1 # no stratification needed

# Model fit -----------------------------

blrmfit <- blrm_exnex(
  cbind(Ntox, Npat - Ntox) ~
    1 + I(log(DosesAdm1 / dref[1])) |
    1 + I(log(DosesAdm2 / dref[2])) |
    0 + I(DosesAdm1/dref[1] *DosesAdm2/dref[2]) |
    group_id,
  data = hist_combo2,
  prior_EX_mu_mean_comp = matrix(
    c(logit(0.1), 0, # hyper-mean of (intercept, log-slope) for drug A
      logit(0.1), 0), # hyper-mean of (intercept, log-slope) for drug B
    nrow = num_comp,
    ncol = 2,
    byrow = TRUE
  ),
  prior_EX_mu_sd_comp = matrix(
    c(3.33, 1, # hyper-sd of mean mu for (intercept, log-slope) for drug B
      3.33, 1), # hyper-sd of mean mu for (intercept, log-slope) for drug B
    nrow = num_comp,
    ncol = 2,
    byrow = TRUE
  ),
  prior_EX_tau_mean_comp = matrix(
    c(log(0.25), log(0.125),
      log(0.25), log(0.125)),
    nrow = num_comp,
    ncol = 2,
    byrow = TRUE
  ),
  prior_EX_tau_sd_comp = matrix(
    c(log(4) / 1.96, log(4) / 1.96,
      log(4) / 1.96, log(4) / 1.96),
    nrow = num_comp,
    ncol = 2,
    byrow = TRUE
  ),
  prior_EX_mu_mean_inter = 0,
  prior_EX_mu_sd_inter = 1.121,
  prior_EX_tau_mean_inter = matrix(log(0.125), nrow = num_inter, ncol = num_strata),
  prior_EX_tau_sd_inter = matrix(log(4) / 1.96, nrow = num_inter, ncol = num_strata),
  prior_is_EXNEX_comp = rep(FALSE, num_comp),
  prior_is_EXNEX_inter = rep(FALSE, num_inter),
  prior_EX_prob_comp = matrix(1, nrow = num_groups, ncol = num_comp),
  prior_EX_prob_inter = matrix(1, nrow = num_groups, ncol = num_inter),
  prior_tau_dist = 1
)

The function blrm_exnex returns an object from which numerical and graphical posterior summaries can be extracted using OncoBayes2 functions. We recommend making use of the methods described below.

Summary of prior specification

The function prior_summary provides a facility for printing, in a readable format, a summary of the prior specification.

Summary of posterior

The main target of inference is generally the probability of DLT at a selection of possible doses. In order to obtain this inference, one needs to specify the covariate levels of interest (which need not be present in the observed data).

In this case, we are interested in predicitons for trial_AB, with the possible combination doses of drugs A and B below.

Note it is important that the factor levels associated with newdata$group_id be consistent with the levels of the grouping factor used when calling blrm_exnex. The stringsAsFactors = FALSE argument above ensures that the variable will initially be treated as a character. The next line re-converts it to a factor with the correct set of four levels. Alternativley, we can create the group_id column directly as a factor column within newdata. The code below results in the same newdata in a more compact form.

Posterior summary statistics for the DLT rates at these provisional doses can be extracted from the blrmfit object using the summary method.

group_id DosesAdm1 DosesAdm2 mean sd 2.5% 50% 97.5% (0,0.16] (0.16,0.33] (0.33,1]
trial_AB 0.0 0 0.000 0.000 0.000 0.000 0.000 1.000 0.000 0.000
trial_AB 3.0 0 0.056 0.070 0.000 0.031 0.249 0.924 0.067 0.009
trial_AB 4.5 0 0.098 0.093 0.005 0.072 0.346 0.812 0.158 0.030
trial_AB 6.0 0 0.166 0.139 0.013 0.129 0.537 0.598 0.294 0.108
trial_AB 0.0 400 0.033 0.039 0.000 0.020 0.126 0.988 0.010 0.002
trial_AB 3.0 400 0.093 0.090 0.005 0.065 0.333 0.829 0.146 0.026
trial_AB 4.5 400 0.143 0.129 0.010 0.103 0.501 0.675 0.234 0.091
trial_AB 6.0 400 0.221 0.193 0.014 0.161 0.710 0.499 0.266 0.236
trial_AB 0.0 600 0.061 0.055 0.003 0.048 0.190 0.954 0.040 0.005
trial_AB 3.0 600 0.130 0.119 0.010 0.092 0.467 0.716 0.210 0.074
trial_AB 4.5 600 0.189 0.176 0.011 0.130 0.665 0.571 0.248 0.181
trial_AB 6.0 600 0.271 0.245 0.010 0.193 0.860 0.450 0.222 0.328
trial_AB 0.0 800 0.104 0.073 0.017 0.089 0.278 0.844 0.141 0.014
trial_AB 3.0 800 0.185 0.162 0.015 0.135 0.623 0.568 0.269 0.164
trial_AB 4.5 800 0.250 0.229 0.010 0.174 0.824 0.478 0.235 0.286
trial_AB 6.0 800 0.327 0.293 0.006 0.232 0.943 0.410 0.185 0.405

Such summaries may be used to assess which combination doses have acceptable risk of toxicity. For example, according the escalation with overdose control (EWOC) design criteria [3], any doses for which the last column does not exceed 25% are eligible for enrollment.

Data scenarios

Before trial_AB is initiated, it may be of interest to test how this model responds in various scenarios for the initial combination cohort(s).

This can be done easily in OncoBayes2 by updating the initial model fit with additional rows of hypothetical data. In the code below, we explore 3 possible outcomes for an initial cohort enrolled at 3 mg Drug A + 400 mg Drug B, and review the model’s inference at adjacent doses.

Model inference when 1 DLT is observed in first cohort
group_id DosesAdm1 DosesAdm2 mean sd 2.5% 50% 97.5% (0,0.16] (0.16,0.33] (0.33,1]
trial_AB 3.0 400 0.147 0.110 0.019 0.119 0.438 0.653 0.270 0.076
trial_AB 4.5 400 0.217 0.155 0.030 0.177 0.611 0.446 0.354 0.200
Model inference when 2 DLTs are observed in first cohort
group_id DosesAdm1 DosesAdm2 mean sd 2.5% 50% 97.5% (0,0.16] (0.16,0.33] (0.33,1]
trial_AB 3.0 400 0.256 0.155 0.051 0.223 0.639 0.306 0.438 0.257
trial_AB 4.5 400 0.348 0.194 0.068 0.315 0.784 0.180 0.347 0.473

Continuation of example

In the example of [1], at the time of completion of trial_AB, the complete historical and concurrent data are as follows.

kable(codata_combo2)
group_id DosesAdm1 DosesAdm2 Npat Ntox
trial_A 3.0 0.0 3 0
trial_A 4.5 0.0 6 0
trial_A 6.0 0.0 11 0
trial_A 8.0 0.0 3 2
trial_B 0.0 33.3 3 0
trial_B 0.0 50.0 3 0
trial_B 0.0 100.0 4 0
trial_B 0.0 200.0 9 0
trial_B 0.0 400.0 15 0
trial_B 0.0 800.0 20 2
trial_B 0.0 1120.0 17 4
IIT 3.0 400.0 3 0
IIT 3.0 800.0 7 5
IIT 4.5 400.0 3 0
IIT 6.0 400.0 6 0
IIT 6.0 600.0 3 2
trial_AB 3.0 400.0 3 0
trial_AB 3.0 800.0 6 2
trial_AB 4.5 600.0 10 2
trial_AB 6.0 400.0 10 3

Numerous toxicities were observed in the concurrent IIT study. Through the MAC framework, these data can influence the model summaries for trial_AB.

final_fit <- update(blrmfit, data = codata_combo2)

summ <- summary(final_fit, newdata, prob = c(0.5, 0.95), interval_prob = c(0,0.33,1))

final_summ_stats <- cbind(newdata, summ) %>%
    mutate(EWOC=1*`(0.33,1]`<=0.25)
ggplot(final_summ_stats,
       aes(x=factor(DosesAdm2), colour=EWOC)) +
    facet_wrap(~DosesAdm1, labeller=label_both) +
    scale_y_continuous(breaks=c(0, 0.16, 0.33, 0.4, 0.6, 0.8, 1.0)) +
    coord_cartesian(ylim=c(0,0.8)) +
    geom_hline(yintercept = c(0.16, 0.33),
               linetype = "dotted") +
    geom_pointrange(aes(y=`50%`, ymin=`2.5%`, ymax=`97.5%`)) +
    geom_linerange(aes(ymin=`25%`, ymax=`75%`), size=1.5) +
    ggtitle("DLT Probability", "Shown is the median (dot), 50% CrI (thick line) and 95% CrI (thin line)") +
    ylab(NULL) + 
    xlab("Dose Drug B [mg]")

It can be insightful to consider the continuous representation of the model as shown below using the modern tidybayes package. The EWOC criterion fails to be fullfilled once the upper end of the 50% CrI crosses the critical 33% threshold probability since then the 75% quantile of the distribution exceeds the 33% thresholds such that more than 25% of probability lies beyond 33%.

library(tidybayes)

expand.grid(group_id=factor("trial_AB", levels=levels(codata_combo2$group_id)),
            DosesAdm2=exp(seq(log(100),log(800),length=100)), DosesAdm1=c(0, 3, 4.5, 6)) %>%
    add_draws(posterior_linpred(final_fit, newdata = ., transform=TRUE)) %>%
    median_qi(.width=c(0.5, 0.95)) %>%
    ggplot(aes(y = .value, x = DosesAdm2)) +
    scale_x_log10(breaks=c(100,200,400,600,800)) +
    facet_wrap(~DosesAdm1, labeller=label_both) +
    scale_y_continuous(breaks=c(0, 0.16, 0.33, 0.4, 0.6, 0.8, 1.0)) +
    geom_lineribbon() +
    scale_fill_brewer() +
    coord_cartesian(ylim=c(0,0.8)) + 
    geom_hline(yintercept = c(0.16, 0.33),
               linetype = "dotted") +
    ggtitle("DLT Probability", "Shown is the median (line), 50% CrI (dark) and 95% CrI (light)") +
    ylab(NULL) + 
    xlab("Dose Drug B [mg]")

References

[1] Neuenschwander, B., Roychoudhury, S., & Schmidli, H. (2016). On the use of co-data in clinical trials. Statistics in Biopharmaceutical Research, 8(3), 345-354.

[2] Neuenschwander, B., Wandel, S., Roychoudhury, S., & Bailey, S. (2016). Robust exchangeability designs for early phase clinical trials with multiple strata. Pharmaceutical statistics, 15(2), 123-134.

[3] Neuenschwander, B., Branson, M., & Gsponer, T. (2008). Critical aspects of the Bayesian approach to phase I cancer trials. Statistics in medicine, 27(13), 2420-2439.

[4] Neuenschwander, B., Matano, A., Tang, Z., Roychoudhury, S., Wandel, S. Bailey, Stuart. (2014). A Bayesian Industry Approach to Phase I Combination Trials in Oncology. In Statistical methods in drug combination studies (Vol. 69). CRC Press.

Session Info

sessionInfo()
## R version 3.5.3 (2019-03-11)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 16.04.6 LTS
## 
## Matrix products: default
## BLAS: /usr/lib/libblas/libblas.so.3.6.0
## LAPACK: /usr/lib/lapack/liblapack.so.3.6.0
## 
## locale:
## [1] C
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] tidybayes_1.1.0  dplyr_0.8.3      ggplot2_3.2.0    knitr_1.22      
## [5] RBesT_1.4-0      OncoBayes2_0.4-4 Rcpp_1.0.1      
## 
## loaded via a namespace (and not attached):
##  [1] rstan_2.18.2              ggstance_0.3.2           
##  [3] tidyselect_0.2.5          xfun_0.6                 
##  [5] purrr_0.2.5               lattice_0.20-38          
##  [7] colorspace_1.3-2          htmltools_0.3.6          
##  [9] stats4_3.5.3              loo_2.0.0                
## [11] yaml_2.2.0                rlang_0.4.0              
## [13] pkgbuild_1.0.2            pillar_1.4.2             
## [15] glue_1.3.1                withr_2.1.2              
## [17] RColorBrewer_1.1-2        matrixStats_0.54.0       
## [19] plyr_1.8.4                stringr_1.4.0            
## [21] munsell_0.5.0             gtable_0.2.0             
## [23] mvtnorm_1.0-8             coda_0.19-2              
## [25] codetools_0.2-16          evaluate_0.13            
## [27] forcats_0.3.0             inline_0.3.15            
## [29] callr_3.1.0               ps_1.2.1                 
## [31] parallel_3.5.3            bayesplot_1.6.0          
## [33] highr_0.8                 rstantools_1.5.1         
## [35] arrayhelpers_1.0-20160527 scales_1.0.0             
## [37] backports_1.1.3           checkmate_1.8.5          
## [39] StanHeaders_2.18.0-1      abind_1.4-5              
## [41] gridExtra_2.3             svUnit_0.7-12            
## [43] digest_0.6.18             stringi_1.4.3            
## [45] processx_3.2.1            grid_3.5.3               
## [47] cli_1.0.1                 tools_3.5.3              
## [49] magrittr_1.5              lazyeval_0.2.1           
## [51] tibble_2.1.3              Formula_1.2-3            
## [53] crayon_1.3.4              tidyr_0.8.2              
## [55] pkgconfig_2.0.2           prettyunits_1.0.2        
## [57] ggridges_0.5.1            assertthat_0.2.1         
## [59] rmarkdown_1.11            R6_2.4.0                 
## [61] compiler_3.5.3