HC: Sample size for AUC and Cmax: exact and sim’s [Power / Sample Size]

posted by Helmut Homepage – Vienna, Austria, 2017-01-19 13:30 (2647 d 17:40 ago) – Posting: # 16983
Views: 6,325

Hi VStus,

❝ ❝ It’s easy enough through simulations (i.e., θ0 0.95, CVintra 40%, n 12, power 82.2%).

❝ Can such a simulation be performed using PowerTOST?


Yes – set α to 0.5. ;-)

library(PowerTOST)
alpha <- 0.5
# exact
sprintf("%.1f%%", 100*power.TOST(alpha=alpha, CV=0.4, theta0=0.95, n=12))
# [1] "82.2%"
# simulations
sprintf("%.1f%%", 100*power.TOST.sim(alpha=alpha, CV=0.4, theta0=0.95, n=12, nsim=1e6))
# [1] "82.2%"


Or the one of from my OP (1):

library(PowerTOST)
CV     <- seq(0.3, 1, 0.1)
theta0 <- seq(1, 1.6, 0.005)
power  <- matrix(nrow=length(CV), ncol=length(theta0), byrow=TRUE,
                 dimnames=list(CV, theta0))
matplot(1, 1, type="n", xlim=range(theta0), ylim=c(0, 100),
      xlab=expression(theta[0]), ylab="power (%)",
      main="HC\'s PE-inclusion (n=36)", cex.main=1, las=1)
grid()
ramp   <- colorRamp(c("lightblue", "orange"))
col    <- rgb(ramp(seq(0, 1, length=length(CV))), max=255)
op     <- par(no.readonly=TRUE)
par(family="mono")
legend("topright", title=expression(CV[w]),
       legend=sprintf("%3.0f%%", 100*CV), lwd=2, col=col, par)
par(op)
for (j in seq_along(CV)) {
 for (k in seq_along(theta0)) {
   power[j, k] <- 100*power.TOST(alpha=0.5, CV=CV[j],
                                 theta0=theta0[k], n=36)
 }
 lines(theta0, power[j, ], lwd=2, col=col[j])
}


Coming back to the subject line of this thread (2):

library(PowerTOST)
CV     <- seq(0.3, 1, 0.1)
hi     <- seq(1, 1.2, 0.02)
lo     <- 1/rev(hi)
theta0 <- unique(c(lo, hi))
design <- "2x2x4"
n.Cmax <- n.AUC <- matrix(nrow=length(CV), ncol=length(theta0), byrow=TRUE,
                          dimnames=list(CV, theta0))
for (j in seq_along(CV)) {
  for (k in seq_along(theta0)) {
    n.Cmax[j, k] <- sampleN.TOST(alpha=0.5, CV=CV[j], theta0=theta0[k],
                                 design=design, print=FALSE)[["Sample size"]]
    n.AUC[j, k]  <- sampleN.scABEL(alpha=0.05, CV=CV[j], theta0=theta0[k],
                                   design=design, regulator="HC",
                                   details=FALSE, print=FALSE)[["Sample size"]]
  }
}
ramp   <- colorRamp(c("lightblue", "orange"))
col    <- rgb(ramp(seq(0, 1, length=length(CV))), max=255)
op     <- par(no.readonly=TRUE)
split.screen(c(1, 2))
screen(1)
matplot(1, 1, type="n", log="xy", xlim=range(theta0), ylim=range(n.Cmax, n.AUC),
     las=1, xlab=expression(theta[0]), ylab="sample size", cex.main=0.9,
     main="Cmax: HC\'s PE-inclusion (80% power)")
grid()
abline(h=12, lty=3, col="blue")
par(family="mono")
legend("top", title=expression(CV[w]),
       legend=sprintf("%3.0f%%", 100*CV), pch=19, cex=0.9,
       pt.cex=1.15, col=col, bg="white", ncol=2)
par(family="")
for (j in seq_along(CV)) {
  points(theta0, n.Cmax[j, ], pch=19, cex=1.15, col=col[j])
}
screen(2)
matplot(1, 1, type="n", log="xy", xlim=range(theta0), ylim=range(n.Cmax, n.AUC),
     las=1, xlab=expression(theta[0]), ylab="sample size", cex.main=0.9,
     main="AUC: HC\'s ABEL (80% power)")
grid()
abline(h=12, lty=3, col="blue")
par(family="mono")
legend("top", title=expression(CV[w]),
       legend=sprintf("%3.0f%%", 100*CV), pch=19, cex=0.9,
       pt.cex=1.15, col=col, bg="white", ncol=2)
par(family="")
for (j in seq_along(CV)) {
  points(theta0, n.AUC[j, ], pch=19, cex=1.15, col=col[j])
}
close.screen(all=TRUE)
par(op)


[image]

Even if the CV of Cmax is much higher than the one of AUC we don’t have to worry about it – confirming what Detlew wrote above.

Now try this one (3):

library(PowerTOST)
CV     <- seq(0.3, 1, 0.1)
theta0 <- seq(1, 1.2, 0.02)
design <- "2x2x4"
n.Cmax <- n.AUC <- matrix(nrow=length(CV), ncol=length(theta0), byrow=TRUE,
                          dimnames=list(CV, theta0))
ramp   <- colorRamp(c("lightblue", "orange"))
col    <- paste0(rgb(ramp(seq(0, 1, length=length(CV))), max=255), "80")
matplot(1, 1, type="n", log="xy", xlim=c(6, 300), ylim=c(6, 300),las=1,
        xlab="Cmax [PE 80.0\u2013125.0%]",
        ylab="AUC [ABEL]", cex.main=1,
        main="sample size for 80% power")
grid()
abline(a=0, b=1, col="gray")
op     <- par(no.readonly=TRUE)
par(family="mono")
legend("bottomright", title=expression(CV[w]),
       legend=sprintf("%3.0f%%", 100*CV), pch=19, pt.cex=1.25, col=col,
       bg="white", ncol=2)
par(op)
for (j in seq_along(CV)) {
  for (k in seq_along(theta0)) {
    n.Cmax[j, k] <- sampleN.TOST(alpha=0.5, CV=CV[j], theta0=theta0[k],
                                 design=design, print=FALSE)[["Sample size"]]
    n.AUC[j, k]  <- sampleN.scABEL(alpha=0.05, CV=CV[j], theta0=theta0[k],
                                   design=design, regulator="HC",
                                   details=FALSE, print=FALSE)[["Sample size"]]
    points(n.Cmax[j, k], n.AUC[j, k], pch=19, cex=1.4, col=col[j])
  }
}


[image]

If the CVs of Cmax and AUC would be equal, ABEL still drives the sample size. At high CVs and PEs off from 1 scaling doesn’t help much more due to the CV cap + PE-restriction. Therefore, even in ABEL mainly the PE-restriction leads the BE-decision.


Edit: Patience! Runtimes on my machine: 1.9 s (1), 33 s (2), 17 s (3).

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
22,988 posts in 4,825 threads, 1,654 registered users;
90 visitors (0 registered, 90 guests [including 7 identified bots]).
Forum time: 08:10 CEST (Europe/Vienna)

The whole purpose of education is
to turn mirrors into windows.    Sydney J. Harris

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