Sample size and power [RSABE / ABEL]

posted by Helmut Homepage – Vienna, Austria, 2022-03-28 15:39 (929 d 21:28 ago) – Posting: # 22876
Views: 1,735

Dear all,

following this thread some remarks.

The idea behind Scaled Average Bioequivalence (SABE) is to avoid extreme sample sizes required for Average Bio­equi­va­lence (ABE) while preserving power independent from the CV.

With the [image]-script at the end you can reproduce the plots below. All with sample sizes for at least 80% power in a two-se­quence four-period full replicate design. Since Average Bio­equi­va­lence with Expanding Limits (ABEL) is less permissive than Re­fe­rence-Scaled Average Bioequivalence (RSABE) we require larger sample sizes (28–36 vs 22–32).

[image]

[image]


If \(\small{\widehat{CV}_\textrm{wR}}\) is relatively small, the ABE-component is relevant. At \(\small{\widehat{CV}_\textrm{wR}\sim 30\%}\) the chance to assess the study by ABE is \(\small{\sim 50\%}\). When \(\small{\widehat{CV}_\textrm{wR}}\) gets larger, the PE-constraint gets increasingly important. That’s more pronounced for RSABE because in ABEL the upper cap of scaling is relevant as well.


library(PowerTOST)
design <- "2x2x4"
target <- 0.8
theta0 <- 0.9
CV     <- seq(0.3, 0.65, 0.0005)
# Cave: Long runtime with such a small step size
# 'Pure' SABE for comparison: No upper cup of scaling, no PE constraint
# ABEL modified

pure1  <- reg_const("USER", r_const = 0.76, CVswitch = 0.3, CVcap = Inf)
# RSABE modified
pure2  <- reg_const("USER", r_const = log(1.25)/0.25, CVswitch = 0.3, CVcap = Inf)
pure1$pe_constr  <- pure2$pe_constr <- FALSE
pure1$est_method <- "ANOVA"
pure2$est_method <- "ISC"
# Defaults: theta0 = 0.9, targetpower = 0.8
res1   <- res2 <- data.frame(CV = CV, n = NA_integer_, overall = NA_real_,
                             PE = NA_real_, ABE = NA_real_, SABE = NA_real_)
pb     <- txtProgressBar(0, 1, 0, char = "\u2588", width = NA, style = 3)
for (i in seq_along(CV)) {
  tmp           <- sampleN.scABEL(CV = CV[i], design = design,
                                  theta0 = theta0, targetpower = target,
                                  details = FALSE, print = FALSE)
  res1[i, 2] <- tmp[["Sample size"]]
  res1[i, 3] <- tmp[["Achieved power"]]
  tmp        <- sampleN.RSABE(CV = CV[i], design = design,
                              theta0 = theta0, targetpower = target,
                              details = FALSE, print = FALSE)
  res2[i, 2] <- tmp[["Sample size"]]
  res2[i, 3] <- tmp[["Achieved power"]]
  # Component of ABEL and RSABE: PE within constraints
  res1[i, 4] <- suppressMessages(
                  power.scABEL(CV = CV[i], design = design,
                               theta0 = theta0, n = res1$n[i],
                               details = TRUE)[3])
  res2[i, 4] <- suppressMessages(
                  power.RSABE(CV = CV[i], design = design,
                               theta0 = theta0, n = res2$n[i],
                               details = TRUE)[3])
  # Component of ABEL and RSABE: ABE
  res1[i, 5] <- power.TOST(CV = CV[i], design = design,
                           theta0 = theta0, n = res1$n[i])
  res2[i, 5] <- power.TOST(CV = CV[i], design = design,
                           theta0 = 0.9, n = res2$n[i])
  # unconstrained SABE
  res1[i, 6] <- power.scABEL(CV = CV[i], design = design,
                             theta0 = theta0, n = res1$n[i],
                             regulator = pure1)
  res2[i, 6] <- power.RSABE(CV = CV[i], design = design,
                             theta0 = theta0, n = res2$n[i],
                             regulator = pure2)
  setTxtProgressBar(pb, i / length(CV))
}
close(pb)

# Plots
clr    <- c("#0000AA80", "magenta", "#11AA10", "#CC000080")
leg    <- c("PE constraint alone", "ABE", "Unconstrained SABE")
dev.new(width = 4.5, height = 4.5)
op     <- par(no.readonly = TRUE)
par(mar = c(3, 2.8, 0, 0), mgp = c(2, 0.5, 0), cex.axis = 0.9)
# ABEL
plot(CV, res1$n, type = "n", ylim = range(c(res1[, 3:6], res2[, 3:6])),
     xlab = expression(italic(CV)[wR]), ylab = "power", las = 1)
abline(v = c(0.3, 0.5), lty = 2)
grid(); box()
lines(CV, res1$overall, lwd = 2, col = clr[1])
lines(CV, res1$PE, lwd = 2, col = clr[2])
lines(CV, res1$ABE, lwd = 2, col = clr[3])
lines(CV, res1$SABE, lwd = 2, col = clr[4])
legend("right", bg = "white", box.lty = 0, seg.len = 3, inset = 0.02, col = clr,
       legend = c("ABEL", leg), lwd = 2, y.intersp = 1.2, cex = 0.9)
# RSABE
plot(CV, res2$n, type = "n", ylim = range(c(res1[, 3:6], res2[, 3:6])),
     xlab = expression(italic(CV)[wR]), ylab = "power", las = 1)
abline(v = 0.3, lty = 2)
grid(); box()
lines(CV, res2$overall, lwd = 2, col = clr[1])
lines(CV, res2$PE, lwd = 2, col = clr[2])
lines(CV, res2$ABE, lwd = 2, col = clr[3])
lines(CV, res2$SABE, lwd = 2, col = clr[4])
legend("right", bg = "white", box.lty = 0, seg.len = 3, inset = 0.02, col = clr,
       legend = c("RSABE", leg), lwd = 2, y.intersp = 1.2, cex = 0.9)
par(op)


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,249 posts in 4,885 threads, 1,660 registered users;
59 visitors (0 registered, 59 guests [including 9 identified bots]).
Forum time: 13:08 CEST (Europe/Vienna)

I believe there is no philosophical high-road in science,
with epistemological signposts. No, we are in a jungle
and find our way by trial and error,
building our road behind us as we proceed.    Max Born

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