| Type: | Package |
| Title: | Assurance Methods for Clinical Trials with a Delayed Treatment Effect |
| Version: | 1.3.0 |
| Description: | Provides functions for planning clinical trials subject to a delayed treatment effect using assurance-based methods. Includes two 'shiny' applications for interactive exploration, simulation, and visualisation of trial designs and outcomes. The methodology is described in: Salsbury JA, Oakley JE, Julious SA, Hampson LV (2024) "Assurance methods for designing a clinical trial with a delayed treatment effect" <doi:10.1002/sim.10136>, Salsbury JA, Oakley JE, Julious SA, Hampson LV (2024) "Adaptive clinical trial design with delayed treatment effects using elicited prior distributions" <doi:10.48550/arXiv.2509.07602>. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| LazyData: | true |
| RoxygenNote: | 7.3.3 |
| Imports: | SHELF, stats, survival, nph, nphRCT, dplyr, rpact, magrittr, rlang, future.apply |
| Suggests: | testthat (≥ 3.0.0), nleqslv, rjags, coda, shiny, shinyAce, shinyBS, shinyjs, rhandsontable, plotly |
| Config/testthat/edition: | 3 |
| Depends: | R (≥ 4.0) |
| URL: | https://jamesalsbury.github.io/DTEAssurance/ |
| NeedsCompilation: | no |
| Packaged: | 2026-10-13 15:55:26 UTC; jamesalsbury |
| Author: | James Salsbury |
| Maintainer: | James Salsbury <jsalsbury1@sheffield.ac.uk> |
| Repository: | CRAN |
| Date/Publication: | 2026-10-13 16:10:24 UTC |
Pipe operator
Description
See magrittr::%>% for details.
Usage
lhs %>% rhs
Arguments
lhs |
A value or the magrittr placeholder. |
rhs |
A function call using the magrittr semantics. |
Value
The result of calling rhs(lhs).
Deprecated functions in DTEAssurance
Description
These functions were renamed to match the manuscript notation (PP for the predictive probability, kappa for the futility threshold) and will be removed in the next release. Each one forwards its arguments to its replacement.
Usage
BPP_func(...)
calibrate_BPP_threshold(...)
calibrate_BPP_timing(...)
summarize_grid_by_lambda(raw, lambda_grid, conf_level = 0.9)
select_lambda_star(...)
Arguments
... |
Arguments passed to the replacement function. |
raw, lambda_grid, conf_level |
See |
Details
Only the function names are translated. The elements and columns they
return use the new names (PP_df, PP_vec, PP_values,
PP_val, kappa, kappa_star), so code that reads
BPP_df, BPP_vec, lambda_star, etc. must be updated.
-
BPP_func(): usePP_func. -
calibrate_BPP_threshold(): usecalibrate_PP_threshold. -
calibrate_BPP_timing(): usecalibrate_PP_timing. -
summarize_grid_by_lambda(): usesummarize_grid_by_kappa. -
select_lambda_star(): useselect_kappa_star.
Value
The return value of the replacement function.
INTEREST data set
Description
A reconstructed survival data set for the INTEREST clinical trial
Usage
INTEREST
Format
A data frame with 710 rows and 2 variables:
- Survival time
Survival Time (in months)
- Status
Event indicator (0=Alive, 1=Dead)
Source
Reconstructed survival data set from the following publication: https://www.sciencedirect.com/science/article/pii/S0140673608617584?via%3Dihub
MCMC_sample
Description
An MCMC sample for the example given in Salsbury et al (2024)
Usage
MCMC_sample
Format
A data frame with 100000 rows and 1 variables:
- x
Sample from the MAP prior
Source
A MCMC sample for the control group for the example given in https://onlinelibrary.wiley.com/doi/full/10.1002/sim.10136. Three historical data seta are used to generate a Meta-Analytic-Predictive Prior distribution
Calculate the predictive probability (PP) given interim data and posterior samples
Description
Calculate the predictive probability (PP) given interim data and posterior samples
Usage
PP_func(
data,
posterior_df,
control_distribution = "Exponential",
n_c_planned,
n_t_planned,
rec_time_planned,
df_cens_time,
analysis_model,
censoring_model = NULL,
future_boundaries = NULL,
n_sims
)
Arguments
data |
A data frame containing interim survival data, censored at
|
posterior_df |
A data frame of posterior samples with columns:
|
control_distribution |
Distributional form assumed for the control arm:
either |
n_c_planned |
Planned maximum number of patients in the control group. |
n_t_planned |
Planned maximum number of patients in the treatment group. |
rec_time_planned |
Planned maximum recruitment calendar time for the full trial. |
df_cens_time |
Calendar time at which |
analysis_model |
A named list specifying the analysis method and decision rule:
|
censoring_model |
Legacy fallback, deprecated (see the
Deprecated section). Used only if
|
future_boundaries |
Recommended. A list of future, pre-specified, fixed decision points to evaluate on each posterior-predictive draw, in ascending chronological order, matching the trial's own group-sequential design. Each element is a list with:
On each predictive draw, boundaries are checked in order: if Scope: |
n_sims |
Number of posterior-predictive draws (required, no default). |
Details
Model. The control arm is Weibull with rate lambda_c and
shape gamma_c; an exponential control arm
(control_distribution = "Exponential") is handled as the Weibull
case with gamma_c = 1, using the same code path. The treatment arm
follows the control hazard up to delay_time and the control hazard
multiplied by HR afterwards. Each predictive draw samples one row
of posterior_df, simulates event times for patients not yet
recruited, and simulates residual event times for patients censored at
the interim, conditional on their follow-up so far.
Recruitment assumption. Recruitment times for patients not yet
recruited at the interim are drawn from
Uniform(df_cens_time, rec_time_planned). This is correct for
uniform recruitment (the "power" recruitment model with
power = 1) only; the simulation functions that call
PP_func() stop if another recruitment model is supplied.
Value
A list with a single element PP_df, a data frame with
columns success (0/1, whether this predictive draw ultimately
rejects H_0, accounting for any future fixed efficacy boundaries)
and Z_val (the test statistic at the analysis where the draw was
decided). The predictive probability is mean(PP_df$success).
Deprecated
The exponential control arm (control_distribution = "Exponential")
and the legacy single-stage censoring_model fallback are
deprecated and will be removed in a future release. Use
control_distribution = "Weibull" (an exponential control arm is
the Weibull case with gamma_c = 1) and future_boundaries.
Examples
set.seed(123)
n <- 30
cens_time <- 15
time <- runif(n, 0, 12)
rec_time <- runif(n, 0, 12)
df <- data.frame(
time = time,
group = c(rep("Control", n/2), rep("Treatment", n/2)),
rec_time = rec_time
)
df$pseudo_time <- df$time + df$rec_time
df$status <- df$pseudo_time < cens_time
df$survival_time <- ifelse(df$status == TRUE, df$time, cens_time - df$rec_time)
posterior_df <- data.frame(HR = rnorm(20, mean = 0.75, sd = 0.05),
delay_time = rep(0, 20),
lambda_c = rnorm(20, log(2)/9, sd = 0.01))
analysis_model <- list(method = "LRT", alpha = 0.025,
alternative_hypothesis = "one.sided")
# Recommended usage: pass the design's own future boundaries, e.g. a single
# efficacy look at 20 events (Z > 2.24) followed by a final analysis at
# 28 events (Z > 2.00):
future_boundaries <- list(
list(events = 20, crit = 2.24),
list(events = 28, crit = 2.00)
)
PP_outcome <- PP_func(df, posterior_df,
control_distribution = "Exponential",
n_c_planned = n/2, n_t_planned = n/2,
rec_time_planned = 12, df_cens_time = 15,
analysis_model = analysis_model,
future_boundaries = future_boundaries,
n_sims = 10)
REVEL data set
Description
A reconstructed survival data set for the REVEL clinical trial
Usage
REVEL
Format
A data frame with 625 rows and 2 variables:
- Survival time
Survival Time (in months)
- Status
Event indicator (0=Alive, 1=Dead)
Source
Reconstructed survival data set from the following publication: https://www.thelancet.com/journals/lancet/article/PIIS0140-6736(14)60845-X/fulltext
ZODIAC data set
Description
A reconstructed survival data set for the ZODIAC clinical trial
Usage
ZODIAC
Format
A data frame with 697 rows and 2 variables:
- Survival time
Survival Time (in months)
- Status
Event indicator (0=Alive, 1=Dead)
Source
Reconstructed survival data set from the following publication: https://www.sciencedirect.com/science/article/abs/pii/S1470204510701327?via%3Dihub
Add recruitment time to a survival dataset
Description
Simulates recruitment timing for each patient in a survival dataset using either a power model or a piecewise constant (PWC) model. The function appends recruitment times and pseudo survival times (time from recruitment to event or censoring).
Usage
add_recruitment_time(
data,
rec_method,
rec_period = NULL,
rec_power = NULL,
rec_rate = NULL,
rec_duration = NULL
)
Arguments
data |
A dataframe containing survival data with columns: |
rec_method |
Recruitment method: |
rec_period |
Period length for the power model |
rec_power |
Power parameter for the power model |
rec_rate |
Comma-separated string of recruitment rates for the PWC model |
rec_duration |
Comma-separated string of durations corresponding to each rate in the PWC model |
Value
A dataframe with two additional columns:
- rec_time
Simulated recruitment time for each patient
- pseudo_time
Time from recruitment to event or censoring
Class: data.frame
Examples
set.seed(123)
df <- data.frame(
time = rexp(20, rate = 0.1),
status = rbinom(20, 1, 0.8),
group = rep(c("Control", "Treatment"), each = 10)
)
recruited <- add_recruitment_time(df, rec_method = "power", rec_period = 12, rec_power = 1)
head(recruited)
Apply a group-sequential design to one simulated trial
Description
Runs the looks of a group-sequential design on one simulated trial, in
order, stopping at the first look whose rule is met: efficacy if Z exceeds
the efficacy critical value, futility under the design's futility rule
("Beta": Z below the beta-spending bound; "MatchedZ": Z
below GSD_model$futility_boundary_Z; "PP": predictive
probability below GSD_model$kappa), and otherwise the final
analysis. Each look cuts the trial with cens_data at
floor(IF * total_events) events. This is the engine of
calc_dte_assurance_adaptive. For simulation studies, use
run_paired_scenario and apply_design_rule,
which evaluate all designs on the same replicates.
Usage
apply_GSD_to_trial(
n_c,
n_t,
trial_data,
design,
total_events,
GSD_model,
control_model = NULL,
effect_model = NULL,
recruitment_model = NULL,
analysis_model = NULL,
update_priors_sims = NULL,
PP_sims = NULL,
.PP_val = NULL
)
Arguments
n_c, n_t |
Planned number of patients in the control / treatment arm. |
trial_data |
A simulated trial with columns |
design |
The |
total_events |
Maximum planned number of events. |
GSD_model |
The design specification (see
|
control_model, effect_model, recruitment_model |
Analysis prior and
recruitment model, used only for |
analysis_model |
Test specification ( |
update_priors_sims, PP_sims |
MCMC samples per chain and predictive
draws; required for |
.PP_val |
Internal, for testing: a precomputed predictive probability to use at the PP futility look instead of computing it. |
Value
A list with decision ("Stop for efficacy",
"Stop for futility", "Successful at final" or
"Unsuccessful at final"), stop_time, sample_size,
PP_val, converged and Z_probs.
Apply a design rule to paired replicate output
Description
Turns the output of run_paired_scenario into the decisions
of one design, post hoc. The efficacy look is only checked if the trial
was not stopped at the futility look. A missing test statistic never
crosses a boundary (as in apply_GSD_to_trial).
Usage
apply_design_rule(raw, rule)
Arguments
raw |
The |
rule |
A list with |
Details
- D1
Fixed design: success iff
Z_fin_LRT > crit_final.- D2
Efficacy look then final:
"Stop for efficacy"ifZ_eff_LRT > crit_eff, otherwise the final analysis withZ_fin_LRT > crit_fin.- D3
D2 plus PP futility:
"Stop for futility"ifPP_val < kappa. Stops with an error ifPP_valisNAfor any replicate that did not fail (e.g. output fromcompute_PP = FALSE).- D4
D2 plus Z futility:
"Stop for futility"ifZ_int_LRT < z_fut.- D5
As D4 with the modestly weighted statistics
Z_int_MW_t<t>,Z_eff_MW_t<t>,Z_fin_MW_t<t>fort = mw_t_star.
D1, D2, D4 and D5 do not use PP_val, so they also work on output
from run_paired_scenario(compute_PP = FALSE).
Value
A data frame with one row per replicate and columns
decision ("Stop for efficacy", "Stop for futility",
"Successful at final" or "Unsuccessful at final"),
success, early_fut, early_eff, sample_size
and duration. Rows for failed replicates (non-missing
error) are NA.
See Also
run_paired_scenario, summarize_grid_by_kappa
Launch the 'shiny' adaptive assurance app
Description
Launches a 'shiny' application to simulate group sequential trials with delayed treatment effects (DTE) using elicited prior distributions. The app allows interactive exploration of trial designs and assurance calculations.
Usage
assurance_adaptive_shiny_app()
Value
No return value, called for side effects (invisibly returns NULL). The function launches an interactive 'shiny' application.
Examples
# Launch the interactive Shiny app
assurance_adaptive_shiny_app()
Launch the 'shiny' Assurance app
Description
Launches a 'shiny' application to calculate assurance for clinical trials where delayed treatment effects (DTE) may be present. The app allows elicitation of prior distributions and calculates assurance metrics.
Usage
assurance_shiny_app()
Value
No return value, called for side effects (invisibly returns NULL). The function launches an interactive 'shiny' application.
Examples
# Launch the interactive Shiny app
assurance_shiny_app()
Calculate Assurance for a Trial with a Delayed Treatment Effect
Description
Simulates operating characteristics for a clinical trial under prior uncertainty about a delayed treatment effect. The function integrates beliefs about control survival, treatment delay, post-delay hazard ratio, recruitment, censoring, and analysis method to estimate assurance and other trial metrics.
Usage
calc_dte_assurance(
n_c,
n_t,
control_model,
effect_model,
censoring_model,
recruitment_model,
analysis_model,
n_sims = 1000
)
Arguments
n_c |
Vector of control group sample sizes |
n_t |
Vector of treatment group sample sizes |
control_model |
A named list specifying the control arm survival distribution:
|
effect_model |
A named list specifying beliefs about the treatment effect:
|
censoring_model |
A named list specifying the censoring mechanism:
|
recruitment_model |
A named list specifying the recruitment process:
|
analysis_model |
A named list specifying the statistical test and decision rule:
|
n_sims |
Number of simulations to run (default = 1000) |
Value
A named list containing:
- assurance
Estimated assurance (probability of success under prior uncertainty)
- CI
95% confidence interval for assurance
- duration
Mean trial duration across simulations
- sample_size
Mean sample size across simulations
- diagnostics
Additional diagnostics if
success_threshold_HRis specified
Class: list
Examples
set.seed(123)
control_model <- list(dist = "Exponential", parameter_mode = "Fixed",
fixed_type = "Parameters", lambda = 0.1)
effect_model <- list(delay_SHELF = SHELF::fitdist(c(3, 4, 5),
probs = c(0.25, 0.5, 0.75), lower = 0, upper = 10),
delay_dist = "gamma",
HR_SHELF = SHELF::fitdist(c(0.55, 0.6, 0.7), probs = c(0.25, 0.5, 0.75), lower = 0, upper = 1.5),
HR_dist = "gamma",
P_S = 1, P_DTE = 0)
censoring_model <- list(method = "Time", time = 12)
recruitment_model <- list(method = "power", period = 12, power = 1)
analysis_model <- list(method = "LRT", alpha = 0.025, alternative_hypothesis = "two.sided")
result <- calc_dte_assurance(n_c = 300, n_t = 300,
control_model = control_model,
effect_model = effect_model,
censoring_model = censoring_model,
recruitment_model = recruitment_model,
analysis_model = analysis_model,
n_sims = 10)
str(result)
Calculates operating characteristics for a Group Sequential Trial with a Delayed Treatment Effect
Description
Simulates assurance and operating characteristics for a group sequential trial under prior uncertainty about a delayed treatment effect. The function integrates beliefs about control survival, treatment delay, post-delay hazard ratio, recruitment, and group sequential design (GSD) parameters.
Usage
calc_dte_assurance_adaptive(
n_c,
n_t,
control_model,
effect_model,
recruitment_model,
GSD_model,
analysis_model = NULL,
update_priors_sims = NULL,
PP_sims = NULL,
n_sims = 1000
)
Arguments
n_c |
Control group sample size |
n_t |
Treatment group sample size |
control_model |
A named list specifying the control arm survival distribution:
|
effect_model |
A named list specifying beliefs about the treatment effect:
|
recruitment_model |
A named list specifying the recruitment process:
|
GSD_model |
A named list specifying the group sequential design:
|
analysis_model |
A named list specifying the final analysis and decision rule:
|
update_priors_sims |
Number of posterior samples per chain for
each interim dataset, passed to |
PP_sims |
Number of predictive simulations per interim dataset,
passed to |
n_sims |
Number of simulations to run (default = 1000) |
Value
A data frame with one row per simulated trial and the following columns:
- Trial
Simulation index
- Decision
Final interim/final decision outcome – one of
"Stop for efficacy","Stop for futility","Successful at final", or"Unsuccessful at final". This is the single source of truth for trial outcome; use it directly rather than deriving success/failure independently.- StopTime
Time at which the trial stopped or completed
- SampleSize
Total sample size at the time of decision
- Success
Logical recode of
Decisionfor convenience:TRUEifDecision %in% c("Stop for efficacy", "Successful at final"),FALSEotherwise.- Converged
For
"PP"designs, whether the interim MCMC fit converged (seeupdate_priors);NAfor other futility types, which involve no MCMC step.- PP_val
For
"PP"designs, the predictive probability at the futility look;NAotherwise (or if the trial stopped for efficacy before the futility look).- P_Z1, P_Z2, P_Z3
For
"PP"designs, the posterior probabilities of the three latent states at the futility look;NAotherwise.
Class: data.frame, with attribute settings: a list of
all arguments, plus the package, R, rjags and JAGS versions, the git
commit of the working directory, the hostname and a timestamp.
Examples
set.seed(123)
control_model <- list(dist = "Exponential", parameter_mode = "Fixed",
fixed_type = "Parameters", lambda = 0.1)
effect_model <- list(P_S = 1, P_DTE = 0,
HR_SHELF = SHELF::fitdist(c(0.6, 0.65, 0.7), probs = c(0.25, 0.5, 0.75), lower = 0, upper = 2),
HR_dist = "gamma",
delay_SHELF = SHELF::fitdist(c(3, 4, 5), probs = c(0.25, 0.5, 0.75), lower = 0, upper = 10),
delay_dist = "gamma"
)
recruitment_model <- list(method = "power", period = 12, power = 1)
GSD_model <- list(events = 300, alpha_spending = c(0.0125, 0.025),
alpha_IF = c(0.75, 1), futility_type = "none")
result <- calc_dte_assurance_adaptive(n_c = 300, n_t = 300,
control_model = control_model,
effect_model = effect_model,
recruitment_model = recruitment_model,
GSD_model = GSD_model,
n_sims = 10)
str(result)
Function to calculate the 'optimal' PP threshold value
Description
Function to calculate the 'optimal' PP threshold value
Usage
calibrate_PP_threshold(
n_c,
n_t,
control_model,
effect_model,
recruitment_model,
IA_model,
analysis_model,
data_generating_model,
future_boundaries = NULL,
n_df_sims = 100,
update_priors_sims = 1000,
PP_sims = 2000,
n_cores = 1,
seed = NULL
)
Arguments
n_c |
Number of control patients |
n_t |
Number of treatment patients |
control_model |
A named list specifying the control arm survival distribution
(see |
effect_model |
A named list specifying beliefs about the treatment effect
(see |
recruitment_model |
A named list specifying the recruitment process
(see |
IA_model |
A named list specifying the interim analysis timing:
|
analysis_model |
A named list specifying the analysis method
(see |
data_generating_model |
A named list specifying the true data-generating parameters used to simulate trials for calibration:
|
future_boundaries |
Recommended. A list of future, pre-specified,
fixed decision points (efficacy look(s) and the final analysis) to check on
each posterior-predictive draw, matching the true group-sequential design
under which this PP threshold will actually be used – see
|
n_df_sims |
Number of interim datasets to simulate (default is 100). For calibration decisions near a specific power/Type I error target, consider a substantially larger number and report Monte Carlo standard errors alongside the result. |
update_priors_sims |
Number of posterior samples to generate per
interim dataset via |
PP_sims |
Number of predictive simulations used to estimate PP for
each interim dataset, passed to |
n_cores |
Number of cores to parallelise over via
|
seed |
Optional integer seed. If supplied, each simulated interim
dataset |
Value
A list with:
- PP_vec
A numeric vector of length
n_df_sims, the estimated PP for each simulated interim dataset.- settings
A list of all arguments, plus the package, R, rjags and JAGS versions, the git commit of the working directory, the hostname and a timestamp.
Deprecated
calibrate_PP_threshold() is deprecated and will be removed in a
future release. Use run_paired_scenario with
summarize_grid_by_kappa and select_kappa_star.
Examples
set.seed(123)
control_model <- list(dist = "Exponential", parameter_mode = "Distribution",
t1 = 12, t1_Beta_a = 20, t1_Beta_b = 32)
effect_model <- list(delay_SHELF = SHELF::fitdist(c(5.5, 6, 6.5),
probs = c(0.25, 0.5, 0.75), lower = 0, upper = 12),
delay_dist = "gamma",
HR_SHELF = SHELF::fitdist(c(0.5, 0.6, 0.7),
probs = c(0.25, 0.5, 0.75), lower = 0, upper = 1),
HR_dist = "gamma",
P_S = 1, P_DTE = 0)
recruitment_model <- list(method = "power", period = 12, power = 1)
IA_model <- list(events = 40, IF = 0.5)
analysis_model <- list(method = "LRT", alpha = 0.025,
alternative_hypothesis = "one.sided")
data_generating_model <- list(lambda_c = log(2)/12, gamma_c = NULL,
delay_time = 3, post_delay_HR = 0.75)
# A single future efficacy look at 30 events (Z > 2.24), then final at 40
# events (Z > 2.00) -- match this to the true design's own boundaries.
future_boundaries <- list(
list(events = 30, crit = 2.24),
list(events = 40, crit = 2.00)
)
# Deliberately small settings so the example runs quickly. For a real
# analysis use the defaults (update_priors_sims = 1000, PP_sims = 2000)
# and a larger n_df_sims.
threshold <- calibrate_PP_threshold(n_c = 25, n_t = 25,
control_model = control_model,
effect_model = effect_model,
recruitment_model = recruitment_model,
IA_model = IA_model,
analysis_model = analysis_model,
data_generating_model = data_generating_model,
future_boundaries = future_boundaries,
update_priors_sims = 100,
PP_sims = 100,
n_df_sims = 2)
Function to calculate the 'optimal' information fraction to calculate PP
Description
Function to calculate the 'optimal' information fraction to calculate PP
Usage
calibrate_PP_timing(
n_c,
n_t,
control_model,
effect_model,
recruitment_model,
IA_model,
analysis_model,
future_boundaries = NULL,
update_priors_sims = 1000,
PP_sims = 2000,
n_sims = 100,
n_cores = 1,
seed = NULL
)
Arguments
n_c |
Number of control patients |
n_t |
Number of treatment patients |
control_model |
A named list specifying the control arm survival distribution
(see |
effect_model |
A named list specifying beliefs about the treatment effect
(see |
recruitment_model |
A named list specifying the recruitment process
(see |
IA_model |
A named list specifying the censoring mechanism for the future data:
|
analysis_model |
A named list specifying the final analysis and decision rule
(see |
future_boundaries |
Recommended. The chain of fixed future
decision points (efficacy look(s) and final analysis) of the true
group-sequential design under consideration – see |
update_priors_sims |
Number of posterior samples per interim dataset (default 1000). |
PP_sims |
Number of predictive simulations per interim dataset (default 2000). |
n_sims |
Number of interim datasets to simulate per candidate timing (default is 100). |
n_cores |
Number of cores to parallelise over via
|
seed |
Optional integer seed; if supplied, replicate |
Value
A list with:
- outcome_list
A list, one element per candidate information fraction, each containing
PP_values(a vector of estimated PP, one per simulated interim dataset) andcens_time(the corresponding calendar times).- settings
A list of all arguments, plus the package, R, rjags and JAGS versions, the git commit of the working directory, the hostname and a timestamp.
Examples
set.seed(123)
control_model <- list(dist = "Exponential", parameter_mode = "Distribution",
t1 = 12, t1_Beta_a = 20, t1_Beta_b = 32)
effect_model <- list(delay_SHELF = SHELF::fitdist(c(5.5, 6, 6.5),
probs = c(0.25, 0.5, 0.75), lower = 0, upper = 12),
delay_dist = "gamma",
HR_SHELF = SHELF::fitdist(c(0.5, 0.6, 0.7),
probs = c(0.25, 0.5, 0.75), lower = 0, upper = 1),
HR_dist = "gamma",
P_S = 1, P_DTE = 0)
recruitment_model <- list(method = "power", period = 12, power = 1)
# Sweep candidates from 0.2 to 0.7 only -- all genuinely precede the
# design's own efficacy look at IF = 0.75.
# Two candidate timings, both before the design's efficacy look at IF = 0.75.
IA_model <- list(events = 40, IF = c(0.4, 0.6))
analysis_model <- list(method = "LRT", alpha = 0.025,
alternative_hypothesis = "one.sided")
future_boundaries <- list(
list(events = 30, crit = 2.24), # efficacy look at IF = 0.75
list(events = 40, crit = 2.00) # final analysis
)
# Deliberately small settings so the example runs quickly. For a real
# analysis use the defaults (update_priors_sims = 1000, PP_sims = 2000)
# and a larger n_sims.
timing <- calibrate_PP_timing(n_c = 25, n_t = 25,
control_model = control_model,
effect_model = effect_model,
recruitment_model = recruitment_model,
IA_model = IA_model,
analysis_model = analysis_model,
future_boundaries = future_boundaries,
update_priors_sims = 100,
PP_sims = 100,
n_sims = 2)
Calibrate a fixed Z-statistic futility boundary
Description
Finds the Z-statistic futility boundary at futility_IF such that
the probability of stopping for futility under the "null"
scenario equals target_null_futility_rate (the corresponding
empirical quantile of the simulated null Z distribution), and reports
the resulting futility-stopping rate under every supplied scenario. The
result is used as GSD_model$futility_boundary_Z with
GSD_model$futility_type = "MatchedZ" in
calc_dte_assurance_adaptive.
Usage
calibrate_matched_futility_boundary(
n_c,
n_t,
recruitment_model,
futility_IF,
total_events,
analysis_model,
target_null_futility_rate,
scenarios,
n_sims = 2000,
n_cores = 1,
seed = NULL
)
Arguments
n_c, n_t |
Number of patients in the control / treatment group. |
recruitment_model |
Recruitment specification (see
|
futility_IF |
Information fraction of the futility look. |
total_events |
Maximum planned number of events. |
analysis_model |
Analysis specification (see |
target_null_futility_rate |
Target probability of stopping for futility under the null scenario. |
scenarios |
Named list of data-generating scenarios (see
|
n_sims |
Number of simulated trials per scenario (default 2000). |
n_cores |
Number of cores (uses |
seed |
Optional integer seed. |
Value
A list with boundary, scenario_futility_rates,
raw_Z_by_scenario and settings (all arguments, plus the
package, R, rjags and JAGS versions, the git commit of the working
directory, the hostname and a timestamp).
Examples
scenarios <- list(
null = list(lambda_c = log(2) / 12, delay_time = 0, post_delay_HR = 1),
alt = list(lambda_c = log(2) / 12, delay_time = 3, post_delay_HR = 0.6)
)
cal <- calibrate_matched_futility_boundary(
n_c = 100, n_t = 100,
recruitment_model = list(method = "power", period = 12, power = 1),
futility_IF = 0.5, total_events = 120,
analysis_model = list(method = "LRT", alpha = 0.025,
alternative_hypothesis = "one.sided"),
target_null_futility_rate = 0.5,
scenarios = scenarios, n_sims = 20, seed = 1)
cal$boundary
cal$scenario_futility_rates
Censor a survival dataset
Description
Applies administrative censoring to a survival dataset using one of three methods: fixed time, fixed number of events, or fixed information fraction. The input data must contain columns for pseudo survival time, recruitment time, and observed time.
Usage
cens_data(
data,
cens_method = "Time",
cens_time = NULL,
cens_IF = NULL,
cens_events = NULL
)
Arguments
data |
A dataframe containing uncensored survival data with columns: |
cens_method |
Censoring method: |
cens_time |
Time point for censoring (required if |
cens_IF |
Information fraction for censoring (required if |
cens_events |
Number of events for censoring (required if |
Details
This is the single routine used throughout the package to cut a trial at
an analysis. The cut is made at calendar time t, the calendar time
of the k-th event ("Events"); patients recruited before
t are included, and a patient has an event if
pseudo_time <= t. Cutting at k events therefore leaves
exactly k events in the data (assuming no tied event times).
cens_events is floored with a small tolerance, so a non-integer
such as 840 * 0.3 is treated as 252.
Value
A list containing:
- data
Censored dataframe with updated
statusand filtered rows- cens_events
Number of events used for censoring (if applicable)
- cens_time
Time point used for censoring
- sample_size
Number of patients remaining after censoring
Examples
set.seed(123)
df <- data.frame(
pseudo_time = rexp(20, rate = 0.1),
rec_time = runif(20, 0, 12),
time = rexp(20, rate = 0.1)
)
censored <- cens_data(df, cens_method = "Time", cens_time = 10)
str(censored)
Relative power floors for kappa selection
Description
For each alternative scenario, the D2 power (the power with no futility
stopping, i.e. at kappa = 0) minus margin. Pass the result
as power_floor to select_kappa_star.
Usage
compute_relative_floors(raw_by_scenario, alt_scenarios, margin = 0.05)
Arguments
raw_by_scenario |
A named list of raw replicate data frames (each
with a |
alt_scenarios |
Character vector of alternative scenario names. |
margin |
Allowed loss of power relative to D2 (default 0.05). |
Value
A named numeric vector with one floor per alternative scenario.
See Also
Build the group-sequential design for a GSD_model
Description
Builds the rpact group-sequential design used by
calc_dte_assurance_adaptive, apply_GSD_to_trial
and single_paired_rep. GSD_model$alpha_spending is
the user-specified cumulative alpha spent at each efficacy look
GSD_model$alpha_IF (rpact's typeOfDesign = "asUser").
For "PP" and "MatchedZ" futility, the futility look
(futility_IF) is added to the information-rate grid with zero
alpha spent, so its critical value is Inf and the efficacy critical
values are exactly those of the efficacy-only design. For "Beta"
futility, GSD_model$beta_spending is the cumulative beta spent at
each futility_IF (typeBetaSpending = "bsUser").
Information fractions are rounded to 6 dp before they are compared.
Usage
make_gsd_design(GSD_model)
make_rpact_design_from_GSD_model(GSD_model)
Arguments
GSD_model |
A named list with |
Details
make_rpact_design_from_GSD_model() is the previous name, kept as an
alias for one release.
Value
A list with design (the rpact design object;
design$informationRates and design$criticalValues give
the looks and their Z critical values), IF_all,
alpha_spending_full and beta_spending_full.
Examples
# Efficacy look at 75% information and final analysis, with a PP futility
# look at 50% information (zero alpha spent there)
gsd <- make_gsd_design(list(alpha_IF = c(0.75, 1),
alpha_spending = c(0.0125, 0.025),
futility_type = "PP", futility_IF = 0.5))
gsd$design$informationRates
gsd$design$criticalValues
Simulate PP values and true trial outcomes for PP-threshold calibration
Description
For a single fixed data-generating scenario, simulates n_sims
trials, computes the predictive probability (PP) at the
futility look, and records what actually happens to each trial if it is
allowed to continue through the remaining fixed decision points in
future_boundaries. Because the PP value does not depend on the
futility threshold \kappa, the output can be summarised over a
whole grid of thresholds afterwards via summarize_grid_by_kappa
without re-simulating.
Usage
run_calibration_grid(
n_c,
n_t,
control_model,
effect_model,
recruitment_model,
data_generating_model,
futility_IF,
total_events,
future_boundaries,
analysis_model,
update_priors_sims = 1000,
PP_sims = 2000,
n_sims = 1000,
n_cores = 1,
seed = NULL
)
Arguments
n_c, n_t |
Planned number of patients in the control / treatment group. |
control_model, effect_model |
Prior specification used for the
interim posterior update (see |
recruitment_model |
Recruitment specification (see
|
data_generating_model |
A named list giving the true scenario used to
simulate data: |
futility_IF |
Information fraction of the PP futility look. |
total_events |
Maximum planned number of events. |
future_boundaries |
List of future fixed decision points, each a list
with |
analysis_model |
Analysis specification (see |
update_priors_sims |
Number of posterior samples per interim dataset. |
PP_sims |
Number of posterior-predictive simulations per interim dataset. |
n_sims |
Number of simulated trials. |
n_cores |
Number of cores (uses |
seed |
Optional integer seed; replicate |
Value
A list with elements
rawA data frame with one row per simulated trial and columns
PP_val,t_interim,sample_size_interim,continuation_success,continuation_stop_time,continuation_sample_size,converged,P_Z1,P_Z2,P_Z3.settingsAll arguments, plus the package, R, rjags and JAGS versions, the git commit of the working directory, the hostname and a timestamp.
See Also
summarize_grid_by_kappa, select_kappa_star
Run paired replicates for one scenario, with checkpointing
Description
Runs single_paired_rep for i = 1, ..., n_sims, in
chunks of chunk_size replicates (in parallel via
parallel::mclapply when n_cores > 1). After each chunk, all
rows so far are written to checkpoint_file; if that file exists at
the start, the run resumes from the replicates already completed.
Usage
run_paired_scenario(
n_sims,
seed,
...,
compute_PP = TRUE,
n_cores = 1,
checkpoint_file = NULL,
chunk_size = 100
)
Arguments
n_sims |
Number of replicates. |
seed |
Base seed (see |
... |
Further arguments passed to |
compute_PP |
Passed to |
n_cores |
Number of cores (default 1). |
checkpoint_file |
Optional path of an RDS checkpoint file. |
chunk_size |
Number of replicates per chunk (default 100). |
Value
A list with raw (one row per replicate, ordered by
rep_id) and settings (all arguments, the package, R,
rjags and JAGS versions, the git commit of the working directory, the
hostname, a timestamp and n_failed). The
number of failed replicates is reported with a message, and a warning
is given if more than 1\
See Also
single_paired_rep, summarize_grid_by_kappa
Select the PP futility threshold minimising null expected sample size
Description
Among candidate thresholds for which the one-sided 95\
confidence bound on power (power_LCB from
summarize_grid_by_kappa) is at least the floor under every
alternative scenario, selects the one with the smallest expected sample
size under the null scenario. A threshold with an NA lower bound in
any alternative scenario is infeasible. Ties in null expected sample size
(within 1e-8) are broken in favour of the larger kappa.
Usage
select_kappa_star(
summary_by_scenario,
power_floor,
null_scenario,
alt_scenarios
)
Arguments
summary_by_scenario |
A named list of data frames, one per scenario,
each as returned by |
power_floor |
Minimum acceptable lower confidence bound on power:
a scalar applied to every alternative scenario, or a named numeric
vector with one entry per alternative scenario (e.g. from
|
null_scenario |
Name of the null scenario in |
alt_scenarios |
Character vector of alternative scenario names. |
Value
A list with kappa_star (the selected threshold, or
NA with a warning if none is feasible) and
feasibility_table (kappa, null_ESS,
feasible and, per alternative scenario, power_<s>,
power_LCB_<s> and floor_<s>).
See Also
summarize_grid_by_kappa, compute_relative_floors
Simulates survival times for a delayed treatment effect (DTE) scenario, where the treatment group experiences a delayed onset of benefit. Control and treatment groups are generated under exponential or Weibull distributions.
Description
Simulates survival times for a delayed treatment effect (DTE) scenario, where the treatment group experiences a delayed onset of benefit. Control and treatment groups are generated under exponential or Weibull distributions.
Usage
sim_dte(
n_c,
n_t,
lambda_c,
delay_time,
post_delay_HR,
dist = "Exponential",
gamma_c = NULL
)
Arguments
n_c |
The number of patients in the control group |
n_t |
The number of patients in the treatment group |
lambda_c |
The baseline hazard rate for the control group |
delay_time |
The length of delay before treatment effect begins |
post_delay_HR |
The hazard ratio after the delay period |
dist |
The distribution for the control group; must be one of "Exponential" (default) or "Weibull" |
gamma_c |
The shape parameter for the Weibull distribution (only used if |
Value
A data frame with two columns:
time |
Simulated survival times |
group |
Group assignment: "Control" or "Treatment" |
Class: data.frame
Examples
set.seed(123)
sim_data <- sim_dte(n_c = 10, n_t = 10, lambda_c = 0.1,
delay_time = 6, post_delay_HR = 0.6)
head(sim_data)
Simulate one interim dataset and compute Z at the futility look
Description
Single replicate used by calibrate_matched_futility_boundary:
simulates one trial under a fixed data-generating scenario, censors it at
floor(futility_IF * total_events) events, and returns the test
statistic from survival_test (positive Z favours treatment).
Usage
single_matched_futility_rep(
i,
n_c,
n_t,
data_generating_model,
recruitment_model,
futility_IF,
total_events,
analysis_model,
seed = NULL
)
Arguments
i |
Replicate index (used with |
n_c, n_t |
Number of patients in the control / treatment group. |
data_generating_model |
True scenario: |
recruitment_model |
Recruitment specification (see
|
futility_IF |
Information fraction of the futility look. |
total_events |
Maximum planned number of events. |
analysis_model |
Analysis specification (see |
seed |
Optional integer seed; replicate |
Value
A one-row data frame with column Z.
Simulate one paired replicate for post hoc design evaluation
Description
Simulates a single trial and records everything needed to evaluate a family of designs afterwards, without baking any design into the run: interim statistics and the predictive probability (PP) at the futility look, and the test statistics at the efficacy look and the final analysis of the real trial (which is never stopped here).
Usage
single_paired_rep(
i,
seed,
n_c,
n_t,
total_events,
futility_IF,
efficacy_IF = 0.75,
design,
control_model,
effect_model,
recruitment_model,
truth = NULL,
force_state = NULL,
analysis_model_LRT,
mw_t_stars = c(2, 6),
update_priors_sims,
PP_sims,
compute_PP = TRUE
)
Arguments
i |
Replicate index. |
seed |
Base seed. Replicate |
n_c, n_t |
Planned number of patients in the control / treatment arm. |
total_events |
Maximum planned number of events. |
futility_IF |
Information fraction of the futility (PP) look. |
efficacy_IF |
Information fraction of the interim efficacy look (default 0.75). |
design |
An |
control_model, effect_model |
The analysis prior, used for the
interim posterior update (see |
recruitment_model |
Recruitment specification. Must be
|
truth |
Either a list with the true |
force_state |
|
analysis_model_LRT |
Analysis specification for the log-rank test
( |
mw_t_stars |
Values of |
update_priors_sims |
Number of posterior samples per chain
(required when |
PP_sims |
Number of posterior-predictive draws (required when
|
compute_PP |
If |
Details
All designs are then summaries of the returned columns. With critical
values c_{eff}, c_{fin} from design and a final-only
critical value c_1:
D1 (fixed design): success if
Z_fin_LRT > c_1.D2 (efficacy look only): success if
Z_eff_LRT > c_eff, otherwiseZ_fin_LRT > c_fin. This iscontinuation_success.D3 (D2 plus PP futility): stop for futility if
PP_val < kappa; seesummarize_grid_by_kappa.D4, D5 (D2 plus Z futility): stop for futility if
Z_int_LRT(orZ_int_MW_t*) is below a cutoff.
Value
A one-row data frame with columns: rep_id,
seed_used, state, true_lambda_c, true_gamma_c
(1 for an exponential control arm), true_delay, true_HR;
interim t_int, n_int, frac_recruited_int (enrolled
/ planned), fu_gt3_int, fu_gt6_int (fraction of enrolled
treated patients with follow-up t_int - rec_time above 3 and 6),
Z_int_LRT, Z_int_MW_t<t>; PP_val, converged,
rhat_max, n_nonfinite_rhat, P_Z1, P_Z2,
P_Z3; t_eff, n_eff, Z_eff_LRT,
Z_eff_MW_t<t>, t_fin, n_fin, Z_fin_LRT,
Z_fin_MW_t<t>; the D2 outcome continuation_success,
continuation_stop_time, continuation_sample_size; aliases
t_interim and sample_size_interim (for
summarize_grid_by_kappa); and error (NA, or
the error message if the replicate failed, in which case all other
outcome columns are NA).
See Also
Summarise calibration output over a grid of PP futility thresholds
Description
Applies each candidate PP futility threshold \kappa to raw
replicate output (from run_paired_scenario or
run_calibration_grid): a trial stops for futility if its
interim PP is below \kappa, otherwise it takes its continuation
(D2) outcome. At kappa = 0 no trial stops, so the result is the D2
operating characteristics.
Usage
summarize_grid_by_kappa(
raw,
kappa_grid,
lcb_level = 0.95,
exclude_nonconverged = FALSE
)
Arguments
raw |
A data frame with columns |
kappa_grid |
Numeric vector of candidate PP thresholds. |
lcb_level |
Confidence level of the one-sided exact (Clopper-Pearson) lower bound on power (default 0.95). |
exclude_nonconverged |
If |
Value
A data frame with one row per \kappa and columns
kappa, n (replicates used), n_NA_dropped
(replicates dropped because PP_val was NA, with a
warning), P_early_fut, power_or_typeI, power_SE,
power_LCB (one-sided exact lower bound at level
lcb_level, 95\
size), ESS_SE and duration (expected trial duration).
See Also
select_kappa_star, compute_relative_floors
Calculate statistical significance on a survival dataset
Description
Performs a survival analysis using the standard log-rank test (LRT), a weighted log-rank test in the Fleming-Harrington family (WLRT), or the modestly-weighted log-rank test of Magirr and Burman (MW), and determines whether the result is statistically significant at the specified alpha level and alternative hypothesis.
Usage
survival_test(
data,
analysis_method = "LRT",
alternative = "one.sided",
alpha,
rho = 0,
gamma = 0,
t_star = NULL,
s_star = NULL,
return_HR = TRUE
)
Arguments
data |
A dataframe containing survival data. Must include columns for survival time, event status, and treatment group. |
analysis_method |
Method of analysis: |
alternative |
String specifying the alternative hypothesis: |
alpha |
Type I error level for the significance test (required, no
default). Pass |
rho |
Rho parameter for the Fleming-Harrington weighted log-rank test. |
gamma |
Gamma parameter for the Fleming-Harrington weighted log-rank test. |
t_star |
Parameter |
s_star |
Parameter |
return_HR |
If |
Value
A list containing:
- Signif
Logical: whether the test is significant at level
alpha.FALSEifZisNA;NAifalphaisNULL.- observed_HR
Estimated hazard ratio from a Cox proportional hazards model, or
NAifreturn_HR = FALSE.- Z
Signed test statistic. For all three methods, positive values favour the arm coded as "Treatment" (the second factor level of
group), i.e. positive Z corresponds to a hazard ratio below 1.
Examples
set.seed(123)
df <- data.frame(
survival_time = rexp(40, rate = 0.1),
status = rbinom(40, 1, 0.8),
group = rep(c("Control", "Treatment"), each = 20)
)
result <- survival_test(df, analysis_method = "LRT", alpha = 0.05)
str(result)
Update prior distributions using interim survival data
Description
This function updates elicited priors (defined through SHELF objects and parametric prior distributions) using interim survival data under a delayed-effect, piecewise-exponential model for the treatment arm and an exponential or Weibull model for the control arm.
Usage
update_priors(
data,
control_model,
effect_model,
n.chains = 2,
n_burnin = 500,
n_samples = 1000,
rhat_threshold = 1.1,
jags_seed = NULL
)
Arguments
data |
A data frame containing interim survival data with columns:
|
control_model |
A named list specifying the control arm survival distribution:
|
effect_model |
A named list specifying beliefs about the treatment effect:
|
n.chains |
Number of MCMC chains to run (default is 2) |
n_burnin |
Number of burn-in samples for the MCMC chain(s) (default is 500) |
n_samples |
Number of posterior samples retained per chain
after burn-in (default is 1000). The returned data frame has
|
rhat_threshold |
Convergence threshold on the Gelman-Rubin
potential scale reduction factor (default 1.1). Used only to compute
the |
jags_seed |
Optional integer seed for JAGS. If supplied, chain
|
Value
A data frame containing Monte Carlo samples from the updated
(posterior) distribution of the model parameters, with columns
lambda_c, delay_time, HR, gamma_c (Weibull
only), and Z (the latent scenario indicator: 1 = no separation,
2 = immediate separation, 3 = delayed separation). The following
attributes are attached for diagnostic purposes:
rhatA named numeric vector of per-parameter Gelman-Rubin point estimates (accessed via
attr(posterior_df, "rhat")).convergedTRUEif every finite R-hat is belowrhat_threshold,FALSEif not, orNAif there are no finite R-hat values (or the diagnostic could not be computed). Non-finite values (NaNarises for parameters that are constant across draws, e.g.delay_timewhenZ != 3throughout) are not treated as failures; they are counted inn_nonfinite_rhat.rhat_maxThe largest finite R-hat (
NAif none).n_nonfinite_rhatThe number of non-finite R-hat values.
n_retained_totalThe number of retained draws over all chains,
n.chains * n_samples.Z_probsA named numeric vector
c(P_Z1=, P_Z2=, P_Z3=), the posterior probability of each latent state, i.e.table(posterior_df$Z) / nrow(posterior_df)(accessed viaattr(posterior_df, "Z_probs")).
Priors for lambda_c, T, and HR are constructed from
elicited distributions using the SHELF framework, then updated through
sampling-based posterior inference.
Deprecated
The exponential control arm (control_model$dist = "Exponential")
is deprecated and will be removed in a future release; use
"Weibull".
Examples
set.seed(123)
interim_data = data.frame(survival_time = runif(10, min = 0, max = 10),
status = rbinom(10, size = 1, prob = 0.5),
group = c(rep("Control", 5), rep("Treatment", 5)))
control_model = list(dist = "Exponential",
parameter_mode = "Distribution",
t1 = 12,
t1_Beta_a = 20,
t1_Beta_b = 32)
effect_model = list(delay_SHELF = SHELF::fitdist(c(5.5, 6, 6.5),
probs = c(0.25, 0.5, 0.75), lower = 0, upper = 12),
delay_dist = "gamma",
HR_SHELF = SHELF::fitdist(c(0.5, 0.6, 0.7),
probs = c(0.25, 0.5, 0.75), lower = 0, upper = 1),
HR_dist = "gamma",
P_S = 1,
P_DTE = 0)
posterior_df <- update_priors(
data = interim_data,
control_model = control_model,
effect_model = effect_model,
n_samples = 10)
# Diagnostics, e.g.:
attr(posterior_df, "rhat")
attr(posterior_df, "converged")
attr(posterior_df, "Z_probs")
Package imports
Description
Package imports