Group sequential design using average hazard ratio under non-proportional hazards
Source:R/gs_update_ahr.R
gs_update_ahr.Rd
Group sequential design using average hazard ratio under non-proportional hazards
Arguments
- x
A original design created by either
gs_design_ahr
orgs_power_ahr
.- alpha
Alpha for the updated design.
- ia_alpha_spending
Alpha spending strategy for interim analyses, either
"actual_info_frac"
(default), or"min_of_planned_and_actual_info_frac"
.- fa_alpha_spending
Alpha spending strategy for final analysis, either
"info_frac"
or"full_alpha"
(default).- observed_data
a list of observed datasets by analyses.
Examples
library(gsDesign)
library(gsDesign2)
library(dplyr)
alpha <- 0.025
beta <- 0.1
ratio <- 1
# Enrollment
enroll_rate <- define_enroll_rate(
duration = c(2, 2, 10),
rate = (1:3) / 3)
# Failure and dropout
fail_rate <- define_fail_rate(
duration = c(3, Inf), fail_rate = log(2) / 9,
hr = c(1, 0.6), dropout_rate = .0001)
# IA and FA analysis time
analysis_time <- c(20, 36)
# Randomization ratio
ratio <- 1
# Example A: one-sided design (efficacy only) ----
# Original design
upper <- gs_spending_bound
upar <- list(sf = sfLDOF, total_spend = alpha)
x <- gs_design_ahr(
enroll_rate = enroll_rate, fail_rate = fail_rate,
alpha = alpha, beta = beta, ratio = ratio,
info_scale = "h0_info",
info_frac = NULL,
analysis_time = c(20, 36),
upper = gs_spending_bound, upar = upar,
lower = gs_b, lpar = rep(-Inf, 2),
test_upper = TRUE, test_lower = FALSE) |> to_integer()
# Observed dataset at IA and FA
set.seed(123)
observed_data <- simtrial::sim_pw_surv(
n = x$analysis$n[x$analysis$analysis == 2],
stratum = data.frame(stratum = "All", p = 1),
block = c(rep("control", 2), rep("experimental", 2)),
enroll_rate = x$enroll_rate,
fail_rate = (fail_rate |> simtrial::to_sim_pw_surv())$fail_rate,
dropout_rate = (fail_rate |> simtrial::to_sim_pw_surv())$dropout_rate)
observed_data_ia <- observed_data |> simtrial::cut_data_by_date(x$analysis$time[1])
observed_data_fa <- observed_data |> simtrial::cut_data_by_date(x$analysis$time[2])
# Example A1 ----
# IA spending = observed events / final planned events
gs_update_ahr(
x = x,
ia_alpha_spending = "actual_info_frac",
fa_alpha_spending = "full_alpha",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.2
#> 2 All 2 20.3
#> 3 All 10 30.5
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.315 0.00484 2.59 0.686 0.00484
#> 2 2 upper 0.901 0.0250 1.99 0.794 0.0235
#> 3 1 lower 0 0 -Inf Inf 1
#> 4 2 lower 0 0 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.86657 366 188 0.7356221 0.3070388 47.00 47.00 0.6329966
#> 2 2 35.81007 366 295 0.6832088 0.3809547 73.75 73.75 1.0000000
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"
# Example A2 ----
# IA, FA spending = observed events / final planned events
gs_update_ahr(
x = x,
ia_alpha_spending = "actual_info_frac",
fa_alpha_spending = "info_frac",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.2
#> 2 All 2 20.3
#> 3 All 10 30.5
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.315 0.00484 2.59 0.686 0.00484
#> 2 2 upper 0.899 0.0245 2.00 0.793 0.0230
#> 3 1 lower 0 0 -Inf Inf 1
#> 4 2 lower 0 0 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.86657 366 188 0.7356221 0.3070388 47.00 47.00 0.6329966
#> 2 2 35.81007 366 295 0.6832088 0.3809547 73.75 73.75 0.9932660
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"
# Example A3 ----
# IA spending = min(observed events, planned events) / final planned events
gs_update_ahr(
x = x,
ia_alpha_spending = "min_of_planned_and_actual_info_frac",
fa_alpha_spending = "full_alpha",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.2
#> 2 All 2 20.3
#> 3 All 10 30.5
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.315 0.00484 2.59 0.686 0.00484
#> 2 2 upper 0.901 0.0250 1.99 0.794 0.0235
#> 3 1 lower 0 0 -Inf Inf 1
#> 4 2 lower 0 0 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.86657 366 188 0.7356221 0.3070388 47.00 47.00 0.6329966
#> 2 2 35.81007 366 295 0.6832088 0.3809547 73.75 73.75 1.0000000
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"
# Example A4 ----
# IA spending = min(observed events, planned events) / final planned events
gs_update_ahr(
x = x,
ia_alpha_spending = "min_of_planned_and_actual_info_frac",
fa_alpha_spending = "info_frac",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.2
#> 2 All 2 20.3
#> 3 All 10 30.5
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.315 0.00484 2.59 0.686 0.00484
#> 2 2 upper 0.899 0.0245 2.00 0.793 0.0230
#> 3 1 lower 0 0 -Inf Inf 1
#> 4 2 lower 0 0 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.86657 366 188 0.7356221 0.3070388 47.00 47.00 0.6329966
#> 2 2 35.81007 366 295 0.6832088 0.3809547 73.75 73.75 0.9932660
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"
# Example A5 ----
# IA spending = min(observed events, planned events) / final planned events
# alpha is upadted to 0.05
gs_update_ahr(
x = x,
alpha = 0.05,
ia_alpha_spending = "min_of_planned_and_actual_info_frac",
fa_alpha_spending = "info_frac",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.2
#> 2 All 2 20.3
#> 3 All 10 30.5
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.461 0.0138 2.20 0.725 0.0138
#> 2 2 upper 0.943 0.0492 1.69 0.821 0.0451
#> 3 1 lower 0 0 -Inf Inf 1
#> 4 2 lower 0 0 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.86657 366 188 0.7356221 0.3070388 47.00 47.00 0.6329966
#> 2 2 35.81007 366 295 0.6832088 0.3809547 73.75 73.75 0.9932660
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"
# Example B: Two-sided asymmetric design,
# beta-spending with non-binding lower bound ----
# Original design
x <- gs_design_ahr(
enroll_rate = enroll_rate, fail_rate = fail_rate,
alpha = alpha, beta = beta, ratio = ratio,
info_scale = "h0_info",
info_frac = NULL, analysis_time = c(20, 36),
upper = gs_spending_bound,
upar = list(sf = sfLDOF, total_spend = alpha, param = NULL),
test_upper = TRUE,
lower = gs_spending_bound,
lpar = list(sf = sfLDOF, total_spend = beta, param = NULL),
test_lower = c(TRUE, FALSE),
binding = FALSE) |> to_integer()
# Example B1 ----
# IA spending = observed events / final planned events
# the remaining alpha will be allocated to FA.
gs_update_ahr(
x = x,
ia_alpha_spending = "actual_info_frac",
fa_alpha_spending = "full_alpha",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.6
#> 2 All 2 21.2
#> 3 All 10 31.8
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.290 0.00394 2.66 0.679 0.00394
#> 2 2 upper 0.894 0.0248 1.98 0.794 0.0239
#> 3 1 lower 0.0344 0.612 0.285 0.959 0.388
#> 4 2 lower 0.0344 0.612 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.91897 382 188 0.7356221 0.3070388 47.00 47.00 0.6045016
#> 2 2 36.06513 382 295 0.6832088 0.3809547 73.75 73.75 1.0000000
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"
# Example B2 ----
# IA, FA spending = observed events / final planned events
gs_update_ahr(
x = x,
ia_alpha_spending = "actual_info_frac",
fa_alpha_spending = "info_frac",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.6
#> 2 All 2 21.2
#> 3 All 10 31.8
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.290 0.00394 2.66 0.679 0.00394
#> 2 2 upper 0.882 0.0213 2.05 0.788 0.0201
#> 3 1 lower 0.0344 0.612 0.285 0.959 0.388
#> 4 2 lower 0.0344 0.612 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.91897 382 188 0.7356221 0.3070388 47.00 47.00 0.6045016
#> 2 2 36.06513 382 295 0.6832088 0.3809547 73.75 73.75 0.9485530
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"
# Example B3 ----
# IA spending = min(observed events, planned events) / final planned events
gs_update_ahr(
x = x,
ia_alpha_spending = "min_of_planned_and_actual_info_frac",
fa_alpha_spending = "full_alpha",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.6
#> 2 All 2 21.2
#> 3 All 10 31.8
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.290 0.00394 2.66 0.679 0.00394
#> 2 2 upper 0.894 0.0248 1.98 0.794 0.0239
#> 3 1 lower 0.0344 0.612 0.285 0.959 0.388
#> 4 2 lower 0.0344 0.612 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.91897 382 188 0.7356221 0.3070388 47.00 47.00 0.6045016
#> 2 2 36.06513 382 295 0.6832088 0.3809547 73.75 73.75 1.0000000
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"
# Example B4 ----
# IA spending = min(observed events, planned events) / final planned events
gs_update_ahr(
x = x,
ia_alpha_spending = "min_of_planned_and_actual_info_frac",
fa_alpha_spending = "info_frac",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.6
#> 2 All 2 21.2
#> 3 All 10 31.8
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.290 0.00394 2.66 0.679 0.00394
#> 2 2 upper 0.882 0.0213 2.05 0.788 0.0201
#> 3 1 lower 0.0344 0.612 0.285 0.959 0.388
#> 4 2 lower 0.0344 0.612 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.91897 382 188 0.7356221 0.3070388 47.00 47.00 0.6045016
#> 2 2 36.06513 382 295 0.6832088 0.3809547 73.75 73.75 0.9485530
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"
# Example A5 ----
# IA spending = min(observed events, planned events) / final planned events
# alpha is upadted to 0.05
gs_update_ahr(
x = x,
alpha = 0.05,
ia_alpha_spending = "min_of_planned_and_actual_info_frac",
fa_alpha_spending = "info_frac",
observed_data = list(observed_data_ia, observed_data_fa))
#> Joining with `by = join_by(analysis, bound, z)`
#> $enroll_rate
#> # A tibble: 3 × 3
#> stratum duration rate
#> <chr> <dbl> <dbl>
#> 1 All 2 10.6
#> 2 All 2 21.2
#> 3 All 10 31.8
#>
#> $fail_rate
#> # A tibble: 2 × 5
#> stratum duration fail_rate dropout_rate hr
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 All 3 0.0770 0.0001 1
#> 2 All Inf 0.0770 0.0001 0.6
#>
#> $bound
#> # A tibble: 4 × 7
#> analysis bound probability probability0 z `~hr at bound` `nominal p`
#> <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 upper 0.436 0.0117 2.27 0.718 0.0117
#> 2 2 upper 0.924 0.0436 1.74 0.816 0.0406
#> 3 1 lower 0.0344 0.612 0.285 0.959 0.388
#> 4 2 lower 0.0344 0.612 -Inf Inf 1
#>
#> $analysis
#> analysis time n event ahr theta info info0 info_frac
#> 1 1 19.91897 382 188 0.7356221 0.3070388 47.00 47.00 0.6045016
#> 2 2 36.06513 382 295 0.6832088 0.3809547 73.75 73.75 0.9485530
#>
#> attr(,"class")
#> [1] "non_binding" "ahr" "gs_design" "list"
#> [5] "updated_design"