Skip to contents

Practicals

Simple GSD optimization

Description:

Set an optimization criterion as a function of parameter(s).
Use numerical solvers, e.g., stats::nlminb().

Exercise:

  • Explore how the optimal parameter changes for a 3-stage design with respect to different alpha, beta and timing of analysis.

  • Find an optimal WT boundary for OS using KEYNOTE-598 study setting

library(gsDesign)

opt_fun <- function(
    x,                 # optimization parameter
    timing,            # timing of IAs
    delta ,            # target effect size 
    theta,             # effect size vector for which to get expected value N
    thetawgt,          # corresponing weight
    k = length(timing),# number of analysis
    alpha,             # Type I 
    beta,              # Type II
    sfu = "WT"
) {
  # Derive design
  d <- gsDesign(
    k = k,            
    timing = timing,   
    test.type = 1,     
    alpha     = alpha, 
    beta      = beta,  
    delta     = delta, 
    sfu = "WT",        
    sfupar = x[1]     
  )
  # Compute boundary crossing probabilities for input theta
  y <- gsProbability(theta = theta, d = d)
  # Compute weighted average of expected values of N 
  sp_1 <- head(y$upper$prob,-1)
  en <- sum(y$n.I * c(sp_1, 1 - sum(sp_1)))
  en <- sum(as.vector(en) * as.vector(thetawgt))
  return(en)
}


effect_size_H1 <- -log(0.70)/2  # standardized effect size under H1
beta_target  <- 0.20
alpha_target <- 0.025
IA_timing    <- (1:3)/3

# Call optimizer 
x <- nlminb(
  start = c(0.15),    # starting value for opt_fun
  opt_fun,            # function to optimize
                      # other fixed parameters
  k = 3,
  timing   = IA_timing,
  alpha    = alpha_target,
  beta     = beta_target,
  delta    = effect_size_H1,  # effect size under alternative
  theta    = effect_size_H1,  # to compute EN under H1
  thetawgt = 1,
)
# Optimal value of parameter for WT boundary
x$par
#> [1] 0.388577

# optimization function value at optimal 
x$objective
#> [1] 200.3242

Design details:

gsDesign(
  k = 3,
  test.type = 1,
  delta = effect_size_H1,
  alpha = alpha_target,
  beta  = beta_target,
  timing = IA_timing,
  sfu = "WT",
  sfupar = x$par
)
#> One-sided group sequential design with
#> 80 % power and 2.5 % Type I Error.
#>               
#>   Analysis  N   Z   Nominal p  Spend
#>          1  91 2.46    0.0070 0.0070
#>          2 182 2.28    0.0114 0.0091
#>          3 273 2.18    0.0148 0.0090
#>      Total                    0.0250 
#> 
#> ++ alpha spending:
#>  Wang-Tsiatis boundary with Delta = 0.388577023922542.
#> 
#> Boundary crossing probabilities and expected sample size
#> assume any cross stops the trial
#> 
#> Upper boundary (power or Type I Error)
#>           Analysis
#>    Theta      1      2      3 Total  E{N}
#>   0.0000 0.0070 0.0091 0.0090 0.025 270.1
#>   0.1783 0.2235 0.3452 0.2313 0.800 200.3

Compare with WT(0.389)

gsDesign(
  k = 3,
  test.type = 1,
  delta = effect_size_H1,
  alpha = alpha_target,
  beta  = beta_target,
  timing = IA_timing,
  sfu = "WT",
  sfupar = 0.389
)
#> One-sided group sequential design with
#> 80 % power and 2.5 % Type I Error.
#>               
#>   Analysis  N   Z   Nominal p  Spend
#>          1  91 2.46    0.0070 0.0070
#>          2 182 2.28    0.0114 0.0091
#>          3 273 2.18    0.0148 0.0090
#>      Total                    0.0250 
#> 
#> ++ alpha spending:
#>  Wang-Tsiatis boundary with Delta = 0.389.
#> 
#> Boundary crossing probabilities and expected sample size
#> assume any cross stops the trial
#> 
#> Upper boundary (power or Type I Error)
#>           Analysis
#>    Theta      1      2      3 Total  E{N}
#>   0.0000 0.0070 0.0091 0.0090 0.025 270.2
#>   0.1783 0.2238 0.3451 0.2311 0.800 200.3

Compare with a Lan-DeMets O’Brien-Fleming spending function

gsDesign(
  k = 3,
  test.type = 1,
  delta = effect_size_H1,
  alpha = alpha_target,
  beta  = beta_target,
  timing = IA_timing,
  sfu = sfLDOF
)
#> One-sided group sequential design with
#> 80 % power and 2.5 % Type I Error.
#>               
#>   Analysis  N   Z   Nominal p  Spend
#>          1  84 3.71    0.0001 0.0001
#>          2 167 2.51    0.0060 0.0059
#>          3 250 1.99    0.0231 0.0190
#>      Total                    0.0250 
#> 
#> ++ alpha spending:
#>  Lan-DeMets O'Brien-Fleming approximation spending function (no parameters).
#> 
#> Boundary crossing probabilities and expected sample size
#> assume any cross stops the trial
#> 
#> Upper boundary (power or Type I Error)
#>           Analysis
#>    Theta      1      2      3 Total  E{N}
#>   0.0000 0.0001 0.0059 0.0190 0.025 249.4
#>   0.1783 0.0186 0.3988 0.3826 0.800 213.6