Group sequential design computation with non-constant effect and information
Source:R/gs_design_npe.R
gs_design_npe.Rd
Derives group sequential design size, bounds and boundary crossing probabilities based on proportionate information and effect size at analyses. It allows a non-constant treatment effect over time, but also can be applied for the usual homogeneous effect size designs. It requires treatment effect and proportionate statistical information at each analysis as well as a method of deriving bounds, such as spending. The routine enables two things not available in the gsDesign package:
non-constant effect, 2) more flexibility in boundary selection. For many applications, the non-proportional-hazards design function
gs_design_nph()
will be used; it calls this function. Initial bound types supported are 1) spending bounds,fixed bounds, and 3) Haybittle-Peto-like bounds. The requirement is to have a boundary update method that can each bound without knowledge of future bounds. As an example, bounds based on conditional power that require knowledge of all future bounds are not supported by this routine; a more limited conditional power method will be demonstrated. Boundary family designs Wang-Tsiatis designs including the original (non-spending-function-based) O'Brien-Fleming and Pocock designs are not supported by
gs_power_npe()
.
Usage
gs_design_npe(
theta = 0.1,
theta0 = NULL,
theta1 = NULL,
info = 1,
info0 = NULL,
info1 = NULL,
info_scale = c("h0_h1_info", "h0_info", "h1_info"),
alpha = 0.025,
beta = 0.1,
upper = gs_b,
upar = qnorm(0.975),
lower = gs_b,
lpar = -Inf,
test_upper = TRUE,
test_lower = TRUE,
binding = FALSE,
r = 18,
tol = 1e-06
)
Arguments
- theta
Natural parameter for group sequential design representing expected incremental drift at all analyses; used for power calculation.
- theta0
Natural parameter used for upper bound spending; if
NULL
, this will be set to 0.- theta1
Natural parameter used for lower bound spending; if
NULL
, this will be set totheta
which yields the usual beta-spending. If set to 0, spending is 2-sided under null hypothesis.- info
Proportionate statistical information at all analyses for input
theta
.- info0
Proportionate statistical information under null hypothesis, if different than alternative; impacts null hypothesis bound calculation.
- info1
Proportionate statistical information under alternate hypothesis; impacts null hypothesis bound calculation.
- info_scale
Information scale for calculation. Options are:
"h0_h1_info"
(default): variance under both null and alternative hypotheses is used."h0_info"
: variance under null hypothesis is used."h1_info"
: variance under alternative hypothesis is used.
- alpha
One-sided Type I error.
- beta
Type II error.
- upper
Function to compute upper bound.
- upar
Parameters passed to the function provided in
upper
.- lower
Function to compare lower bound.
- lpar
Parameters passed to the function provided in
lower
.- test_upper
Indicator of which analyses should include an upper (efficacy) bound; single value of
TRUE
(default) indicates all analyses; otherwise, a logical vector of the same length asinfo
should indicate which analyses will have an efficacy bound.- test_lower
Indicator of which analyses should include an lower bound; single value of
TRUE
(default) indicates all analyses; single valueFALSE
indicates no lower bound; otherwise, a logical vector of the same length asinfo
should indicate which analyses will have a lower bound.- binding
Indicator of whether futility bound is binding; default of
FALSE
is recommended.- r
Integer value controlling grid for numerical integration as in Jennison and Turnbull (2000); default is 18, range is 1 to 80. Larger values provide larger number of grid points and greater accuracy. Normally
r
will not be changed by the user.- tol
Tolerance parameter for boundary convergence (on Z-scale).
Details
The inputs info
and info0
should be
vectors of the same length with increasing positive numbers.
The design returned will change these by some constant scale
factor to ensure the design has power 1 - beta
.
The bound specifications in upper
, lower
, upar
, lpar
will be used to ensure Type I error and other boundary properties are as specified.
Author
Keaven Anderson keaven_anderson@merck.com
Examples
library(dplyr)
library(gsDesign)
# Example 1 ----
# Single analysis
# Lachin book p 71 difference of proportions example
pc <- .28 # Control response rate
pe <- .40 # Experimental response rate
p0 <- (pc + pe) / 2 # Ave response rate under H0
# Information per increment of 1 in sample size
info0 <- 1 / (p0 * (1 - p0) * 4)
info <- 1 / (pc * (1 - pc) * 2 + pe * (1 - pe) * 2)
# Result should round up to next even number = 652
# Divide information needed under H1 by information per patient added
gs_design_npe(theta = pe - pc, info = info, info0 = info0)
#> # A tibble: 1 × 10
#> analysis bound z probability probability0 theta info info0 info1
#> <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 1.96 0.9 0.025 0.12 737. 725. 737.
#> # ℹ 1 more variable: info_frac <dbl>
# Example 2 ----
# Fixed bound
x <- gs_design_npe(
alpha = 0.0125,
theta = c(.1, .2, .3),
info = (1:3) * 80,
info0 = (1:3) * 80,
upper = gs_b,
upar = gsDesign::gsDesign(k = 3, sfu = gsDesign::sfLDOF, alpha = 0.0125)$upper$bound,
lower = gs_b,
lpar = c(-1, 0, 0)
)
x
#> # A tibble: 6 × 10
#> analysis bound z probability probability0 theta info_frac info info0
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 4.17 0.000278 0.0000152 0.1 0.333 51.6 51.6
#> 2 1 lower -1 0.0429 0.159 0.1 0.333 51.6 51.6
#> 3 2 upper 2.85 0.208 0.00222 0.2 0.667 103. 103.
#> 4 2 lower 0 0.0537 0.513 0.2 0.667 103. 103.
#> 5 3 upper 2.26 0.900 0.0125 0.3 1 155. 155.
#> 6 3 lower 0 0.0537 0.606 0.3 1 155. 155.
#> # ℹ 1 more variable: info1 <dbl>
# Same upper bound; this represents non-binding Type I error and will total 0.025
gs_power_npe(
theta = rep(0, 3),
info = (x %>% filter(bound == "upper"))$info,
upper = gs_b,
upar = (x %>% filter(bound == "upper"))$z,
lower = gs_b,
lpar = rep(-Inf, 3)
)
#> # A tibble: 6 × 10
#> analysis bound z probability theta theta1 info_frac info info0 info1
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 4.17 0.0000152 0 0 0.333 51.6 51.6 51.6
#> 2 2 upper 2.85 0.00222 0 0 0.667 103. 103. 103.
#> 3 3 upper 2.26 0.0125 0 0 1 155. 155. 155.
#> 4 1 lower -Inf 0 0 0 0.333 51.6 51.6 51.6
#> 5 2 lower -Inf 0 0 0 0.667 103. 103. 103.
#> 6 3 lower -Inf 0 0 0 1 155. 155. 155.
# Example 3 ----
# Spending bound examples
# Design with futility only at analysis 1; efficacy only at analyses 2, 3
# Spending bound for efficacy; fixed bound for futility
# NOTE: test_upper and test_lower DO NOT WORK with gs_b; must explicitly make bounds infinite
# test_upper and test_lower DO WORK with gs_spending_bound
gs_design_npe(
theta = c(.1, .2, .3),
info = (1:3) * 40,
info0 = (1:3) * 40,
upper = gs_spending_bound,
upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL),
lower = gs_b,
lpar = c(-1, -Inf, -Inf),
test_upper = c(FALSE, TRUE, TRUE)
)
#> # A tibble: 6 × 10
#> analysis bound z probability probability0 theta info_frac info info0
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper Inf 0 0 0.1 0.333 44.6 44.6
#> 2 1 lower -1 0.0477 0.159 0.1 0.333 44.6 44.6
#> 3 2 upper 2.51 0.267 0.00605 0.2 0.667 89.1 89.1
#> 4 2 lower -Inf 0.0477 0.159 0.2 0.667 89.1 89.1
#> 5 3 upper 1.99 0.900 0.0249 0.3 1 134. 134.
#> 6 3 lower -Inf 0.0477 0.159 0.3 1 134. 134.
#> # ℹ 1 more variable: info1 <dbl>
# one can try `info_scale = "h1_info"` or `info_scale = "h0_info"` here
gs_design_npe(
theta = c(.1, .2, .3),
info = (1:3) * 40,
info0 = (1:3) * 30,
info_scale = "h1_info",
upper = gs_spending_bound,
upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL),
lower = gs_b,
lpar = c(-1, -Inf, -Inf),
test_upper = c(FALSE, TRUE, TRUE)
)
#> # A tibble: 6 × 10
#> analysis bound z probability probability0 theta info_frac info info0
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper Inf 0 0 0.1 0.333 44.6 44.6
#> 2 1 lower -1 0.0477 0.159 0.1 0.333 44.6 44.6
#> 3 2 upper 2.51 0.267 0.00605 0.2 0.667 89.1 89.1
#> 4 2 lower -Inf 0.0477 0.159 0.2 0.667 89.1 89.1
#> 5 3 upper 1.99 0.900 0.0249 0.3 1 134. 134.
#> 6 3 lower -Inf 0.0477 0.159 0.3 1 134. 134.
#> # ℹ 1 more variable: info1 <dbl>
# Example 4 ----
# Spending function bounds
# 2-sided asymmetric bounds
# Lower spending based on non-zero effect
gs_design_npe(
theta = c(.1, .2, .3),
info = (1:3) * 40,
info0 = (1:3) * 30,
upper = gs_spending_bound,
upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL),
lower = gs_spending_bound,
lpar = list(sf = gsDesign::sfHSD, total_spend = 0.1, param = -1, timing = NULL)
)
#> # A tibble: 6 × 10
#> analysis bound z probability probability0 theta info_frac info info0
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 3.71 0.000145 0.000104 0.1 0.333 43.5 32.7
#> 2 1 lower -1.34 0.0139 0.0909 0.1 0.333 43.5 32.7
#> 3 2 upper 2.51 0.258 0.00605 0.2 0.667 87.1 65.3
#> 4 2 lower 0.150 0.0460 0.562 0.2 0.667 87.1 65.3
#> 5 3 upper 1.99 0.900 0.0249 0.3 1 131. 98.0
#> 6 3 lower 2.00 0.0908 0.976 0.3 1 131. 98.0
#> # ℹ 1 more variable: info1 <dbl>
# Example 5 ----
# Two-sided symmetric spend, O'Brien-Fleming spending
# Typically, 2-sided bounds are binding
xx <- gs_design_npe(
theta = c(.1, .2, .3),
info = (1:3) * 40,
binding = TRUE,
upper = gs_spending_bound,
upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL),
lower = gs_spending_bound,
lpar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL)
)
xx
#> # A tibble: 6 × 10
#> analysis bound z probability probability0 theta info_frac info info0
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 3.71 0.00104 0.000104 0.1 0.333 39.8 39.8
#> 2 1 lower -3.08 0.000104 0.00104 0.1 0.333 39.8 39.8
#> 3 2 upper 2.51 0.233 0.00605 0.2 0.667 79.5 79.5
#> 4 2 lower -0.728 0.00605 0.233 0.2 0.667 79.5 79.5
#> 5 3 upper 1.99 0.900 0.0250 0.3 1 119. 119.
#> 6 3 lower 1.28 0.0250 0.900 0.3 1 119. 119.
#> # ℹ 1 more variable: info1 <dbl>
# Re-use these bounds under alternate hypothesis
# Always use binding = TRUE for power calculations
gs_power_npe(
theta = c(.1, .2, .3),
info = (1:3) * 40,
binding = TRUE,
upper = gs_b,
lower = gs_b,
upar = (xx %>% filter(bound == "upper"))$z,
lpar = -(xx %>% filter(bound == "upper"))$z
)
#> # A tibble: 6 × 10
#> analysis bound z probability theta theta1 info_frac info info0 info1
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 3.71 0.00104 0.1 0.1 0.333 40 40 40
#> 2 2 upper 2.51 0.235 0.2 0.2 0.667 80 80 80
#> 3 3 upper 1.99 0.902 0.3 0.3 1 120 120 120
#> 4 1 lower -3.71 0.00000704 0.1 0.1 0.333 40 40 40
#> 5 2 lower -2.51 0.0000151 0.2 0.2 0.667 80 80 80
#> 6 3 lower -1.99 0.0000151 0.3 0.3 1 120 120 120