The dtpcrm package presents the design and conduct of a Continual Reassessment Method (CRM) trial with the use of the Dose Transition Pathways (DTP). Building on the R dfcrm package [1], the dtpcrm package provides the DTP to project in advance the doses recommended by a model-based dose-finding design for subsequent subjects (stay, escalate, de-escalate or stop early) using all the accumulated toxicity information [2]. DTP can be used as a design calibration tool and an operational/trial conduct tool. It can be presented as a table or as a flow diagram. The dtpcrm package also provides the modified CRM [3] and Time to event CRM (TITE-CRM) [4] with added practical modifications to allow stopping early when:
Here, we will illustrate the use of the DTP as
when designing a CRM, using the Viola trial as a case study [2,5].
In order to run the code, you have to first install the package and load it with
We need to input the parameters required for design considerations for CRM (see Figure 1 in Yap et al [2]). Those could be grouped under the three broad categories of Clinical Parameters, Model Specification Parameters and Practical Considerations.
A one-stage one-parameter Bayesian empiric model is used where the slope parameter is assumed to be normally distributed with mean 0 with a specified prior variance.
The prior DLT rates for the 7 doses and prior variance are specified as:
Using a model-based dose-escalation design, dose recommendations to escalate, de-escalate or stay at the current dose for subsequent cohorts of subjects are directed by the specified model, prior and observed data. In certain cases, those purely model-based recommendations may cause safety concerns, and it may be desirable to introduce practical constraints.
Practical considerations for Viola include:
p(true DLT rate at lowest dose > target DLT rate + \(x%\) | current observed data and any relevant prior information) > \(y\)
Stopping early criterion (for safety and sufficient number of subjects at MTD)
Simulated operating characteristics (OCs) are an important tool to assess the performance of a proposed adaptive design for informed decision making.
Let’s examine three scenarios, S1, S2 and S3 with assumed true DLT rates at each dose as defined below. S1 and S2 presents scenarios where the true MTD are at d(1) and d(3) respectively. S3 presents a setting whereby all doses are too toxic.
S1=c(0.03, 0.05, 0.07, 0.20, 0.36, 0.45, 0.55)
S2=c(0.005, 0.01, 0.03, 0.05, 0.07, 0.20, 0.36)
S3=c(0.45, 0.55, 0.65, 0.7, 0.75, 0.80, 0.85)
Scenario | d(-2) | d(-1) | d(0) | d(1) | d(2) | d(3) | d(4) |
---|---|---|---|---|---|---|---|
S1 | 0.030 | 0.05 | 0.07 | 0.20 | 0.36 | 0.45 | 0.55 |
S2 | 0.005 | 0.01 | 0.03 | 0.05 | 0.07 | 0.20 | 0.36 |
S3 | 0.450 | 0.55 | 0.65 | 0.70 | 0.75 | 0.80 | 0.85 |
It is useful to bear in mind that simulaton results are unavoidably subject to random variation. Hence in order to obtain adequately stable results, 5000 simulations per setting would be recommended for the final design. For illustrative purposes, we have used 50 here.
Scenario 1: True MTD at d(1),
Extracting outputs on probability of selecting each dose as the MTD and the number of subjects allocated to each dose, as well as stopping probabilty for toxicity or sufficient number at MTD,
stop.fun<-function(x, matchtxt) {
prob<-round(ifelse( !is.null(grep(matchtxt, names(x))>0) , x[grep(matchtxt, names(x))], 0),2)
prob[is.na(prob)]<-0
return(prob)
}
out<- cbind.data.frame(
rbind.data.frame("S1 True Tox" = sim1_1$summary$true_tox,
"S1 Prob Select"= sim1_1$summary$mtd,
"S1 No.Subjects"= sim1_1$summary$doses_given),
Stop.Tox = c("", stop.fun(sim1_1$summary$prob_stop, "Tox"), ""),
Stop.nMTD = c("", stop.fun(sim1_1$summary$prob_stop, "Con"), "")
)
dimnames(out)[[2]][1:length(dose.labels)]<-paste("d(", dose.labels,")", sep="")
dimnames(out)[[1]] <- paste(c(paste("S1", " True DLT rate", sep = ""), paste("S1", " Selection Probability", sep = ""), paste("S1", " Mean Number of Subjects", sep = "")))
Repeat the procedure for Scenarios 2 and 3.
The table below presents the simulation results for the selected scenarios, with prior and true DLT rates, probability of selecting a dose as the MTD and the number of subjects allocated to each dose. It also presents the probability of stopping early due to toxicity or having sufficient number of subjects at the MTD.
d(-2) | d(-1) | d(0) | d(1) | d(2) | d(3) | d(4) | Stop.Tox | Stop.nMTD | |
---|---|---|---|---|---|---|---|---|---|
Prior DLT | 0.03 | 0.07 | 0.12 | 0.2 | 0.3 | 0.4 | 0.52 | ||
S1 True DLT rate | 0.03 | 0.05 | 0.07 | 0.2 | 0.36 | 0.45 | 0.55 | ||
S1 Selection Probability | 0 | 0.02 | 0.28 | 0.48 | 0.2 | 0.02 | 0 | 0 | 0.46 |
S1 Mean Number of Subjects | 0 | 1.8 | 6.18 | 7.8 | 4.44 | 0.36 | 0 | ||
S2 True DLT rate | 0.005 | 0.01 | 0.03 | 0.05 | 0.07 | 0.2 | 0.36 | ||
S2 Selection Probability | 0 | 0 | 0 | 0 | 0.3 | 0.48 | 0.22 | 0 | 0.24 |
S2 Mean Number of Subjects | 0 | 0.18 | 3.18 | 3.6 | 5.76 | 5.52 | 2.76 | ||
S3 True DLT rate | 0.45 | 0.55 | 0.65 | 0.7 | 0.75 | 0.8 | 0.85 | ||
S3 Selection Probability | 0.32 | 0 | 0 | 0 | 0 | 0 | 0 | 0.68 | 0.32 |
S3 Mean Number of Subjects | 7.5 | 3.12 | 3.06 | 0.06 | 0 | 0 | 0 |
Using the specific parameters above, we can produce the DTP for the initial 4 cohorts of the Viola trial.
start.dose.level<-3 #(eg. 1,2,3 etc)
viola_dtp <- calculate_dtps(next_dose = start.dose.level, cohort_sizes = c(cohort.size, cohort.size, cohort.size), dose_func = applied_crm, prior = prior.DLT, target = target.DLT,
stop_func = stop_func, scale = sqrt(prior.var),
no_skip_esc = no_skip_esc, no_skip_deesc = no_skip_deesc,
global_coherent_esc = global_coherent_esc)
In Viola, there are 7 dose levels where the starting dose level is 3. For display purposes, we would use the dose-labels as used in Viola, which range from d(-2) to d(4), with starting dose at d(0).
# Using dose labels
viola_dtp[seq(1, ncol(viola_dtp), by=2)] <- viola_dtp[seq(1, ncol(viola_dtp), by=2)] - start.dose.level
# Indicate when stopping early occurs
indSTOP<-is.na(viola_dtp[seq(1,ncol(viola_dtp), by=2)])
viola_dtp.pretty<-viola_dtp
viola_dtp.pretty[seq(1,ncol(viola_dtp.pretty), by=2)][indSTOP]<-"STOP"
viola_dtp.pretty<-cbind.data.frame(1:nrow(viola_dtp.pretty), viola_dtp.pretty)
dimnames(viola_dtp.pretty)[[2]]<-c('Pathway', 'C1 Dose', 'C1 No.DLT', 'C2 Dose', 'C2 No.DLT','C3 Dose', 'C3 No.DLT', 'C4 Dose')
Pathway | C1 Dose | C1 No.DLT | C2 Dose | C2 No.DLT | C3 Dose | C3 No.DLT | C4 Dose |
---|---|---|---|---|---|---|---|
1 | 0 | 0 | 1 | 0 | 2 | 0 | 3 |
2 | 0 | 0 | 1 | 0 | 2 | 1 | 2 |
3 | 0 | 0 | 1 | 0 | 2 | 2 | 1 |
4 | 0 | 0 | 1 | 0 | 2 | 3 | 0 |
5 | 0 | 0 | 1 | 1 | 1 | 0 | 2 |
6 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
7 | 0 | 0 | 1 | 1 | 1 | 2 | -1 |
8 | 0 | 0 | 1 | 1 | 1 | 3 | -2 |
9 | 0 | 0 | 1 | 2 | -1 | 0 | 0 |
10 | 0 | 0 | 1 | 2 | -1 | 1 | -1 |
11 | 0 | 0 | 1 | 2 | -1 | 2 | -2 |
12 | 0 | 0 | 1 | 2 | -1 | 3 | -2 |
13 | 0 | 0 | 1 | 3 | -2 | 0 | -1 |
14 | 0 | 0 | 1 | 3 | -2 | 1 | -2 |
15 | 0 | 0 | 1 | 3 | -2 | 2 | -2 |
16 | 0 | 0 | 1 | 3 | -2 | 3 | STOP |
17 | 0 | 1 | -1 | 0 | 0 | 0 | 1 |
18 | 0 | 1 | -1 | 0 | 0 | 1 | 0 |
19 | 0 | 1 | -1 | 0 | 0 | 2 | -1 |
20 | 0 | 1 | -1 | 0 | 0 | 3 | -2 |
21 | 0 | 1 | -1 | 1 | -1 | 0 | -1 |
22 | 0 | 1 | -1 | 1 | -1 | 1 | -2 |
23 | 0 | 1 | -1 | 1 | -1 | 2 | -2 |
24 | 0 | 1 | -1 | 1 | -1 | 3 | -2 |
25 | 0 | 1 | -1 | 2 | -2 | 0 | -2 |
26 | 0 | 1 | -1 | 2 | -2 | 1 | -2 |
27 | 0 | 1 | -1 | 2 | -2 | 2 | -2 |
28 | 0 | 1 | -1 | 2 | -2 | 3 | STOP |
29 | 0 | 1 | -1 | 3 | -2 | 0 | -2 |
30 | 0 | 1 | -1 | 3 | -2 | 1 | -2 |
31 | 0 | 1 | -1 | 3 | -2 | 2 | STOP |
32 | 0 | 1 | -1 | 3 | -2 | 3 | STOP |
33 | 0 | 2 | -2 | 0 | -2 | 0 | -1 |
34 | 0 | 2 | -2 | 0 | -2 | 1 | -2 |
35 | 0 | 2 | -2 | 0 | -2 | 2 | -2 |
36 | 0 | 2 | -2 | 0 | -2 | 3 | STOP |
37 | 0 | 2 | -2 | 1 | -2 | 0 | -2 |
38 | 0 | 2 | -2 | 1 | -2 | 1 | -2 |
39 | 0 | 2 | -2 | 1 | -2 | 2 | STOP |
40 | 0 | 2 | -2 | 1 | -2 | 3 | STOP |
41 | 0 | 2 | -2 | 2 | STOP | NA | STOP |
42 | 0 | 2 | -2 | 2 | STOP | NA | STOP |
43 | 0 | 2 | -2 | 2 | STOP | NA | STOP |
44 | 0 | 2 | -2 | 2 | STOP | NA | STOP |
45 | 0 | 2 | -2 | 3 | STOP | NA | STOP |
46 | 0 | 2 | -2 | 3 | STOP | NA | STOP |
47 | 0 | 2 | -2 | 3 | STOP | NA | STOP |
48 | 0 | 2 | -2 | 3 | STOP | NA | STOP |
49 | 0 | 3 | -2 | 0 | -2 | 0 | -2 |
50 | 0 | 3 | -2 | 0 | -2 | 1 | -2 |
51 | 0 | 3 | -2 | 0 | -2 | 2 | -2 |
52 | 0 | 3 | -2 | 0 | -2 | 3 | STOP |
53 | 0 | 3 | -2 | 1 | -2 | 0 | -2 |
54 | 0 | 3 | -2 | 1 | -2 | 1 | -2 |
55 | 0 | 3 | -2 | 1 | -2 | 2 | STOP |
56 | 0 | 3 | -2 | 1 | -2 | 3 | STOP |
57 | 0 | 3 | -2 | 2 | STOP | NA | STOP |
58 | 0 | 3 | -2 | 2 | STOP | NA | STOP |
59 | 0 | 3 | -2 | 2 | STOP | NA | STOP |
60 | 0 | 3 | -2 | 2 | STOP | NA | STOP |
61 | 0 | 3 | -2 | 3 | STOP | NA | STOP |
62 | 0 | 3 | -2 | 3 | STOP | NA | STOP |
63 | 0 | 3 | -2 | 3 | STOP | NA | STOP |
64 | 0 | 3 | -2 | 3 | STOP | NA | STOP |
The term “NA” denotes not applicable.
Another way to display DTP is via a flow diagram. To obtain DTP flow diagram for Cohorts 1-3,
One can utilise the DTP for the initial cohorts to discuss with the investigators on the working of the proposed CRM design to check agreement and highlight unanticpated pathways. One can further calibrate the model by fine-tuning the model parameters to achieve DTP that are agreeable by the investigators. In particular, it would be useful to check that the investigators are in agreement on when a trial should be stopped early due to toxicity if excessive DLTs are observed in the initial cohorts. One should then evaluate average model performance of the fine-tuned model by re-running simulations to ensure that it is still favorable (see Figure 2 in [2]). When it comes to choosing a desirable model-based design,the final recommended model should be one that not only has promising operating characteristics but achieves DTP which the investigators are happy to adopt in practice [2,5].
In the case for Viola, the investigators were keen to only stop the trial early if they saw 2 or 3 DLTs out of the first 3 subjects at the lowest dose, d(-2), which would indicate that all the doses were too toxic. This guided the choice of \(y\) to be around 0.72.
No DLTs were observed in the first 2 cohorts who were dosed at dose levels 3 and 4.
C2 <- applied_crm(prior=prior.DLT, target = target.DLT, tox = DLT.outcomes, level = dose.level,
stop_func = stop_func,
no_skip_esc = no_skip_esc,
no_skip_deesc = no_skip_deesc,
global_coherent_esc = global_coherent_esc,
scale = sqrt(prior.var))
results<-cbind.data.frame(Dose=paste0("d(", dose.labels, ")"), summary_crm(C2)[2:ncol(summary_crm(C2))])
dimnames(results)[[2]][2:ncol(results)]<-c("Prior DLT", "No.subjects", "No.DLT", "Posterior DLT (90% PI)")
Recommended dose for next cohort is Dose level
Or dose label
The table below presents the CRM updates with prior DLT rates, number of evaluable subjects, number of DLTs and posterior DLT rates with 90% probability interval at each of the dose level.
Dose | Prior DLT | No.subjects | No.DLT | Posterior DLT (90% PI) |
---|---|---|---|---|
d(-2) | 0.03 | 0 | 0 | 0.001 (0, 0.079) |
d(-1) | 0.07 | 0 | 0 | 0.005 (0, 0.146) |
d(0) | 0.12 | 3 | 0 | 0.015 (0, 0.216) |
d(1) | 0.20 | 3 | 0 | 0.041 (0, 0.312) |
d(2) | 0.30 | 0 | 0 | 0.091 (0.001, 0.419) |
d(3) | 0.40 | 0 | 0 | 0.162 (0.007, 0.515) |
d(4) | 0.52 | 0 | 0 | 0.273 (0.028, 0.623) |
plot_crm(C2, dose_labels = paste0("d(",dose.labels,")"), cohort_sizes = c(3,3), dose_func =applied_crm,
no_skip_esc = no_skip_esc,
no_skip_deesc = no_skip_deesc,
global_coherent_esc = global_coherent_esc,
scale = sqrt(prior.var),
ylim = c(0, 0.7), lwd = 2, cex.axis = 1.5, cex.lab = 1.4, cex = 1, cohort.last = T
)
This figure presents the updates of the dose toxicity curves with evolving estimates of DLT rates at each dose, estimated at the end of each cohort. The black curve represents the prior estimates of DLT rates at each dose.
DTP for subsequent cohorts can be updated regularly. For instance, we can update after Cohorts 1 and 2, giving the DTP for Cohorts 3-6.
dtp_c3 <- calculate_dtps(next_dose = 5, cohort_sizes = c(3, 3, 3),
prev_tox = DLT.outcomes, prev_dose = dose.level,
prior = prior.DLT, target = target.DLT,
no_skip_esc = no_skip_esc,
no_skip_deesc = no_skip_deesc,
global_coherent_esc = global_coherent_esc,
stop_func = stop_func,
scale = sqrt(prior.var))
# Using dose labels
dtp_c3[seq(1, ncol(dtp_c3), by=2)] <- dtp_c3[seq(1, ncol(dtp_c3), by=2)] - start.dose.level
dtp_c3_pretty<-cbind.data.frame(1:nrow(dtp_c3), dtp_c3)
dimnames(dtp_c3_pretty)[[2]]<-c('Pathway','C3 Dose', 'C3 No.DLT', 'C4 Dose', 'C4 No.DLT','C5 Dose', 'C5 No.DLT', 'C6 Dose')
Pathway | C3 Dose | C3 No.DLT | C4 Dose | C4 No.DLT | C5 Dose | C5 No.DLT | C6 Dose |
---|---|---|---|---|---|---|---|
1 | 2 | 0 | 3 | 0 | 4 | 0 | 4 |
2 | 2 | 0 | 3 | 0 | 4 | 1 | 4 |
3 | 2 | 0 | 3 | 0 | 4 | 2 | 3 |
4 | 2 | 0 | 3 | 0 | 4 | 3 | 2 |
5 | 2 | 0 | 3 | 1 | 3 | 0 | 3 |
6 | 2 | 0 | 3 | 1 | 3 | 1 | 3 |
7 | 2 | 0 | 3 | 1 | 3 | 2 | 2 |
8 | 2 | 0 | 3 | 1 | 3 | 3 | 1 |
9 | 2 | 0 | 3 | 2 | 2 | 0 | 3 |
10 | 2 | 0 | 3 | 2 | 2 | 1 | 2 |
11 | 2 | 0 | 3 | 2 | 2 | 2 | 1 |
12 | 2 | 0 | 3 | 2 | 2 | 3 | 0 |
13 | 2 | 0 | 3 | 3 | 1 | 0 | 2 |
14 | 2 | 0 | 3 | 3 | 1 | 1 | 1 |
15 | 2 | 0 | 3 | 3 | 1 | 2 | 0 |
16 | 2 | 0 | 3 | 3 | 1 | 3 | -1 |
17 | 2 | 1 | 2 | 0 | 3 | 0 | 3 |
18 | 2 | 1 | 2 | 0 | 3 | 1 | 2 |
19 | 2 | 1 | 2 | 0 | 3 | 2 | 2 |
20 | 2 | 1 | 2 | 0 | 3 | 3 | 1 |
21 | 2 | 1 | 2 | 1 | 2 | 0 | 2 |
22 | 2 | 1 | 2 | 1 | 2 | 1 | 1 |
23 | 2 | 1 | 2 | 1 | 2 | 2 | 1 |
24 | 2 | 1 | 2 | 1 | 2 | 3 | 0 |
25 | 2 | 1 | 2 | 2 | 1 | 0 | 1 |
26 | 2 | 1 | 2 | 2 | 1 | 1 | 1 |
27 | 2 | 1 | 2 | 2 | 1 | 2 | 0 |
28 | 2 | 1 | 2 | 2 | 1 | 3 | -1 |
29 | 2 | 1 | 2 | 3 | 0 | 0 | 1 |
30 | 2 | 1 | 2 | 3 | 0 | 1 | 0 |
31 | 2 | 1 | 2 | 3 | 0 | 2 | -1 |
32 | 2 | 1 | 2 | 3 | 0 | 3 | -2 |
33 | 2 | 2 | 1 | 0 | 2 | 0 | 2 |
34 | 2 | 2 | 1 | 0 | 2 | 1 | 1 |
35 | 2 | 2 | 1 | 0 | 2 | 2 | 1 |
36 | 2 | 2 | 1 | 0 | 2 | 3 | 0 |
37 | 2 | 2 | 1 | 1 | 1 | 0 | 1 |
38 | 2 | 2 | 1 | 1 | 1 | 1 | 0 |
39 | 2 | 2 | 1 | 1 | 1 | 2 | 0 |
40 | 2 | 2 | 1 | 1 | 1 | 3 | -1 |
41 | 2 | 2 | 1 | 2 | 0 | 0 | 0 |
42 | 2 | 2 | 1 | 2 | 0 | 1 | -1 |
43 | 2 | 2 | 1 | 2 | 0 | 2 | -1 |
44 | 2 | 2 | 1 | 2 | 0 | 3 | -2 |
45 | 2 | 2 | 1 | 3 | -1 | 0 | -1 |
46 | 2 | 2 | 1 | 3 | -1 | 1 | -1 |
47 | 2 | 2 | 1 | 3 | -1 | 2 | -2 |
48 | 2 | 2 | 1 | 3 | -1 | 3 | -2 |
49 | 2 | 3 | 0 | 0 | 1 | 0 | 1 |
50 | 2 | 3 | 0 | 0 | 1 | 1 | 0 |
51 | 2 | 3 | 0 | 0 | 1 | 2 | 0 |
52 | 2 | 3 | 0 | 0 | 1 | 3 | -1 |
53 | 2 | 3 | 0 | 1 | 0 | 0 | 0 |
54 | 2 | 3 | 0 | 1 | 0 | 1 | -1 |
55 | 2 | 3 | 0 | 1 | 0 | 2 | -1 |
56 | 2 | 3 | 0 | 1 | 0 | 3 | -2 |
57 | 2 | 3 | 0 | 2 | -1 | 0 | -1 |
58 | 2 | 3 | 0 | 2 | -1 | 1 | -2 |
59 | 2 | 3 | 0 | 2 | -1 | 2 | -2 |
60 | 2 | 3 | 0 | 2 | -1 | 3 | -2 |
61 | 2 | 3 | 0 | 3 | -2 | 0 | -2 |
62 | 2 | 3 | 0 | 3 | -2 | 1 | -2 |
63 | 2 | 3 | 0 | 3 | -2 | 2 | -2 |
64 | 2 | 3 | 0 | 3 | -2 | 3 | -2 |
[1] Ken Cheung (2013). dfcrm: Dose-finding by the continual reassessment method. R package version 0.2-2. https://CRAN.R-project.org/package=dfcrm
[2] Yap, C., Billingham, L. J., Cheung, Y. K., Craddock, C., & O’Quigley, J. (2017). Dose Transition Pathways: The missing link between complex dose-finding designs and simple decision-making. Clinical Cancer Research, 23(24), 7440-7447
[3] O’Quigley, J. O., Pepe, M., and Fisher, L. (1990). Continual reassessment method: A practical design for phase I clinical trials in cancer. Biometrics 46:33-48.
[4] Cheung YK, Chappell R. Sequential designs for phase I clinical trials with late onset toxicities. Biometrics 2000;56:1177–82.
[5] Craddock C, Slade D, Santo C De, Wheat R, Ferguson P, Hodgkinson A, Brock K, Cavenagh J, Ingram W, Dennis M, Malladi R, Siddique S, Mussai F and Yap C (2018) Combination lenalidomide and azacitidine: a novel salvage therapy in patients who relapse after allogeneic stem cell transplantation for acute myeloid leukemia. Journal of Clinical Oncology (2019), JCO-18.
[6] Wheeler, G.M., Mander, A.P., Bedding, A., Brock, K., Cornelius, V., Grieve, A.P., Jaki, T., Love, S.B., Weir, C.J., Yap, C. and Bond, S.J., 2019. How to design a dose-finding study using the continual reassessment method. BMC medical research methodology, 19(1), p.18.