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 (3435 d 08:22 ago) – Posting: # 16983
Views: 8,919

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
23,654 posts in 4,992 threads, 1,571 registered users;
121 visitors (0 registered, 121 guests [including 15 identified bots]).
Forum time: 22:52 CEST (Europe/Vienna)

Always listen to experts.
They’ll tell you what can’t be done and why.
Then do it.    Robert A. Heinlein

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