| name | advanced-adaptive-trials |
| description | Adaptive trial designs in R, including platform, basket, MAMS, response-adaptive, and interim decision methods. |
Advanced Adaptive Trial Designs in R
Overview
Advanced adaptive clinical trial designs including platform trials, basket and umbrella trials, response-adaptive randomization, multi-arm multi-stage designs, Bayesian adaptive methods, and sample size re-estimation techniques.
Platform Trials
Using adaptr Package
library(adaptr)
setup <- setup_trial(
arms = c("Control", "Arm_A", "Arm_B", "Arm_C"),
control = "Control",
true_ys = c(0.30, 0.35, 0.45, 0.32),
data_looks = seq(100, 500, by = 100),
randomised_at_looks = NULL,
min_n = 25
)
setup <- setup |>
setup_trial_binom(
highest_is_best = TRUE,
soften_power = 0.5
)
setup <- setup_trial_binom(
arms = c("Control", "Arm_A", "Arm_B", "Arm_C"),
control = "Control",
true_ys = c(0.30, 0.35, 0.45, 0.32),
data_looks = seq(100, 500, 100),
superiority = 0.99,
inferiority = 0.01,
equivalence_prob = 0.90,
equivalence_diff = 0.05
)
set.seed(123)
sims <- run_trials(setup, n_rep = 1000, cores = 4)
summary(sims)
plot(sims)
Adding Arms Mid-Trial
library(adaptr)
setup_platform <- setup_trial_binom(
arms = c("Control", "Arm_A", "Arm_B"),
control = "Control",
true_ys = c(0.30, 0.40, 0.35),
data_looks = seq(100, 1000, 100),
superiority = 0.99,
inferiority = 0.01
)
setup_platform <- setup_platform |>
add_arm(
arm = "Arm_C",
true_y = 0.50,
start_look = 3
)
sims_platform <- run_trials(setup_platform, n_rep = 500)
summary(sims_platform)
Response-Adaptive Randomization
Thompson Sampling
thompson_sampling <- function(successes, failures, n_arms) {
samples <- sapply(1:n_arms, function(i) {
rbeta(10000, successes[i] + 1, failures[i] + 1)
})
prob_best <- colMeans(samples == apply(samples, 1, max))
alloc_prob <- prob_best
alloc_prob <- pmax(alloc_prob, 0.1 / n_arms)
alloc_prob <- alloc_prob / sum(alloc_prob)
return(alloc_prob)
}
successes <- c(20, 25, 30)
failures <- c(30, 25, 20)
alloc <- thompson_sampling(successes, failures, 3)
cat("Allocation probabilities:", round(alloc, 3), "\n")
RAR with Minimum Allocation
rar_allocation <- function(posterior_probs, min_alloc = 0.1, control_fixed = TRUE) {
n_arms <- length(posterior_probs)
alloc <- posterior_probs
if (control_fixed) {
control_alloc <- 1 / n_arms
remaining <- 1 - control_alloc
alloc[-1] <- alloc[-1] / sum(alloc[-1]) * remaining
alloc[1] <- control_alloc
}
alloc <- pmax(alloc, min_alloc)
alloc <- alloc / sum(alloc)
return(alloc)
}
Basket Trials
Using basket Package
library(basket)
basket_data <- data.frame(
basket = c("Breast", "Lung", "Colon", "Melanoma", "Ovarian"),
r = c(8, 12, 5, 15, 7),
n = c(20, 25, 18, 30, 22)
)
fit_mem <- mem_exact(
r = basket_data$r,
n = basket_data$n,
p0 = 0.15,
shape1 = 0.5,
shape2 = 0.5
)
summary(fit_mem)
plot(fit_mem)
fit_mem$post_prob
plot(fit_mem, type = "cluster")
Hierarchical Model for Baskets
library(basket)
fit_hier <- basket(
r = basket_data$r,
n = basket_data$n,
p0 = 0.15,
method = "hpd",
alpha = 0.05
)
Umbrella Trials
Design Considerations
umbrella_design <- data.frame(
stratum = c("EGFR+", "ALK+", "KRAS+", "Other"),
treatment = c("Erlotinib", "Crizotinib", "Trametinib", "Chemotherapy"),
target_n = c(100, 80, 120, 150),
alpha = 0.025 / 4
)
library(rpact)
designs <- lapply(1:4, function(i) {
getDesignGroupSequential(
kMax = 2,
alpha = umbrella_design$alpha[i],
beta = 0.20,
sided = 1,
typeOfDesign = "OF"
)
})
Multi-Arm Multi-Stage (MAMS)
Using MAMS Package
library(MAMS)
mams_design <- mams(
K = 3,
J = 2,
alpha = 0.025,
power = 0.90,
r = c(1, 1.5),
r0 = c(1, 1.5),
p = 0.5,
p0 = 0.5,
p1 = 0.65,
ushape = "triangular",
lshape = "triangular"
)
summary(mams_design)
plot(mams_design)
mams_design$n
mams_design$N
MAMS with Continuous Outcome
library(MAMS)
mams_cont <- mams(
K = 4,
J = 3,
alpha = 0.025,
power = 0.90,
r = c(1, 1, 1),
r0 = c(1, 1, 1),
p = 0,
p0 = 0,
p1 = 0.3,
ushape = "obf",
lshape = "fixed"
)
summary(mams_cont)
Bayesian Adaptive Designs with RBesT
Historical Data Integration
library(RBesT)
hist_data <- data.frame(
study = paste0("Hist", 1:4),
r = c(15, 20, 18, 22),
n = c(50, 55, 48, 60)
)
map_prior <- gMAP(
cbind(r, n - r) ~ 1 | study,
data = hist_data,
family = binomial,
tau.dist = "HalfNormal",
tau.prior = 1,
beta.prior = 2
)
summary(map_prior)
plot(map_prior)
prior_mix <- automixfit(map_prior)
plot(prior_mix)
Robust Prior (Protect Against Conflict)
library(RBesT)
robust_prior <- robustify(
prior_mix,
weight = 0.2,
mean = 0.5
)
plot(robust_prior)
plot_mix <- function(...) {
priors <- list(...)
x <- seq(0, 1, 0.01)
plot_data <- map_dfr(names(priors), function(nm) {
tibble(x = x, y = dmix(priors[[nm]], x), prior = nm)
})
ggplot(plot_data, aes(x, y, color = prior)) + geom_line() + theme_bw()
}
Operating Characteristics
library(RBesT)
decision <- decision2S(
pc = 0.975,
qc = 0.10,
lower.tail = FALSE
)
oc <- oc2S(
prior_treatment = robust_prior,
prior_control = robust_prior,
n1_treatment = 30,
n1_control = 30,
n2_treatment = 30,
n2_control = 30,
decision = decision
)
plot(oc)
summary(oc)
Group Sequential Designs with rpact
O'Brien-Fleming Design
library(rpact)
design_of <- getDesignGroupSequential(
kMax = 3,
alpha = 0.025,
beta = 0.20,
sided = 1,
typeOfDesign = "OF",
informationRates = c(0.33, 0.67, 1.0)
)
summary(design_of)
plot(design_of)
design_of$criticalValues
design_of$alphaSpent
Sample Size Calculation
library(rpact)
sample_size <- getSampleSizeSurvival(
design = design_of,
lambda1 = log(2) / 24,
lambda2 = log(2) / 36,
accrualTime = 24,
followUpTime = 12,
dropoutRate1 = 0.05,
dropoutRate2 = 0.05,
allocationRatioPlanned = 1
)
summary(sample_size)
sample_size$eventsPerStage
sample_size$numberOfSubjects
Interim Analysis
library(rpact)
interim <- getAnalysisResults(
design_of,
dataInput = getDataset(
n = c(100, 100),
events = c(40, 80),
logRanks = c(2.1, 2.8)
)
)
summary(interim)
interim$finalStage
interim$futilityStop
interim$rejectAtFinalStage
Sample Size Re-Estimation
Blinded SSR
library(rpact)
ssr <- getSampleSizeReestimation(
design_of,
stageResults = interim,
conditionalPower = 0.80
)
summary(ssr)
ssr$sampleSizeNew
Unblinded SSR
library(rpact)
cp <- getConditionalPower(
design = design_of,
stage = 2,
stageResults = interim,
nPlanned = c(50, 50),
assumedEffect = 0.67
)
summary(cp)
if (cp$conditionalPower < 0.50) {
new_n <- getSampleSizeReestimation(design_of, interim, conditionalPower = 0.80)
}
Graphical Multiplicity with gMCP
library(gMCPLite)
m <- matrix(
c(0, 0.5, 0.5, 0,
0.5, 0, 0, 0.5,
0.5, 0, 0, 0.5,
0, 0.5, 0.5, 0),
nrow = 4, byrow = TRUE
)
weights <- c(0.5, 0.5, 0, 0)
graph <- gMCP::matrix2graph(m, weights)
nodeNames(graph) <- c("H1_Primary", "H2_Primary", "H3_Secondary", "H4_Secondary")
plot(graph)
pvalues <- c(0.01, 0.03, 0.02, 0.04)
result <- gMCP::gMCP(graph, pvalues, alpha = 0.025)
print(result)
result@rejected
Key Packages Summary
| Package | Purpose |
|---|
| adaptr | Platform trial simulation |
| basket | Basket trial analysis |
| MAMS | Multi-arm multi-stage designs |
| rpact | Group sequential and adaptive designs |
| RBesT | Bayesian evidence synthesis |
| gMCPLite | Graphical multiplicity procedures |
| gsDesign | Group sequential designs |
| gsDesign2 | Enhanced group sequential |
| Mediana | Clinical trial simulations |
Best Practices
- Pre-specification: Define adaptation rules before trial starts
- Type I error: Ensure strong control under all adaptations
- Operating characteristics: Simulate extensively under various scenarios
- Blinding: Maintain blinding where possible during adaptations
- Documentation: Document all decision rules in protocol
- Regulatory: Engage regulators early for complex adaptive designs
- Implementation: Plan for operational complexity of adaptations
- Analysis: Plan for potential biases from adaptations