1 Overview

This example demonstrates a simplified Seamless Phase II/III Adaptive Dose-Selection Design.

The trial consists of two stages:

The confirmatory hypothesis is:

\[ H_0: p_{\text{selected}} \leq p_{\text{control}} \]

versus

\[ H_1: p_{\text{selected}} > p_{\text{control}} \]

A one-sided significance level of

\[ \alpha = 0.025 \]

is used.

2 1. Design Parameters

set.seed(123)

alpha <- 0.025

doses <- c(
  "50mg",
  "100mg",
  "200mg"
)

n_doses <- length(doses)

# Stage 1 sample size per arm
n_stage1_per_arm <- 100

# Stage 2 sample size per arm
n_stage2_per_arm <- 150

3 2. True Response Rates

These probabilities are used only to generate simulated trial data.

response_prob <- c(
  "Control" = 0.40,
  "50mg"    = 0.48,
  "100mg"   = 0.60,
  "200mg"   = 0.65
)

4 3. True Toxicity Rates

tox_prob <- c(
  "Control" = 0.05,
  "50mg"    = 0.07,
  "100mg"   = 0.10,
  "200mg"   = 0.30
)

5 4. Stage 1: Dose Finding and Dose Selection

Stage 1 includes four treatment groups:

stage1_arms <- c(
  "Control",
  doses
)

stage1_data <- data.frame()

for (arm in stage1_arms) {
  
  response <- rbinom(
    n_stage1_per_arm,
    1,
    response_prob[arm]
  )
  
  toxicity <- rbinom(
    n_stage1_per_arm,
    1,
    tox_prob[arm]
  )
  
  tmp <- data.frame(
    stage = 1,
    treatment = arm,
    response = response,
    toxicity = toxicity
  )
  
  stage1_data <- rbind(
    stage1_data,
    tmp
  )
}

6 5. Stage 1 Summary

Calculate the observed response rate and toxicity rate for each treatment group.

stage1_summary <- aggregate(
  cbind(response, toxicity) ~ treatment,
  data = stage1_data,
  mean
)

print(stage1_summary)
##   treatment response toxicity
## 1     100mg     0.61     0.10
## 2     200mg     0.64     0.27
## 3      50mg     0.45     0.09
## 4   Control     0.40     0.05

7 6. Control Response Rate

control_stage1 <- subset(
  stage1_data,
  treatment == "Control"
)

rate_control_stage1 <- mean(
  control_stage1$response
)

rate_control_stage1
## [1] 0.4

8 7. Stage 1 Dose-Level Efficacy Tests

For each dose, test:

\[ H_0: p_{\text{dose}} \leq p_{\text{control}} \]

versus

\[ H_1: p_{\text{dose}} > p_{\text{control}} \]

A one-sided two-sample proportion test is used.

dose_results <- data.frame()

for (d in doses) {
  
  dat_dose <- subset(
    stage1_data,
    treatment == d
  )
  
  rate_response <- mean(
    dat_dose$response
  )
  
  rate_toxicity <- mean(
    dat_dose$toxicity
  )
  
  test <- prop.test(
    
    x = c(
      sum(dat_dose$response),
      sum(control_stage1$response)
    ),
    
    n = c(
      nrow(dat_dose),
      nrow(control_stage1)
    ),
    
    alternative = "greater",
    correct = FALSE
  )
  
  dose_results <- rbind(
    
    dose_results,
    
    data.frame(
      dose = d,
      response_rate = rate_response,
      toxicity_rate = rate_toxicity,
      p_value_raw = test$p.value
    )
  )
}

print(dose_results)
##    dose response_rate toxicity_rate  p_value_raw
## 1  50mg          0.45          0.09 0.2372431856
## 2 100mg          0.61          0.10 0.0014890134
## 3 200mg          0.64          0.27 0.0003408551

9 8. Prespecified Dose-Selection Rule

A dose is considered acceptable if:

\[ \text{Response Rate} > \text{Control Response Rate} \]

and

\[ \text{Toxicity Rate} < 0.20 \]

acceptable <- subset(
  dose_results,
  response_rate > rate_control_stage1 &
    toxicity_rate < 0.20
)

print(acceptable)
##    dose response_rate toxicity_rate p_value_raw
## 1  50mg          0.45          0.09 0.237243186
## 2 100mg          0.61          0.10 0.001489013

If no dose meets both criteria, the trial stops for futility or safety.

if (nrow(acceptable) == 0) {
  
  stop(
    "No acceptable dose. Trial stops for futility/safety."
  )
}

10 9. Select the Best Dose

Among acceptable doses:

  1. Select the dose with the highest observed response rate.
  2. If there is a tie, select the dose with the lower toxicity rate.
acceptable <- acceptable[
  order(
    -acceptable$response_rate,
    acceptable$toxicity_rate
  ),
]

selected_dose <- acceptable$dose[1]

cat(
  "\n====================================\n"
)
## 
## ====================================
cat(
  "Selected dose:",
  selected_dose,
  "\n"
)
## Selected dose: 100mg
cat(
  "====================================\n"
)
## ====================================

11 10. Stage 1 P-Value for the Selected Dose

p1_raw <- dose_results$p_value_raw[
  dose_results$dose == selected_dose
]

p1_raw
## [1] 0.001489013

12 11. Stage 1 Multiplicity Adjustment

Because three doses were examined before selecting one, a simple Bonferroni adjustment is applied:

$$ p_{1,} =

(1, 3p_1) $$

More generally:

$$ p_{1,} =

(1, Kp_1) $$

where (K) is the number of candidate doses.

p1_adjusted <- min(
  1,
  n_doses * p1_raw
)

cat(
  "\nStage 1 raw p-value =",
  round(p1_raw, 5),
  "\n"
)
## 
## Stage 1 raw p-value = 0.00149
cat(
  "Stage 1 multiplicity-adjusted p-value =",
  round(p1_adjusted, 5),
  "\n"
)
## Stage 1 multiplicity-adjusted p-value = 0.00447

13 12. Stage 2: Confirmatory Stage

Only the selected dose and Control continue into Stage 2.

Stage 2 uses newly enrolled patients.

response_selected_stage2 <- rbinom(
  n_stage2_per_arm,
  1,
  response_prob[selected_dose]
)

response_control_stage2 <- rbinom(
  n_stage2_per_arm,
  1,
  response_prob["Control"]
)

Create the Stage 2 dataset.

stage2_data <- data.frame(
  
  stage = 2,
  
  treatment = c(
    rep(
      selected_dose,
      n_stage2_per_arm
    ),
    
    rep(
      "Control",
      n_stage2_per_arm
    )
  ),
  
  response = c(
    response_selected_stage2,
    response_control_stage2
  )
)

14 13. Stage 2 Response Rates

stage2_summary <- aggregate(
  response ~ treatment,
  data = stage2_data,
  mean
)

print(stage2_summary)
##   treatment  response
## 1     100mg 0.5933333
## 2   Control 0.3400000

15 14. Stage 2 Confirmatory Test

The Stage 2 hypothesis is:

\[ H_0: p_{\text{selected}} \leq p_{\text{control}} \]

versus

\[ H_1: p_{\text{selected}} > p_{\text{control}} \]

test_stage2 <- prop.test(
  
  x = c(
    sum(response_selected_stage2),
    sum(response_control_stage2)
  ),
  
  n = c(
    n_stage2_per_arm,
    n_stage2_per_arm
  ),
  
  alternative = "greater",
  correct = FALSE
)

p2 <- test_stage2$p.value

cat(
  "\nStage 2 p-value =",
  round(p2, 5),
  "\n"
)
## 
## Stage 2 p-value = 1e-05

16 15. Final Seamless Analysis

Rather than simply pooling Stage 1 and Stage 2 data, evidence from both stages is combined using an inverse-normal combination test.

First, convert the stage-specific p-values into Z statistics:

\[ Z_1 = \Phi^{-1} \left( 1-p_{1,\text{adjusted}} \right) \]

and

$$ Z_2 =

^{-1} ( 1-p_2 ) $$

where (^{-1}) is the standard normal quantile function.

z1 <- qnorm(
  1 - p1_adjusted
)

z2 <- qnorm(
  1 - p2
)

z1
## [1] 2.614566
z2
## [1] 4.397645

17 16. Information-Based Weights

Stage 1 contributes:

\[ 100 + 100 = 200 \]

patients from the selected-dose and Control groups.

Stage 2 contributes:

\[ 150 + 150 = 300 \]

patients.

Weights are defined as:

\[ w_1 = \sqrt{ \frac{I_1} {I_1 + I_2} } \]

and

\[ w_2 = \sqrt{ \frac{I_2} {I_1 + I_2} } \]

so that:

\[ w_1^2 + w_2^2 = 1 \]

In this simplified example, sample size is used as a proxy for statistical information.

info_stage1 <-
  2 * n_stage1_per_arm

info_stage2 <-
  2 * n_stage2_per_arm

w1 <- sqrt(
  info_stage1 /
    (info_stage1 + info_stage2)
)

w2 <- sqrt(
  info_stage2 /
    (info_stage1 + info_stage2)
)

cat(
  "\nStage 1 weight =",
  round(w1, 3),
  "\n"
)
## 
## Stage 1 weight = 0.632
cat(
  "Stage 2 weight =",
  round(w2, 3),
  "\n"
)
## Stage 2 weight = 0.775

18 17. Inverse-Normal Combination Statistic

The combined test statistic is:

\[ Z_{\text{comb}} = w_1 Z_1 + w_2 Z_2 \]

z_comb <- (
  w1 * z1 +
    w2 * z2
)

z_comb
## [1] 5.059998

19 18. Combined P-Value

The final one-sided combined p-value is:

\[ p_{\text{comb}} = 1-\Phi \left( Z_{\text{comb}} \right) \]

p_comb <- 1 - pnorm(
  z_comb
)

p_comb
## [1] 2.096299e-07

20 19. Final Decision

The trial is considered successful if:

\[ p_{\text{comb}} < 0.025 \]

if (p_comb < alpha) {
  
  decision <- paste(
    "SUCCESS:",
    selected_dose,
    "demonstrated superiority to Control."
  )
  
} else {
  
  decision <- paste(
    "NOT SUCCESSFUL:",
    selected_dose,
    "did not demonstrate superiority to Control."
  )
}

cat(
  "\nFinal Decision:",
  decision,
  "\n"
)
## 
## Final Decision: SUCCESS: 100mg demonstrated superiority to Control.

21 20. Final Summary

cat(
  "\n====================================\n"
)
## 
## ====================================
cat(
  "Seamless Phase II/III Trial Summary\n"
)
## Seamless Phase II/III Trial Summary
cat(
  "====================================\n"
)
## ====================================
cat(
  "Selected dose:",
  selected_dose,
  "\n"
)
## Selected dose: 100mg
cat(
  "Stage 1 adjusted p-value:",
  round(p1_adjusted, 5),
  "\n"
)
## Stage 1 adjusted p-value: 0.00447
cat(
  "Stage 2 p-value:",
  round(p2, 5),
  "\n"
)
## Stage 2 p-value: 1e-05
cat(
  "Stage 1 weight:",
  round(w1, 3),
  "\n"
)
## Stage 1 weight: 0.632
cat(
  "Stage 2 weight:",
  round(w2, 3),
  "\n"
)
## Stage 2 weight: 0.775
cat(
  "Combined Z statistic:",
  round(z_comb, 3),
  "\n"
)
## Combined Z statistic: 5.06
cat(
  "Combined p-value:",
  round(p_comb, 5),
  "\n"
)
## Combined p-value: 0
cat(
  "Final decision:",
  decision,
  "\n"
)
## Final decision: SUCCESS: 100mg demonstrated superiority to Control.

22 Interpretation

This simplified seamless design illustrates the following workflow:

\[ \text{Stage 1 Dose Finding} \rightarrow \text{Dose Selection} \rightarrow \text{Stage 2 Confirmation} \rightarrow \text{Combination Test} \]

Stage 1 data contribute to the final confirmatory analysis rather than being discarded.

However, because the selected dose is chosen based on interim data, the final analysis cannot simply treat the selected dose as if it had been prespecified from the beginning.

Multiplicity and adaptive selection must therefore be addressed.

In this example:

For a real confirmatory seamless Phase II/III trial, the adaptation rules, multiplicity procedure, combination-test weights, stopping rules, and final testing strategy should be prespecified. Extensive simulation would generally be required to evaluate operating characteristics such as Type I error, power, dose-selection probability, estimation bias, and expected sample size.