
Course materials
course-materials.Rmd
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