Visualize Simon's Two-Stage Phase II Design

Tingting Zhan

Introduction

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

Getting Started

Examples in this vignette require that the search path has

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

Simon’s Two-Stage Phase II Design

Notations

Simon’s 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.
  1. Enroll an additional (n-n_1) subjects.

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 the function clinfun::ph2simon().

Types of Simon’s two-stage design include

S3 class 'ph2simon'

The 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'

The 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 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 simulate 1e4L Simon’s two-stage trials of each drug to obtain the operating characteristics, i.e., the percentage of trials in which each drug

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)