Parallel design: Only simulation-based methods so far [Two-Stage / GS Designs]

posted by Helmut Homepage – Vienna, Austria, 2024-04-04 22:16 (251 d 13:58 ago) – Posting: # 23940
Views: 5,813

Hi roman_max,

❝ hope you are doing fine and my post here fits to the subject.

Yes to both questions.

❝ I`m wondering how to show a power achieved after completion of the first stage in parallel design using Power2Stage functions, according to Potvin C algo?

Power in the interim is only a means of the decision tree (pass or fail in stage 1, continue to stage 2). Simply use the function power.TOST() with the respective alpha (0.0294 for Method B, 0.05 for Method C). Examples with the [image]-script at the end:

n1 <- c(50, 49) # 110 planned, 11 dropouts (different in the groups)
CV <- 0.45      # observed
PE <- 0.93      # observed (worse than the 0.95 assumed)
TSD.par(method = "B", CV, n1, PE)
Parallel design
Method B (‘Type 1’ TSD)
adj   = 0.0294 (both stages)
observed values in stage 1:
   CV = 0.45
   PE = 0.93
   n1 = 50 and 49 / per group (total 99)
interim power with adj 0.0294
not BE in stage 1, 94.12% CI: 78.85% - 109.69%
interim power = 0.4292, initiate stage 2 with 93 subjects


TSD.par(method = "C", CV, n1, PE)
Parallel design
Method C (‘Type 2’ TSD)
alpha = 0.05 (conditional on power)
adj   = 0.0294 (conditional)
observed values in stage 1:
   CV = 0.45
   PE = 0.93
   n1 = 50 and 49 / per group (total 99)
interim power with alpha 0.05
interim power = 0.5648
not BE in stage 1, 94.12% CI: 78.85% - 109.69%
initiate stage 2 with 93 subjects


n1 <- c(90, 89)
CV <- 0.45
PE <- 0.90
TSD.par(method = "B", CV, n1, PE)
Parallel design
Method B (‘Type 1’ TSD)
adj   = 0.0294 (both stages)
observed values in stage 1:
   CV = 0.45
   PE = 0.9
   n1 = 90 and 89 / per group (total 179)
interim power with adj 0.0294
not BE in stage 1, 94.12% CI: 79.66% - 101.69%
interim power = 0.7714, initiate stage 2 with 13 subjects


TSD.par(method = "C", CV, n1, PE)
Parallel design
Method C (‘Type 2’ TSD)
alpha = 0.05 (conditional on power)
adj   = 0.0294 (conditional)
observed values in stage 1:
   CV = 0.45
   PE = 0.9
   n1 = 90 and 89 / per group (total 179)
interim power with alpha 0.05
interim power = 0.8421
BE in stage 1, 90.00% CI: 80.94% - 100.08%

In the first example both methods perform equally. Not BE in stage 1 with the 94.12% CI, and therefore, same sample size in stage 2.
The second example shows why Method C can be more powerful than Method B. Whereas in Method B we fail with the 94.12% CI and therefore, have to initiate stage 2, in Method C we pass already in stage 1 with the 90% CI.

❝ When I do it for crossover study using interim.tsd.in function I can extract the value of Power Stage 1 component, but how about parallel study?

See the script below. However, no exact method is published for a parallel design yet and therefore, we don’t have it in Power2Stage.


TSD.par <- function(method = "B", CV, n1, PE) {
  library(PowerTOST)
  library(Power2Stage)
  # values of Fuglsang’s paper; don’t change!
  alpha  <- 0.05   # for Method C in stage 1
  adj    <- 0.0294 # adjusted alpha (conditionally in Method C, both stages in B)
  # Note: theta0 and target are fixed
  #       CIs in % rounded to two deciaml places acc. to GLs

  theta0 <- 0.95
  target <- 0.80
  info <- paste("\nParallel design")
  if (method == "B") {
    info <- paste(info, "\nMethod B (‘Type 1’ TSD)",
                  "\nadj   =", adj, "(both stages)")
  } else {
    info <- paste(info, "\nMethod C (‘Type 2’ TSD)",
                  "\nalpha =", alpha, "(conditional on power)",
                  "\nadj   =", adj, "(conditional)")
  }
  info <- paste(info, "\nobserved values in stage 1:",
                "\n   CV =", CV,
                "\n   PE =", PE,
                "\n   n1 =", paste(n1, collapse = " and "), "/ per group",
                sprintf("(total %.0f)", sum(n1)),
                "\ninterim power with")
  ifelse (method == "B",
    info <- paste(info, "adj", adj, "\n"),
    info <- paste(info, "alpha", alpha))
  cat(info)
  # the sample size of stage 2 is the same for both methods
  n2 <- sampleN2.TOST(alpha = adj, CV = CV, n1 = sum(n1), theta0 = theta0,
                      targetpower = target, design = "parallel")[["Sample size"]]
  prt.CI <- function(alpha, CI, lf = TRUE) {
    tmp <- sprintf("%.2f%% CI: %.2f%% - %.2f%%",
                   100 * (1 - 2 * alpha), CI[["lower"]], CI[["upper"]])
    if (lf) tmp <- paste0(tmp, "\n")
    return(tmp)
  }
  if (method == "B") {
    # we check for BE with adjusted alpha first
    CI.B <- round(100 * CI.BE(alpha = adj, pe = PE, CV = CV,
                              n = n1, design = "parallel"), 2)
    if (CI.B[["lower"]] >= 80 & CI.B[["upper"]] <= 125) {
      cat("BE in stage 1,", prt.CI(adj, CI.B, TRUE))
    } else {                # failed
      pwrB <- power.TOST(alpha = adj, CV = CV, theta0 = theta0,
                         design = "parallel", n = n1)
      if (pwrB >= target) { # stop because sufficient power
        cat("not BE in stage 1,", prt.CI(adj, CI.B, FALSE),
            "\nstop, because interim power =", signif(pwrB, 4), "\n")
      } else {              # low power → stage 2
        cat("not BE in stage 1,", prt.CI(adj, CI.B, FALSE),
            paste0("\ninterim power = ", signif(pwrB, 4),
                   ", initiate stage 2 with ", n2, " subjects\n"))
      }
    }
  } else {
    # we check power with unadjusted alpha first
    pwrC <- power.TOST(alpha = alpha, CV = CV, theta0 = theta0,
                       design = "parallel", n = n1)
    cat("\ninterim power =", signif(pwrC, 4))
    if (pwrC >= target) {
      # check for BE with unadjusted alpha first
      CI.C1 <- round(100 * CI.BE(alpha = alpha, pe = PE, CV = CV,
                                 n = n1, design = "parallel"), 2)
      if (CI.C1[["lower"]] >= 80 & CI.C1[["upper"]] <= 125) { # pass
        cat("\nBE in stage 1,", prt.CI(alpha, CI.C1, TRUE))
      } else {                                                # fail
        cat("\nnot BE in stage 1,", prt.CI(alpha, CI.C1, TRUE))
      }
    } else {
      # sufficient power, check for BE with adjusted alpha
      CI.C2 <- round(100 * CI.BE(alpha = adj, pe = PE, CV = CV,
                                 n = n1, design = "parallel"), 2)
      if (CI.C2[["lower"]] >= 80 & CI.C2[["upper"]] <= 125) { # pass
        cat("\nBE in stage 1,", prt.CI(adj, CI.C2, TRUE))
      } else {                                                # fail → stage 2
        cat("\nnot BE in stage 1,", prt.CI(adj, CI.C2, FALSE),
            "\ninitiate stage 2 with", n2, "subjects\n")
      }
    }
  }
}


Dif-tor heh smusma 🖖🏼 Довге життя Україна! [image]
Helmut Schütz
[image]

The quality of responses received is directly proportional to the quality of the question asked. 🚮
Science Quotes

Complete thread:

UA Flag
Activity
 Admin contact
23,336 posts in 4,902 threads, 1,666 registered users;
37 visitors (0 registered, 37 guests [including 12 identified bots]).
Forum time: 11:15 CET (Europe/Vienna)

Biostatistician. One who has neither the intellect for mathematics
nor the commitment for medicine but likes to dabble in both.    Stephen Senn

The Bioequivalence and Bioavailability Forum is hosted by
BEBAC Ing. Helmut Schütz
HTML5