This tutorial complements the manuscript Implementing the EffTox Dose-Finding Design in the Matchpoint Trial (Brock et al.,in submission). Please consult the paper for the clinical background, the methodology details, and full explanation of the terminology.
In this notebook, we illustrate posterior utility plots of selected doses using the EffTox design in the seamless phase I/II dose-finding clinical trial, Matchpoint.
In [15]:
import numpy as np
from scipy.stats import norm
from clintrials.dosefinding.efftox import EffTox, LpNormCurve
In [2]:
%matplotlib inline
In [3]:
real_doses = [7.5, 15, 30, 45]
trial_size = 30
cohort_size = 3
first_dose = 3
prior_tox_probs = (0.025, 0.05, 0.1, 0.25)
prior_eff_probs = (0.2, 0.3, 0.5, 0.6)
tox_cutoff = 0.40
eff_cutoff = 0.45
tox_certainty = 0.05
eff_certainty = 0.03
In [4]:
mu_t_mean, mu_t_sd = -5.4317, 2.7643
beta_t_mean, beta_t_sd = 3.1761, 2.7703
mu_e_mean, mu_e_sd = -0.8442, 1.9786
beta_e_1_mean, beta_e_1_sd = 1.9857, 1.9820
beta_e_2_mean, beta_e_2_sd = 0, 0.2
psi_mean, psi_sd = 0, 1
efftox_priors = [
norm(loc=mu_t_mean, scale=mu_t_sd),
norm(loc=beta_t_mean, scale=beta_t_sd),
norm(loc=mu_e_mean, scale=mu_e_sd),
norm(loc=beta_e_1_mean, scale=beta_e_1_sd),
norm(loc=beta_e_2_mean, scale=beta_e_2_sd),
norm(loc=psi_mean, scale=psi_sd),
]
The above parameters are explained in the manuscript.
In [5]:
hinge_points = [(0.4, 0), (1, 0.7), (0.5, 0.4)]
metric = LpNormCurve(hinge_points[0][0], hinge_points[1][1], hinge_points[2][0], hinge_points[2][1])
In [6]:
et = EffTox(real_doses, efftox_priors, tox_cutoff, eff_cutoff, tox_certainty, eff_certainty, metric, trial_size,
first_dose)
The EffTox class is an object-oriented implementation of the trial design by Thall & Cook (Thall, P. F., & Cook, J. D. (2004). Dose-Finding Based on Efficacy-Toxicity Trade-Offs. Biometrics, 60(3), 684–693.)
Outcomes for a patient are represented by a three item tuple, where:
Outcomes for several patients are represented as lists:
In [7]:
outcomes1 = [(3, 0, 0), (3, 1, 0), (3, 0, 1)]
In [8]:
np.random.seed(123)
et.update(outcomes1, n=10**6)
Out[8]:
In this instance, escalation to dose-level 4 is recommended.
In [9]:
et.tabulate()
Out[9]:
We see that all doses are admissible in this instance, and that the utilities of dose-levels 3 and 4 are very similar. Dose Ambivalence is the likely result, i.e. after observing 3NTE in the Matchpoint trial, the design would have recommended dose 3 or dose 4. The reason is made plain by the plot below.
In [10]:
et.plot_posterior_utility_density(include_doses=[3,4], boot_samps=1000)
Out[10]:
The posterior distributions of the utility of doses 3 and 4 largely occupy the same space so picking between them is difficult. In the Ambivalence.ipynb tutorial, we demonstrate a method for dealing with dose ambivalence.
The plot above is similar (but not identical) to Figure 2 in the publication. I used the R package ggplot2 to produce the plots for the paper because the R package is more mature than the Python version. For instance, I could not get a legend to appear in Python.
In [11]:
outcomes2 = [
(2, 0, 0), (2, 0, 0), (2, 0, 0),
(3, 0, 1), (3, 0, 0), (3, 0, 0),
(4, 0, 1), (4, 1, 1), (4, 0, 1),
(3, 1, 0), (3, 0, 1), (3, 0, 1),
(4, 0, 0), (4, 0, 1), (4, 0, 1),
]
In [12]:
et.reset()
et.update(outcomes2, n=10**6)
Out[12]:
In [13]:
et.tabulate()
Out[13]:
Dose 4 is now clearly the preferable dose.
In [14]:
et.plot_posterior_utility_density(include_doses=[3,4], boot_samps=1000)
Out[14]:
That is reflected in the estimates of the posterior utility curves.
The plot above is similar (but not identical) to Figure 3 in the publication.
In [ ]: