| Title: | Dose Transition Pathways for Time-to-Event Dose-Finding Designs |
|---|---|
| Description: | Implements the Dose Transition Pathways (DTP) look-ahead strategy for time-to-event phase I dose-finding clinical trials with delayed or pending toxicity outcomes. Provides a DTP decorator for the 'escalation' framework, supporting both TITE-CRM (model-based) and TITE-BOIN (model-assisted) base designs. |
| Authors: | Xiaoran Lai [aut, cre], The Institute of Cancer Research [cph], National Institute for Health and Care Research [fnd] |
| Maintainer: | Xiaoran Lai <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.1.0 |
| Built: | 2026-10-21 17:42:09 UTC |
| Source: | https://github.com/cran/dtptite |
Wraps a parent TITE selector factory with the Dose Transition Pathways
projection engine. At fit time, the decorator checks whether waiting
for pending patients' follow-up (up to t_max) could change the dose
recommendation upward.
apply_dtp( parent_selector_factory, t_max, obswin, projection_search = c("binary", "linear"), verbose = TRUE )apply_dtp( parent_selector_factory, t_max, obswin, projection_search = c("binary", "linear"), verbose = TRUE )
parent_selector_factory |
A |
t_max |
Maximum allowable wait time (numeric >= 0, or |
obswin |
DLT observation window length (e.g. 56 days or 8 weeks).
Defines the time-weight mapping: |
projection_search |
Strategy used to locate the minimum wait time.
|
verbose |
If |
A dtp_selector_factory object.
library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Four patients at dose 2: one DLT, and the last patient is only 30% of the # way through the observation window. outcomes <- data.frame(dose = c(2, 2, 2, 2), tox = c(0, 1, 0, 0), weight = c(1, 1, 1, 0.3), cohort = 1:4) x <- fit(design, outcomes) recommended_dose(x) # de-escalate now... dtp_should_wait(x) # ...but waiting could change that dtp_wait_time(x) # days to wait dtp_wait_time(x, type = "weight") # the same wait as a weight increment dtp_projected_dose(x) # recommendation after the waitlibrary(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Four patients at dose 2: one DLT, and the last patient is only 30% of the # way through the observation window. outcomes <- data.frame(dose = c(2, 2, 2, 2), tox = c(0, 1, 0, 0), weight = c(1, 1, 1, 0.3), cohort = 1:4) x <- fit(design, outcomes) recommended_dose(x) # de-escalate now... dtp_should_wait(x) # ...but waiting could change that dtp_wait_time(x) # days to wait dtp_wait_time(x, type = "weight") # the same wait as a weight increment dtp_projected_dose(x) # recommendation after the wait
Projected dose after waiting.
dtp_projected_dose(x, ...)dtp_projected_dose(x, ...)
x |
A |
... |
Additional arguments (unused). |
Integer dose level, or NA if waiting has no benefit.
library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Four patients at dose 2: one DLT, and the last patient is only 30% of the # way through the observation window. outcomes <- data.frame(dose = c(2, 2, 2, 2), tox = c(0, 1, 0, 0), weight = c(1, 1, 1, 0.3), cohort = 1:4) x <- fit(design, outcomes) recommended_dose(x) # de-escalate now... dtp_should_wait(x) # ...but waiting could change that dtp_wait_time(x) # days to wait dtp_wait_time(x, type = "weight") # the same wait as a weight increment dtp_projected_dose(x) # recommendation after the waitlibrary(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Four patients at dose 2: one DLT, and the last patient is only 30% of the # way through the observation window. outcomes <- data.frame(dose = c(2, 2, 2, 2), tox = c(0, 1, 0, 0), weight = c(1, 1, 1, 0.3), cohort = 1:4) x <- fit(design, outcomes) recommended_dose(x) # de-escalate now... dtp_should_wait(x) # ...but waiting could change that dtp_wait_time(x) # days to wait dtp_wait_time(x, type = "weight") # the same wait as a weight increment dtp_projected_dose(x) # recommendation after the wait
Returns TRUE if the DTP projection found that waiting could lead to
a higher dose recommendation within t_max.
dtp_should_wait(x, ...)dtp_should_wait(x, ...)
x |
A |
... |
Additional arguments (unused). |
Logical scalar.
library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Four patients at dose 2: one DLT, and the last patient is only 30% of the # way through the observation window. outcomes <- data.frame(dose = c(2, 2, 2, 2), tox = c(0, 1, 0, 0), weight = c(1, 1, 1, 0.3), cohort = 1:4) x <- fit(design, outcomes) recommended_dose(x) # de-escalate now... dtp_should_wait(x) # ...but waiting could change that dtp_wait_time(x) # days to wait dtp_wait_time(x, type = "weight") # the same wait as a weight increment dtp_projected_dose(x) # recommendation after the waitlibrary(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Four patients at dose 2: one DLT, and the last patient is only 30% of the # way through the observation window. outcomes <- data.frame(dose = c(2, 2, 2, 2), tox = c(0, 1, 0, 0), weight = c(1, 1, 1, 0.3), cohort = 1:4) x <- fit(design, outcomes) recommended_dose(x) # de-escalate now... dtp_should_wait(x) # ...but waiting could change that dtp_wait_time(x) # days to wait dtp_wait_time(x, type = "weight") # the same wait as a weight increment dtp_projected_dose(x) # recommendation after the wait
Returns a tidy tibble with one row per DTP wait event fired across all
simulated replicates. This is the single source of truth from which all
DTP wait summaries are derived; users who want metrics not covered by
dtp_wait_summary() can compute them directly from this table.
dtp_wait_events(x, ...)dtp_wait_events(x, ...)
x |
A |
... |
Unused. |
Replicates with zero waits contribute zero rows (but are still reflected
in dtp_wait_summary() with explicit 0s). Replicates from non-DTP
designs contribute zero rows and are flagged by the design carrying no
event log at all, not by reporting zero waits.
A tibble with columns replicate (and design for a
simulations_collection), cohort_idx, dose_before, time_in,
time_out, wait_duration, projected_dose, dose_after,
ended_by (factor: wait_end/dtp_decision/stopped), dose_delta,
effective, num_extensions, n_held, n_missed.
wait_duration is the total elapsed time between when the wait was
triggered and when it ended, including any extensions caused by
in-wait DLT events: each such event prompts a re-fit, and if the
updated fit still requests a wait the original wait_end is bumped
out. num_extensions records how many times that happened (0 means
the wait ran exactly to its initial projection); as a result
wait_duration can exceed the design's t_max.
n_held is the number of patients held through the wait and dosed at
wait_end, including the cohort opener (the patient the wait is for);
it is at least 1 for any wait that doses and ranges up to the cohort size.
n_missed is the number who arrived while the wait was running to a full
waiting room and were never enrolled. See set_dtp_queue_size() for the
room capacity that bounds n_held and produces n_missed.
library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 9) set.seed(456) sims <- simulate_trials( design, num_sims = 2, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56 ) dtp_wait_events(sims) dtp_wait_summary(sims) dtp_wait_summary(sims, by_dose = TRUE)library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 9) set.seed(456) sims <- simulate_trials( design, num_sims = 2, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56 ) dtp_wait_events(sims) dtp_wait_summary(sims) dtp_wait_summary(sims, by_dose = TRUE)
Aggregates the raw event log returned by dtp_wait_events() into a
curated per-replicate (or per-replicate × starting dose) summary.
dtp_wait_summary(x, by_dose = FALSE, ...)dtp_wait_summary(x, by_dose = FALSE, ...)
x |
A |
by_dose |
If |
... |
Unused. |
With the default by_dose = FALSE, one row per replicate with columns:
num_waits — how often DTP fired in this trial
total_wait_time — sum of wait durations
wait_fraction — total_wait_time / trial_duration, a single
comparable "DTP overhead" number. The denominator is the full trial
calendar time as returned by escalation::trial_duration(), which
includes the post-loop "advance to full follow-up" tail. Use the raw
event log if you need a decision-phase-only denominator.
max_wait_time — longest single wait (for slot / IRB conversations).
Can exceed t_max when an in-wait DLT triggers an extension; see
dtp_wait_events().
num_effective_waits — number of waits where the post-wait
recommendation was strictly higher than the pre-wait recommendation
(dose_after > dose_before). Captures both outright escalations and
waits that recovered from an otherwise unnecessary de-escalation.
num_missed — per-trial sum of the event-log n_missed: patients who
presented during a wait to a full waiting room and were never enrolled.
This is DTP's accrual cost, and is zero whenever no wait ran longer than
the room capacity allows.
With by_dose = TRUE, one row per (replicate × dose_before).
wait_fraction (needs a whole-trial denominator) is dropped and a
mean_wait_time column is added; max_wait_time and
num_effective_waits are retained per dose level.
Non-DTP designs — those whose simulation did not attach a wait event log
at all — return all-NA metric columns so that users can distinguish
"design did not run under DTP" from "ran under DTP and never waited"
(num_waits = 0).
On a simulations_collection (e.g. the return value of
simulate_compare), both accessors prepend a design column naming
the arm.
A tibble. See Details for columns.
library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 9) set.seed(456) sims <- simulate_trials( design, num_sims = 2, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56 ) dtp_wait_events(sims) dtp_wait_summary(sims) dtp_wait_summary(sims, by_dose = TRUE)library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 9) set.seed(456) sims <- simulate_trials( design, num_sims = 2, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56 ) dtp_wait_events(sims) dtp_wait_summary(sims) dtp_wait_summary(sims, by_dose = TRUE)
Minimum wait time before the dose recommendation changes.
dtp_wait_time(x, type = c("time", "weight"), ...)dtp_wait_time(x, type = c("time", "weight"), ...)
x |
A |
type |
Character: |
... |
Additional arguments (unused). |
Numeric scalar (0 if no benefit from waiting).
library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Four patients at dose 2: one DLT, and the last patient is only 30% of the # way through the observation window. outcomes <- data.frame(dose = c(2, 2, 2, 2), tox = c(0, 1, 0, 0), weight = c(1, 1, 1, 0.3), cohort = 1:4) x <- fit(design, outcomes) recommended_dose(x) # de-escalate now... dtp_should_wait(x) # ...but waiting could change that dtp_wait_time(x) # days to wait dtp_wait_time(x, type = "weight") # the same wait as a weight increment dtp_projected_dose(x) # recommendation after the waitlibrary(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Four patients at dose 2: one DLT, and the last patient is only 30% of the # way through the observation window. outcomes <- data.frame(dose = c(2, 2, 2, 2), tox = c(0, 1, 0, 0), weight = c(1, 1, 1, 0.3), cohort = 1:4) x <- fit(design, outcomes) recommended_dose(x) # de-escalate now... dtp_should_wait(x) # ...but waiting could change that dtp_wait_time(x) # days to wait dtp_wait_time(x, type = "weight") # the same wait as a weight increment dtp_projected_dose(x) # recommendation after the wait
Returns a selector factory for the BOIN design with TITE
(time-to-event) support via effective sample sizes. This is a barebone
selector: stopping, elimination, and overdose control are added via
piping (e.g. stop_for_beta_binomial_toxicity, dont_skip_doses).
get_boin_tite( num_doses, target, p.saf = 0.6 * target, p.tox = 1.4 * target, ... )get_boin_tite( num_doses, target, p.saf = 0.6 * target, p.tox = 1.4 * target, ... )
num_doses |
Number of doses under investigation. |
target |
Target toxicity probability. |
p.saf |
Safety boundary parameter (default |
p.tox |
Toxicity boundary parameter (default |
... |
Extra arguments stored for future use. |
A boin_tite_selector_factory object.
# Barebone — pure dose decision library(escalation) get_boin_tite(5, 0.25) %>% fit(data.frame(dose = c(1,1,1), tox = c(0,0,0), weight = c(1,1,1), cohort = c(1,1,1)))# Barebone — pure dose decision library(escalation) get_boin_tite(5, 0.25) %>% fit(data.frame(dose = c(1,1,1), tox = c(0,0,0), weight = c(1,1,1), cohort = c(1,1,1)))
Draws, for each design, the proportion of replicates in which a patient had
been dosed at the true MTD by a given point. The curve plateaus at
reached_fraction; replicates that never reached the MTD keep it below 1.
## S3 method for class 'time_to_first_mtd' plot(x, axis = c("time", "patients"), ci = FALSE, conf = 0.95, ...)## S3 method for class 'time_to_first_mtd' plot(x, axis = c("time", "patients"), ci = FALSE, conf = 0.95, ...)
x |
A |
axis |
|
ci |
If |
conf |
Confidence level for the intervals. Default |
... |
Unused. |
A ggplot object.
library(escalation) skeleton <- c(0.124, 0.25, 0.398, 0.542, 0.666) designs <- list( `TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> stop_at_n(n = 18), `DTP + TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 18) ) set.seed(456) sims <- simulate_compare( designs, num_sims = 10, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56, i_like_big_trials = TRUE ) ttm <- time_to_first_mtd(sims) ttm summary(ttm) if (requireNamespace("ggplot2", quietly = TRUE)) { plot(ttm) }library(escalation) skeleton <- c(0.124, 0.25, 0.398, 0.542, 0.666) designs <- list( `TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> stop_at_n(n = 18), `DTP + TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 18) ) set.seed(456) sims <- simulate_compare( designs, num_sims = 10, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56, i_like_big_trials = TRUE ) ttm <- time_to_first_mtd(sims) ttm summary(ttm) if (requireNamespace("ggplot2", quietly = TRUE)) { plot(ttm) }
Identifies the dose whose true toxicity probability lies within tol of the
target. When several doses qualify the lowest is returned. When none
qualifies the scenario has no MTD and NA is returned with a warning.
scenario_mtd(true_prob_tox, target, tol = 0.05)scenario_mtd(true_prob_tox, target, tol = 0.05)
true_prob_tox |
Numeric vector of true toxicity probabilities, one per dose. |
target |
Target toxicity probability. |
tol |
Half-width of the acceptance band. A dose qualifies when
|
Integer dose index, or NA_integer_ when no dose qualifies.
scenario_mtd(c(0.05, 0.15, 0.25, 0.35, 0.60), target = 0.25) # Two doses inside the band: the lowest is the MTD scenario_mtd(c(0.05, 0.22, 0.27, 0.50), target = 0.25)scenario_mtd(c(0.05, 0.15, 0.25, 0.35, 0.60), target = 0.25) # Two doses inside the band: the lowest is the MTD scenario_mtd(c(0.05, 0.22, 0.27, 0.50), target = 0.25)
Recruitment onto the trial is shut for the duration of a DTP wait, but the
pool of available patients keeps accruing. Patients who present during a
wait are held — up to queue_size of them — and dosed at the post-wait
recommendation the moment the wait ends. Patients who present when the room
is already full are not enrolled; they are the accrual cost of waiting,
reported as the n_missed column of dtp_wait_events().
set_dtp_queue_size(dtp_selector_factory, queue_size)set_dtp_queue_size(dtp_selector_factory, queue_size)
dtp_selector_factory |
A |
queue_size |
Integer >= 0, and no greater than the cohort size.
Default (when not set) equals the cohort size, inferred at simulation time
from the first |
A patient is therefore missed exactly when
wait_duration > queue_size * accrual_gap, which concentrates the cost at
small cohort sizes.
The patient whose arrival opened the cohort is always held — they are the reason the wait is being taken — so they occupy one slot and values below 1 behave as 1. At cohort size 1 the capacity therefore cannot bind: a single-patient cohort has no room for anyone else whatever this is set to. The knob only does work for cohorts of 2 or more.
The modified dtp_selector_factory (invisibly).
library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Hold at most two patients while a wait runs set_dtp_queue_size(design, 2)library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> apply_dtp(t_max = 35, obswin = 56) # Hold at most two patients while a wait runs set_dtp_queue_size(design, 2)
Creates a stopping decorator that monitors one or more doses and halts
the trial when the posterior probability of the true toxicity rate
exceeding tox_threshold is greater than confidence.
stop_for_beta_binomial_toxicity( parent_selector_factory, dose = 1, tox_threshold, confidence = 0.88, a = NULL, b = NULL, n_min = 1 )stop_for_beta_binomial_toxicity( parent_selector_factory, dose = 1, tox_threshold, confidence = 0.88, a = NULL, b = NULL, n_min = 1 )
parent_selector_factory |
A |
dose |
Which dose(s) to monitor. A numeric scalar (e.g. |
tox_threshold |
Toxicity probability threshold. Required. |
confidence |
Posterior exceedance cutoff (default: |
a, b
|
Beta prior hyperparameters. When |
n_min |
Minimum number of patients at a dose required before the
exceedance check fires (default: |
A beta_binom_tox_selector_factory object.
library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> stop_for_beta_binomial_toxicity(dose = 1, tox_threshold = 0.25, confidence = 0.70) # Three DLTs in four patients at the lowest dose stops the trial outcomes <- data.frame(dose = c(1, 1, 1, 1), tox = c(1, 1, 0, 1), weight = c(1, 1, 1, 1), cohort = 1:4) x <- fit(design, outcomes) continue(x) recommended_dose(x)library(escalation) design <- get_dfcrm_tite(skeleton = c(0.124, 0.25, 0.398, 0.542, 0.666), target = 0.25) |> stop_for_beta_binomial_toxicity(dose = 1, tox_threshold = 0.25, confidence = 0.70) # Three DLTs in four patients at the lowest dose stops the trial outcomes <- data.frame(dose = c(1, 1, 1, 1), tox = c(1, 1, 0, 1), weight = c(1, 1, 1, 1), cohort = 1:4) x <- fit(design, outcomes) continue(x) recommended_dose(x)
Summarise time-to-first-MTD across replicates.
## S3 method for class 'time_to_first_mtd' summary(object, probs = NULL, ...)## S3 method for class 'time_to_first_mtd' summary(object, probs = NULL, ...)
object |
A |
probs |
Optional numeric vector of probabilities for additional
quantile columns. Must be distinct values between 0 and 1. Default |
... |
Unused. |
Columns:
num_sims — replicates simulated
mtd — dose treated as the true MTD
num_reached — replicates in which a patient was dosed at mtd
reached_fraction — num_reached / num_sims; NA when the scenario has
no MTD
median_time_to_mtd — median of the cumulative incidence of reaching the
MTD. NA unless more than half of replicates reached it, because the
quantile is otherwise undefined — including when exactly half did
median_n_before_mtd — median patients dosed before the MTD, over
replicates that reached it
Replicates that never reached the MTD remain in the denominator; they are
not dropped. Any probability supplied in probs adds a
q<pct>_time_to_mtd column, computed the same way and likewise NA beyond
reached_fraction. The percentage is not rounded, so 0.125 gives
q12.5_time_to_mtd; distinct probabilities always get distinct columns.
A tibble with one row per design.
library(escalation) skeleton <- c(0.124, 0.25, 0.398, 0.542, 0.666) designs <- list( `TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> stop_at_n(n = 18), `DTP + TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 18) ) set.seed(456) sims <- simulate_compare( designs, num_sims = 10, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56, i_like_big_trials = TRUE ) ttm <- time_to_first_mtd(sims) ttm summary(ttm) if (requireNamespace("ggplot2", quietly = TRUE)) { plot(ttm) }library(escalation) skeleton <- c(0.124, 0.25, 0.398, 0.542, 0.666) designs <- list( `TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> stop_at_n(n = 18), `DTP + TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 18) ) set.seed(456) sims <- simulate_compare( designs, num_sims = 10, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56, i_like_big_trials = TRUE ) ttm <- time_to_first_mtd(sims) ttm summary(ttm) if (requireNamespace("ggplot2", quietly = TRUE)) { plot(ttm) }
Returns one row per simulated replicate recording when, if ever, a patient was first treated at the scenario's true MTD.
time_to_first_mtd(x, mtd = NULL, tol = 0.05, ...)time_to_first_mtd(x, mtd = NULL, tol = 0.05, ...)
x |
A |
mtd |
Dose index to treat as the true MTD. |
tol |
Passed to |
... |
Unused. |
Times are dosing times measured from the start of the trial (t = 0). For
designs without DTP a patient is dosed on arrival, so dosing time equals
recruitment time; for patients held in a DTP queue it is the instant the
wait ends and they are dosed.
Columns:
replicate — index of the simulated trial (and design for a
simulations_collection)
mtd — the dose treated as the true MTD
time_to_mtd — dosing time of the first patient given mtd, or NA if
no patient was given it before the trial ended
reached — whether any patient was dosed at mtd; NA when the scenario
has no MTD
n_before_mtd — patients dosed strictly earlier than that patient, or
NA if the MTD was never given
When the scenario has no MTD (no dose within tol of the target) every row
carries mtd = NA and reached = NA, distinguishing "no MTD to reach" from
"an MTD existed and was not reached" (reached = FALSE).
The number of replicates is recorded in a num_sims attribute and is used
as the denominator by summary.time_to_first_mtd().
A tibble of class time_to_first_mtd. See Details for columns.
library(escalation) skeleton <- c(0.124, 0.25, 0.398, 0.542, 0.666) designs <- list( `TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> stop_at_n(n = 18), `DTP + TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 18) ) set.seed(456) sims <- simulate_compare( designs, num_sims = 10, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56, i_like_big_trials = TRUE ) ttm <- time_to_first_mtd(sims) ttm summary(ttm) if (requireNamespace("ggplot2", quietly = TRUE)) { plot(ttm) }library(escalation) skeleton <- c(0.124, 0.25, 0.398, 0.542, 0.666) designs <- list( `TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> stop_at_n(n = 18), `DTP + TITE-CRM` = get_dfcrm_tite(skeleton = skeleton, target = 0.25) |> apply_dtp(t_max = 35, obswin = 56, verbose = FALSE) |> stop_at_n(n = 18) ) set.seed(456) sims <- simulate_compare( designs, num_sims = 10, true_prob_tox = c(0.05, 0.15, 0.25, 0.35, 0.60), sample_patient_arrivals = function(df) { cohorts_of_n(n = 3, mean_time_delta = 1) }, max_time = 56, i_like_big_trials = TRUE ) ttm <- time_to_first_mtd(sims) ttm summary(ttm) if (requireNamespace("ggplot2", quietly = TRUE)) { plot(ttm) }
Generates a list of escalation::PatientSample objects whose
tox_time values are drawn from U(0, max_time) instead of the
default U(0, 1). Pass the result to
escalation::simulate_compare() or escalation::simulate_trials()
via patient_samples.
tite_patient_samples(num_sims, max_time, num_patients = 100)tite_patient_samples(num_sims, max_time, num_patients = 100)
num_sims |
Number of simulation replicates. |
max_time |
DLT observation window (e.g. 56 days). Must match the
|
num_patients |
Number of latent patients per sample (default 100). |
A list of length num_sims, each element a PatientSample.
samples <- tite_patient_samples(num_sims = 2, max_time = 56) length(samples)samples <- tite_patient_samples(num_sims = 2, max_time = 56) length(samples)