Skip to content

Adjust the final futility bound with same value as the efficacy bound for asymmetric non-binding design #593

Description

@LittleBeannie

Example 1: a two-sided, asymmetric, beta-spending with non-binding lower bound design

The following code generate a two-sided, asymmetric, beta-spending with non-binding lower bound design.

# ------------------------------ #
#         parameters             #
# ------------------------------ #
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 = Inf, fail_rate = log(2) / 9,
  hr = 0.6, dropout_rate = .0001)

# IA and FA analysis time
analysis_time <- c(12, 24, 36)

# Randomization ratio
ratio <- 1

# Spending
upper <- gs_spending_bound
lower <- gs_spending_bound
upar <- list(sf = sfLDOF, total_spend = alpha)
lpar <- list(sf = sfHSD, total_spend = 0.1, param = 3)

# ------------------------------ #
# design by gsDesign2   #
# ------------------------------ #
x_gsd2 <- gs_design_ahr(
  enroll_rate = enroll_rate, fail_rate = fail_rate,
  alpha = alpha, beta = beta, ratio = ratio,
  info_scale = "h0_h1_info",
  info_frac = 1:3/3,
  analysis_time = 36,
  upper = upper, upar = upar, test_upper = TRUE,
  lower = lower, lpar = lpar, test_lower = TRUE,
  binding = FALSE, h1_spending = TRUE
)

Issue

The final efficacy and futility bounds at the final analysis are not the same. However, we expect them to the be same value at the final analysis.

> x_gsd2$bound |> dplyr::filter(analysis == 3, bound == "upper") |> dplyr::pull(z)
[1] 1.993051
> x_gsd2$bound |> dplyr::filter(analysis == 3, bound == "lower") |> dplyr::pull(z)
[1] 1.789483

In gsDesign with the sample parameters, the efficacy and futility bounds are of same value at the final analysis.

# ------------------------------ #
# design by gsDesign    #
# ------------------------------ #
x_gsd <- gsSurv(k = 3, test.type = 4, alpha = alpha, beta = beta,
                astar = 0, timing = 1:3/3,
                sfu = sfLDOF, sfupar = 0,
                sfl = sfHSD, sflpar = 3,
                lambdaC = fail_rate$fail_rate, hr = fail_rate$hr, hr0 = 1,
                eta = fail_rate$dropout_rate,
                gamma = enroll_rate$rate,
                R = enroll_rate$duration,
                S = NULL, T = analysis_time[3],
                minfup = analysis_time[3] - sum(enroll_rate$duration),
                ratio = ratio)

> x_gsd$upper$bound[3]
[1] 1.99297
> x_gsd$lower$bound[3]
[1] 1.99297

Example 2: a two-sided, asymmetric, beta-spending with binding lower bound design

The following code generate a two-sided, asymmetric, beta-spending with binding lower bound design.

# ------------------------------ #
#         parameters             #
# ------------------------------ #
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 = Inf, fail_rate = log(2) / 9,
  hr = 0.6, dropout_rate = .0001)

# IA and FA analysis time
analysis_time <- c(12, 24, 36)

# Randomization ratio
ratio <- 1

# Spending
upper <- gs_spending_bound
lower <- gs_spending_bound
upar <- list(sf = sfLDOF, total_spend = alpha)
lpar <- list(sf = sfHSD, total_spend = 0.1, param = 3)

# ------------------------------ #
# design by gsDesign2   #
# ------------------------------ #
x_gsd2 <- gs_design_ahr(
  enroll_rate = enroll_rate, fail_rate = fail_rate,
  alpha = alpha, beta = beta, ratio = ratio,
  info_scale = "h0_h1_info",
  info_frac = 1:3/3,
  analysis_time = 36,
  upper = upper, upar = upar, test_upper = TRUE,
  lower = lower, lpar = lpar, test_lower = TRUE,
  binding = TRUE, h1_spending = TRUE
)

Issue

The final efficacy and futility bounds at the final analysis are not the same. However, we expect them to the be same value at the final analysis.

> x_gsd2$bound |> dplyr::filter(analysis == 3, bound == "upper") |> dplyr::pull(z)
[1] 1.850081
> x_gsd2$bound |> dplyr::filter(analysis == 3, bound == "lower") |> dplyr::pull(z)
[1] 1.665859

In gsDesign with the sample parameters, the efficacy and futility bounds are of same value at the final analysis.

# ------------------------------ #
# design by gsDesign    #
# ------------------------------ #
x_gsd <- gsSurv(k = 3, test.type = 3, alpha = alpha, beta = beta,
                astar = 0, timing = 1:3/3,
                sfu = sfLDOF, sfupar = 0,
                sfl = sfHSD, sflpar = 3,
                lambdaC = fail_rate$fail_rate, hr = fail_rate$hr, hr0 = 1,
                eta = fail_rate$dropout_rate,
                gamma = enroll_rate$rate,
                R = enroll_rate$duration,
                S = NULL, T = analysis_time[3],
                minfup = analysis_time[3] - sum(enroll_rate$duration),
                ratio = ratio)

> x_gsd$upper$bound[3]
[1] 1.789885
> x_gsd$lower$bound[3]
[1] 1.789885

Objective

We will follow what gsDesign does to enable gsDesign2 to have the same efficacy and futility bound when it is a two-sided, asymmetric, beta-spending with non-binding/binding lower bound design.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions