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 ensure patient safety during trial conduct by supporting dose-escalation decisions. In addition, the model can support estimation of the Maximum Tolerated Dose (MTD) in adaptive Bayesian dose-escalation designs.
Whereas traditional dose escalation designs, such as the 3+3 design, base the dosing decisions on predefined rules about the number of DLTs in the last one or two cohorts at the current dose, model-based designs such as those using Bayesian Logistic Regression Models (BLRMs) endeavor to model the dose-toxicity relationship as a continuous curve, and allow the model to guide dosing decisions. In this way, all available data contributes to the dosing decisions. Furthermore, extensions to the BLRM approach can support inclusion of available historical data on the compound(s) involved.
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.
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.
group_id | drug_A | drug_B | num_patients | num_toxicities | cohort_time |
---|---|---|---|---|---|
trial_A | 3.0 | 0.0 | 3 | 0 | 0 |
trial_A | 4.5 | 0.0 | 3 | 0 | 0 |
trial_A | 6.0 | 0.0 | 6 | 0 | 0 |
trial_A | 8.0 | 0.0 | 3 | 2 | 0 |
trial_B | 0.0 | 33.3 | 3 | 0 | 0 |
trial_B | 0.0 | 50.0 | 3 | 0 | 0 |
trial_B | 0.0 | 100.0 | 4 | 0 | 0 |
trial_B | 0.0 | 200.0 | 9 | 0 | 0 |
trial_B | 0.0 | 400.0 | 15 | 0 | 0 |
trial_B | 0.0 | 800.0 | 20 | 2 | 0 |
trial_B | 0.0 | 1120.0 | 17 | 4 | 0 |
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.
## [1] "trial_A" "trial_B" "IIT" "trial_AB"
The function blrm_trial
provides an object-oriented framework for operationalizing the dose-escalation trial design. This framework is intended as a convenient wrapper for the main model-fitting engine of the package, the blrm_exnex()
function. The latter allows additional flexibility for specifying the functional form of the model, but blrm_trial
covers the most common use-cases. This introductory vignette highlights blrm_trial
in lieu of blrm_exnex
; the reader is referred to the help-page of the function?blrm_exnex
for more details.
One begins with blrm_trial
by specifying three key design elements:
Information about the study drugs is encoded through a tibble
as below. This includes the names of the study-drugs, the reference doses (see [3] or ?blrm_exnex
to understand the role this choice plays in the model specification), the dosing units, and (optionally) the a priori expected DLT rate for each study drug given individually at the respective reference doses.
All design information for the study described in [1] is also included as built-in datasets, which are part of the OncoBayes2
package.
drug_name | dose_ref | dose_unit | reference_p_dlt |
---|---|---|---|
drug_A | 300 | mg | 0.1 |
drug_B | 960 | mg | 0.1 |
The provisional dose levels are specified as below. For conciseness, we begin by fixing the dose level of drug A in these provisional doses.
group_id | drug_A | drug_B | dose_id |
---|---|---|---|
trial_AB | 3 | 0 | 22 |
trial_AB | 3 | 400 | 23 |
trial_AB | 3 | 600 | 24 |
trial_AB | 3 | 800 | 25 |
blrm_trial
Together with the data described in the previous section, these objects can be used to initialize a blrm_trial
object.
combo2_trial_setup <- blrm_trial(
data = hist_combo2,
drug_info = drug_info_combo2,
dose_info = dose_info,
simplified_prior = FALSE
)
## No stratum defined - assigning all groups to single stratum "all"
## Please configure blrm_exnex using the update() function.
At this point, the trial design has been initialized. However, in the absence of simplified_prior = TRUE
, we have not yet specified the prior distribution for the dose-toxicity model.
OncoBayes2 provides two methods for completing the model specification:
Use simplified_prior = TRUE
, which employs a package-default prior distribution, subject to a small number of optional arguments controlling the details.
Provide a full prior specification to be passed to the main model-fitting engine of OncoBayes2: the blrm_exnex
function.
For illustrative purposes, here we highlight method #1. See ?'example-combo2_trial'
for an example of #2. The below choice of prior broadly follows the case study in [4], although we slightly deviate from the model in [4] by allowing an EXchangeable/Non-EXchangeable prior for the drug components.
To employ the simplified prior, and fit the model with MCMC:
combo2_trial_start <- blrm_trial(
data = hist_combo2,
drug_info = drug_info_combo2,
dose_info = dose_info,
simplified_prior = TRUE,
EX_prob_comp_hist = 0.8,
EX_prob_comp_new = 1
)
Now, the object combo2_trial_start
contains the posterior model fit, in addition to the trial design details. Next we highlight the main methods for extracting relevant information from it.
The function prior_summary
provides a facility for printing, in a readable format, a summary of the prior specification.
The main target of inference is generally the probability of DLT at a selection of provisional dose levels. To obtain these summaries for the provisional doses specified previously, we simply write:
group_id | drug_A | drug_B | dose_id | stratum_id | mean | sd | 2.5% | 50% | 97.5% | prob_underdose | prob_target | prob_overdose | ewoc_ok |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
trial_AB | 3 | 0 | 22 | all | 0.08 | 0.12 | 0.00 | 0.04 | 0.44 | 0.86 | 0.10 | 0.04 | TRUE |
trial_AB | 3 | 400 | 23 | all | 0.14 | 0.16 | 0.00 | 0.09 | 0.63 | 0.72 | 0.18 | 0.10 | TRUE |
trial_AB | 3 | 600 | 24 | all | 0.16 | 0.17 | 0.01 | 0.11 | 0.68 | 0.65 | 0.23 | 0.12 | TRUE |
trial_AB | 3 | 800 | 25 | all | 0.20 | 0.18 | 0.02 | 0.15 | 0.73 | 0.53 | 0.31 | 0.16 | TRUE |
Such summaries may be used to assess which combination doses have unacceptable high risk of toxicity. For example, according to the escalation with overdose control (EWOC) design criteria [3], one would compute the posterior probability that each dose is excessively toxic (column prob_overdose
; note that the definition of “excessively toxic” is encoded in the blrm_trial
object through the interval_prob
argument), and take as eligible doses only those where this probability does not exceed 25% (column ewoc_ok
).
The BLRM allows a principled approach to predicting the number of DLTs that may be observed in a future cohort. This may be a key estimand for understanding and limiting the toxicity risk to patients. For example, suppose a candidate starting dose for the new trial trial_AB
is 3 mg of Drug A + 400 mg of Drug B. We may wish to check that at this dose, the estimated probability of 2 or more DLTs out of an initial cohort of 3 to 6 patients is sufficiently low.
candidate_starting_dose <- summary(combo2_trial_start, "dose_info") %>%
filter(drug_A == 3, drug_B == 400) %>%
expand_grid(num_patients = 3:6) %>%
mutate(num_toxicities = 0)
pp_summary <- summary(combo2_trial_start, interval_prob = c(-1, 0, 1, 6), predictive = TRUE,
newdata = candidate_starting_dose)
kable(bind_cols(select(candidate_starting_dose, num_patients),
select(pp_summary, ends_with("]"))), digits = 3)
num_patients | (-1,0] | (0,1] | (1,6] |
---|---|---|---|
3 | 0.698 | 0.216 | 0.086 |
4 | 0.640 | 0.233 | 0.127 |
5 | 0.591 | 0.243 | 0.166 |
6 | 0.550 | 0.248 | 0.202 |
This tells us that for the initial cohort, according to the model, the chance of two or more patients developing DLTs ranges from 8.6% to 20.2%, depending on the number of patients enrolled.
Dose-escalation designs are adaptive in nature, as dosing decisions are made after each sequential cohort. The model must be updated after each new enrollment. If a new cohort of patients is observed, say:
new_cohort <- tibble(group_id = "trial_AB",
drug_A = 3,
drug_B = 400,
num_patients = 5,
num_toxicities = 1)
One can update the model to incorporate this new information using update()
with add_data
equal to the new cohort:
This yields a new blrm_trial
object with updated data and posterior summaries. Below is the method for obtaining posterior estimates at the next highest dose of drug A.
kable(summary(combo2_trial_update, "newdata_prediction",
newdata = tibble(group_id = "trial_AB",
drug_A = 4.5,
drug_B = c(400, 600, 800))), digits = 2)
## stratum_id not given, but only one stratum defined. Assigning first stratum.
group_id | drug_A | drug_B | stratum_id | dose_id | mean | sd | 2.5% | 50% | 97.5% | prob_underdose | prob_target | prob_overdose | ewoc_ok |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
trial_AB | 4.5 | 400 | all | NA | 0.16 | 0.12 | 0.02 | 0.13 | 0.47 | 0.59 | 0.31 | 0.10 | TRUE |
trial_AB | 4.5 | 600 | all | NA | 0.19 | 0.13 | 0.04 | 0.17 | 0.52 | 0.48 | 0.39 | 0.13 | TRUE |
trial_AB | 4.5 | 800 | all | NA | 0.23 | 0.14 | 0.05 | 0.20 | 0.58 | 0.35 | 0.45 | 0.20 | TRUE |
It may be of interest to test prospectively how this model responds in various scenarios for upcoming cohorts.
This can be done easily by again using update()
with the add_data
argument. In the code below, we explore 3 possible outcomes for a subsequent cohort enrolled at 3 mg Drug A + 800 mg Drug B, and review the model’s inference at adjacent doses.
# set up two scenarios at the starting dose level
# store them as data frames in a named list
scenarios <- expand_grid(
group_id = "trial_AB",
drug_A = 3,
drug_B = 800,
num_patients = 3,
num_toxicities = 0:2
) %>% split(1:3) %>% setNames(paste(0:2, "DLTs"))
candidate_doses <- expand_grid(
group_id = "trial_AB",
drug_A = c(3, 4.5),
drug_B = c(600, 800)
)
scenario_inference <- lapply(scenarios, function(scenario_newdata) {
# refit the model with each scenario's additional data
scenario_fit <- update(combo2_trial_update, add_data = scenario_newdata)
# summarize posterior at candidate doses
summary(scenario_fit, "newdata_prediction", newdata = candidate_doses)
})
group_id | drug_A | drug_B | stratum_id | dose_id | mean | sd | 2.5% | 50% | 97.5% | prob_underdose | prob_target | prob_overdose | ewoc_ok |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
trial_AB | 3.0 | 600 | all | 24 | 0.14 | 0.09 | 0.02 | 0.12 | 0.35 | 0.68 | 0.29 | 0.03 | TRUE |
trial_AB | 3.0 | 800 | all | 25 | 0.17 | 0.10 | 0.04 | 0.15 | 0.40 | 0.54 | 0.40 | 0.06 | TRUE |
trial_AB | 4.5 | 600 | all | NA | 0.15 | 0.09 | 0.03 | 0.13 | 0.37 | 0.63 | 0.32 | 0.05 | TRUE |
trial_AB | 4.5 | 800 | all | NA | 0.18 | 0.10 | 0.04 | 0.16 | 0.42 | 0.49 | 0.43 | 0.08 | TRUE |
group_id | drug_A | drug_B | stratum_id | dose_id | mean | sd | 2.5% | 50% | 97.5% | prob_underdose | prob_target | prob_overdose | ewoc_ok |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
trial_AB | 3.0 | 600 | all | 24 | 0.20 | 0.11 | 0.05 | 0.18 | 0.47 | 0.42 | 0.46 | 0.12 | TRUE |
trial_AB | 3.0 | 800 | all | 25 | 0.24 | 0.12 | 0.07 | 0.22 | 0.53 | 0.28 | 0.52 | 0.21 | TRUE |
trial_AB | 4.5 | 600 | all | NA | 0.21 | 0.11 | 0.05 | 0.19 | 0.49 | 0.37 | 0.48 | 0.14 | TRUE |
trial_AB | 4.5 | 800 | all | NA | 0.25 | 0.12 | 0.07 | 0.23 | 0.54 | 0.23 | 0.53 | 0.24 | TRUE |
group_id | drug_A | drug_B | stratum_id | dose_id | mean | sd | 2.5% | 50% | 97.5% | prob_underdose | prob_target | prob_overdose | ewoc_ok |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
trial_AB | 3.0 | 600 | all | 24 | 0.28 | 0.14 | 0.07 | 0.25 | 0.60 | 0.21 | 0.48 | 0.31 | FALSE |
trial_AB | 3.0 | 800 | all | 25 | 0.34 | 0.15 | 0.11 | 0.31 | 0.71 | 0.10 | 0.45 | 0.45 | FALSE |
trial_AB | 4.5 | 600 | all | NA | 0.29 | 0.14 | 0.08 | 0.27 | 0.62 | 0.18 | 0.47 | 0.35 | FALSE |
trial_AB | 4.5 | 800 | all | NA | 0.35 | 0.15 | 0.12 | 0.33 | 0.71 | 0.09 | 0.42 | 0.50 | FALSE |
In the example of [1], at the time of completion of trial_AB
, the following additional data was observed.
group_id | drug_A | drug_B | num_patients | num_toxicities | cohort_time |
---|---|---|---|---|---|
trial_A | 4.5 | 0 | 3 | 0 | 1 |
trial_A | 6.0 | 0 | 5 | 0 | 1 |
IIT | 3.0 | 400 | 3 | 0 | 1 |
IIT | 3.0 | 800 | 7 | 5 | 1 |
IIT | 4.5 | 400 | 3 | 0 | 1 |
IIT | 6.0 | 400 | 6 | 0 | 1 |
IIT | 6.0 | 600 | 3 | 2 | 1 |
trial_AB | 3.0 | 400 | 3 | 0 | 1 |
trial_AB | 3.0 | 800 | 6 | 2 | 1 |
trial_AB | 4.5 | 600 | 10 | 2 | 1 |
trial_AB | 6.0 | 400 | 10 | 3 | 1 |
Numerous toxicities were observed in the concurrent IIT
study. Through the MAC framework, these data can influence the model summaries for trial_AB
. Note that we use the update
function differently than before, since we specify the entire data-set now we use the data
argument.
Model results can be visualized using package functions. See ?plot_toxicity_curve
for details.
plot_toxicity_curve(final_fit, x = vars(drug_B), group = vars(group_id, drug_A),
facet_args = list(ncol = 1))
[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.
## R version 3.6.1 (2019-07-05)
## 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] tibble_2.1.3 tidyr_1.0.0 dplyr_0.8.3 ggplot2_3.2.1
## [5] knitr_1.25 OncoBayes2_0.7-0 Rcpp_1.0.2
##
## loaded via a namespace (and not attached):
## [1] rstan_2.19.3 tidyselect_0.2.5 xfun_0.10
## [4] purrr_0.3.3 colorspace_1.4-1 vctrs_0.2.0
## [7] htmltools_0.4.0 stats4_3.6.1 loo_2.1.0
## [10] yaml_2.2.0 rlang_0.4.0 pkgbuild_1.0.6
## [13] pillar_1.4.2 glue_1.3.1 withr_2.1.2
## [16] matrixStats_0.55.0 lifecycle_0.1.0 plyr_1.8.4
## [19] stringr_1.4.0 munsell_0.5.0 gtable_0.3.0
## [22] codetools_0.2-16 evaluate_0.14 labeling_0.3
## [25] inline_0.3.15 callr_3.3.2 ps_1.3.0
## [28] parallel_3.6.1 bayesplot_1.7.0 rstantools_2.0.0
## [31] highr_0.8 scales_1.0.0 backports_1.1.5
## [34] checkmate_1.9.4 StanHeaders_2.19.2 abind_1.4-5
## [37] gridExtra_2.3 digest_0.6.21 stringi_1.4.3
## [40] processx_3.4.1 grid_3.6.1 cli_1.1.0
## [43] tools_3.6.1 magrittr_1.5 lazyeval_0.2.2
## [46] Formula_1.2-3 crayon_1.3.4 pkgconfig_2.0.3
## [49] zeallot_0.1.0 prettyunits_1.0.2 ggridges_0.5.1
## [52] assertthat_0.2.1 rmarkdown_1.16 R6_2.4.0
## [55] compiler_3.6.1