Visualize Simon's Two-Stage Phase II Design

Author

Tingting Zhan

Introduction

This vignette of package VisualizeSimon2Stage (CRAN, Github, RPubs) documents the visualization of probabilities and operating characteristics of Simon’s two-stage Phase II design.

Prerequisite

remotes::install_github('tingtingzhan/VisualizeSimon2Stage')

Getting Started

Examples in this vignette require that the search path has

library(VisualizeSimon2Stage)
library(clinfun)
library(flextable)
library(ggplot2)

Simon (1989) Two-Stage Phase II Design

Notations

Simon (1989) two-stage design tests the one-sided hypothesis H_0: p\leq p_u vs. H_a: p>p_u for a binary response in the following steps.

  1. Enroll n_1 subjects.
  • Early termination, or frail, if \leq r_1 positive responses are observed.
  • Move to next stage if >r_1 responses are observed.
  1. Enroll an additional (n-n_1) subjects.
  • Fail, if \leq r total responses are observed.
  • Success, or H_0 rejected, if >r total responses are observed.

In this vignette, p_u denotes the unacceptable response rate, and p_a denotes the acceptable response rate. The parameter nomenclature of r_1, n_1, r and n follows that of PASS and of function clinfun::ph2simon().

Types of Simon’s two-stage design include

  • 'minimax' (default), minimum total sample size n
  • 'optimal', minimum expected total sample size \textrm{E}(n|p=p_u)
  • 'n1', minimum Stage-1 sample size n_1
  • 'maximax', to use up the user-provided maximum total sample size, i.e., parameter nmax of function clinfun::ph2simon()
  • 'all', all types listed above

S3 class 'ph2simon'

Function clinfun::ph2simon() returns an object of S3 class 'ph2simon'. The output is printed in the R console using S3 method dispatch clinfun:::print.ph2simon().

Example below provides the various Simon’s two-stage designs for hypotheses p_u=.2, p_a=.4, with Type-I error rate \alpha=5\% and Type-II error rate \beta=10\%.

(x = ph2simon(pu = .2, pa = .4, ep1 = .05, ep2 = .1)) 

 Simon 2-stage Phase II design 

Unacceptable response rate:  0.2 
Desirable response rate:  0.4 
Error rates: alpha =  0.05 ; beta =  0.1 

           r1 n1  r  n EN(p0) PET(p0)   qLo   qHi
Minimax     5 24 13 45  31.23  0.6559 0.108 1.000
Admissible  4 20 14 49  30.74  0.6296 0.058 0.108
Optimal     4 19 15 54  30.43  0.6733 0.000 0.058

S4 class 'ph2simon4'

Function ph2simon4() converts an S3 object 'ph2simon' to an S4 object 'ph2simon4'. The output is printed in the R console using S4 method dispatch getMethod(f = 'show', signature = 'ph2simon4').

x |> ph2simon4(type = 'all')

 Simon's 2-Stage Phase II Design

Unacceptable Response Rate: 20.0%
Desirable Response Rate: 40.0%
Controlled Error Rates: α ≤ 5%, β ≤ 10%
Maximum Sample Size Allowed: 100

        r1 n1  r   n EN(pu) EN(pa) PET(pu) PET(pa)    α     β
minimax  5 24 13  45   31.2   44.2   65.6%    4.0% 4.8% 10.0%
optimal  4 19 15  54   30.4   51.6   67.3%    7.0% 4.8%  9.6%
n1       3 15 19  71   34.7   65.9   64.8%    9.1% 4.5%  9.8%
maximax  7 27 28 100   38.4   93.0   84.4%    9.5% 1.2%  9.9%

Probabilities

Math

Given a Simon’s two-stage design (r_1,n_1,r,n) and a true response rate p, we have

  • the number of Stage-1 positive responses X_1 \sim \textrm{binom}(n_1, p).
  • the number of Stage-2 positive responses X_2 \sim \textrm{binom}(n-n_1, p).
  • X_1 and X_2 are independent.

The probability of early termination is

p_{\textrm{frail}} = \textrm{Pr}(X_1 \leq r_1)

The probability of failure to reject H_0 is

p_{\textrm{fail}} = \sum_{s_1 = r_1+1}^{n_1} \textrm{Pr}(X_1=s_1)\cdot\textrm{Pr}\left(X_2 \leq (r-s_1)\right)

The probability of successfully rejecting H_0 is

p_{\textrm{success}} = \sum_{s_1 = r_1+1}^{n_1} \textrm{Pr}(X_1=s_1)\cdot\textrm{Pr}(X_2 > (r-s_1))

The expected sample size is

\textrm{E}(n) = p_{\textrm{frail}} \cdot n_1 + (1 - p_{\textrm{frail}}) \cdot n

Numbers

The S3 generic simon_pr() calculates the probabilities of early termination, fail and success at one-or-more response rates p, either from an S3 object 'ph2simon',

x |> simon_pr(prob = c(.2, .3, .4)) |> as_flextable()

Probabilities

Response Rate

E(N)

Early Termination

Fail

Success

p = 20%

31.2

65.6%

29.6%

4.8%

p = 30%

40.2

22.9%

30.3%

46.8%

p = 40%

44.2

4.0%

6.0%

90.0%

or from an S4 object 'ph2simon4',

x |> ph2simon4() |> simon_pr(prob = c(.2, .3, .4)) |> as_flextable()

Probabilities

Response Rate

E(N)

Early Termination

Fail

Success

p = 20%

31.2

65.6%

29.6%

4.8%

p = 30%

40.2

22.9%

30.3%

46.8%

p = 40%

44.2

4.0%

6.0%

90.0%

or from the design parameters (r_1, n_1, r, n). In such case the user must call the S3 method dispatch simon_pr.ph2simon4() explicitly.

simon_pr.ph2simon4(prob = c(.2, .3, .4), r1 = 5L, n1 = 24L, r = 13L, n = 45L) |>
  as_flextable()

Probabilities

Response Rate

E(N)

Early Termination

Fail

Success

p = 20%

31.2

65.6%

29.6%

4.8%

p = 30%

40.2

22.9%

30.3%

46.8%

p = 40%

44.2

4.0%

6.0%

90.0%

Visualization

S3 methods dispatches for the generic ggplot2::autoplot() visualize the probabilities of early termination, fail and success at p=p_u and p=p_a. The donut slices for success are colored with the highest opacity, indicating that they represent the Type-I error rate \alpha if p=p_u, and the power 1-\beta if p=p_a. The probabilities are visualized either from an S3 object 'ph2simon',

x |> autoplot(type = 'optimal')

or from an S4 object 'ph2simon4'.

x |> ph2simon4(type = 'optimal') |> autoplot()

or from the design parameters (r_1, n_1, r, n) and type. In such case the user must call the S3 method dispatch autoplot.ph2simon4() explicitly.

autoplot.ph2simon4(pu = .2, pa = .4, r1 = 4L, n1 = 19L, r = 15L, n = 54L, type = 'optimal')

Simulation

The S3 generic r_simon() simulates the number of positive responses in Simon’s two-stage design. Following examples show simulations of 1e4L trials at p=.3, either from an S3 object 'ph2simon',

set.seed(15); s = x |> r_simon(R = 1e4L, prob = .3, type = 'optimal')

or from an S4 object 'ph2simon4',

set.seed(15); s1 = x |> ph2simon4(type = 'optimal') |> r_simon(R = 1e4L, prob = .3)
stopifnot(identical(s, s1))

or from the design parameters (r_1, n_1, r, n). In such case the user must call the S3 method dispatch r_simon.ph2simon4() explicitly.

set.seed(15); s2 = r_simon.ph2simon4(R = 1e4L, prob = .3, r1 = 4L, n1 = 19L, r = 15L, n = 54L)
stopifnot(identical(s, s2))

The Type-I error rate is controlled at \alpha\leq 5\% when p=p_u=.2 at a sufficiently large simulated sample size. The Type-II error rate is controlled at \beta\leq 10\%, or power (1-\beta)\geq 90\%, when p=p_a=.4.

R code: Type-I-error rate at p_u, 1e4L simulated copies
set.seed(31); x |> 
  r_simon(R = 1e4L, prob = .2) |> 
  attr(which = 'dx', exact = TRUE) |> 
  table(Decision = _) |>
  as_flextable() |> 
  highlight(i = 3L, j = 3L) |>
  add_header_lines(values = 'pu = .2')

pu = .2

Decision

Count

Percent

[0,5]; Early Termination

6,577

65.8%

(5,13]; Fail

2,961

29.6%

(13,45]; Success

462

4.6%

Total

10,000

100.0%

R code: power at p_a, 1e4L simulated copies
set.seed(24); x |> 
  r_simon(R = 1e4L, prob = .4) |>
  attr(which = 'dx', exact = TRUE) |>
  table(Decision = _) |>
  as_flextable() |> 
  highlight(i = 3L, j = 3L) |>
  add_header_lines(values = 'pa = .4')

pa = .4

Decision

Count

Percent

[0,5]; Early Termination

379

3.8%

(5,13]; Fail

583

5.8%

(13,45]; Success

9,038

90.4%

Total

10,000

100.0%

Power Curve

x |> 
  powerCurve.ph2simon()

x |> 
  ph2simon4() |>
  powerCurve.ph2simon4()

Operating Characteristics

Suppose we have three drugs A, B and C, with true response rate p^A=.3, p^B=.2 and p^C=.15, respectively.

p = c(A = .3, B = .2, C = .15)

We simulated 1e4L Simon’s two-stage trials of each drug to obtain the operating characteristics, i.e., the percentage of trials in which each drug

  • having the highest number of responses
  • both having the highest number of responses and successfully rejecting the null hypothesis.

The operating characteristics are visualized either from an S3 object 'ph2simon',

set.seed(52); x |> simon_oc(prob = p, R = 1e4L, type = 'optimal')

or from an S4 object 'ph2simon4',

set.seed(52); x |> ph2simon4(type = 'optimal') |> simon_oc(prob = p, R = 1e4L)

or from the design parameters (r_1, n_1, r, n). In such case the user must call the S3 method dispatch simon_oc.ph2simon4() explicitly.

set.seed(52); simon_oc.ph2simon4(prob = p, R = 1e4L, r1 = 4L, n1 = 19L, r = 15L, n = 54L)

Appendix

Terms & Abbreviations

Term / Abbreviation Description
|> Forward pipe operator introduced since R 4.1.0
$ Extract parts of an object
binom Binomial density and distribution
CRAN, R The Comprehensive R Archive Network
class Object class
flextable Flexible tables, from package flextable (Gohel and Skintzos 2025)
PASS Power Analysis & Sample Size, https://www.ncss.com/software/pass/
PET Probability of early termination
ph2simon Simon (1989) two-stage Phase II design, from package clinfun (Seshan and Whiting 2023)
S3, generic, methods S3 object oriented system, UseMethod; getS3method; https://adv-r.hadley.nz/s3.html
S4, generic, methods S4 object oriented system, isS4; setClass; getMethod; https://adv-r.hadley.nz/s4.html
search Search path
seed Random number generation seed

References

Gohel, David, and Panagiotis Skintzos. 2025. flextable: Functions for Tabular Reporting. https://doi.org/10.32614/CRAN.package.flextable.
Seshan, Venkatraman E., and Karissa Whiting. 2023. clinfun: Clinical Trial Design and Data Analysis Functions. https://doi.org/10.32614/CRAN.package.clinfun.
Simon, Richard. 1989. “Optimal Two-Stage Designs for Phase II Clinical Trials.” Controlled Clinical Trials 10 (1): 1–10. https://doi.org/https://doi.org/10.1016/0197-2456(89)90015-9.