Spaghetti viennese [🇷 for BE/BA]
hey good idea! I merged our pasta; some cosmetics. Added a “clinical justification” flag (T|F) which forces to ABE for Cmax if FALSE:
###### input section ######
GMR <- c(0.90, 0.90) # GMR of Cmax, AUC
CV <- c(0.55, 0.40) # CV of Cmax, AUC
pwr <- 0.8 # target power
des <- "2x2x4" # ABEL: "2x2x4", "2x2x3", "2x3x3"
# ABE : "2x2x2" ("2x2")
just <- TRUE # widening for Cmax clin. justified (T|F)
# TRUE: ABEL | FALSE: ABE
###########################
##### not implemented #####
n.min <- 12 # minimum sample size according to GL
reg <- "EMA" # "EMA" (ABEL for CV >0.3)
# "ANVISA" (ABEL for CV >0.4)
###########################
library(PowerTOST)
f1 <- function(x) power.TOST(CV=CV[2], theta0=x,
n=n, des=des)-pwr
f2 <- function(x) power.scABEL(CV=CV[1], theta0=x,
n=n, des=des, reg=reg)-pwr
f3 <- function(x) power.TOST(CV=CV[1], theta0=x,
n=n, des=des)-pwr
if (des == "2x2") des <- "2x2x2"
designs <- c("2x2x2", "2x2x4", "2x2x3", "2x3x3")
type <- c("RT|TR", "RTRT|TRTR", "RTR|TRT", "RRT|RTR|TRR")
trt0 <- c(2, 4, 3, 3) # treatments / subject
fmt <- paste0("%.", max(nchar(as.character(c(GMR, CV))))-2, "f")
ifelse (CV[1] <= 0.5, LL <- exp(-0.76*CV2se(CV[1])),
LL <- exp(-0.76*CV2se(0.5))) # lower scaled limit
if (CV[1] <= 0.3 | des == "2x2x2" | just == F) LL <- 0.8 # conv. limit
res <- matrix(nrow=2, ncol=10, byrow=T, dimnames=list(NULL,
c("Design", "method", "metric", "GMR", "CV",
"LL", "UL", "n", "power", "GMRlo")))
# 1st row: method / PK-metric driving the sample size
# 2nd row: the other one + lowest GMR keeping target power
res[, 1] <- type[match(des, designs)]
if (des == "2x2x2" | just == FALSE) { # 2x2 or ABEL not justified
tmp.Cmax <- sampleN.TOST(CV=CV[1], theta0=GMR[1],
targetpower=pwr, des=des, print=F)
} else { # design suitable and ABEL justified
tmp.Cmax <- sampleN.scABEL(CV=CV[1], theta0=GMR[1],
targetpower=pwr, des=des, reg=reg,
details=F, print=F)
}
n.Cmax <- tmp.Cmax[["Sample size"]]
pwr.Cmax <- tmp.Cmax[["Achieved power"]]
tmp.AUC <- sampleN.TOST(CV=CV[2], theta0=GMR[2],
targetpower=pwr, des=des, print=F) # ABE
n.AUC <- tmp.AUC[["Sample size"]]
pwr.AUC <- tmp.AUC[["Achieved power"]]
ifelse (n.Cmax >= n.AUC, n <- n.Cmax, n <- n.AUC)
txt <- NULL
if (n.Cmax >= n.AUC) { # sample size driven by Cmax
pwr.AUC <- power.TOST(CV=CV[2], theta0=GMR[2], n=n, des=des)
GMR.AUC.lo <- uniroot(f1, interval=c(0.8, GMR[2]), tol=1e-6)$root
ifelse (CV[1] <= 0.3 | des == "2x2x2" | just == FALSE,
res[1, 2] <- "ABE", res[1, 2] <- "ABEL")
if (des != "2x2x2" & just == FALSE) {
txt <- paste("Expanding limits for Cmax clinically not justified",
"(study will be\nevaluated by \u2013 conventional",
"\u2013 ABE).\n")
}
txt <- paste0(txt, "The sample size is ruled by Cmax.\n",
"Sample size: ", n, " (", res[1, 2], ", power: ",
sprintf("%.4f", pwr.Cmax), ")\n",
"Power of AUC (ABE): ", sprintf("%.4f", pwr.AUC), "\n",
"Lowest GMR of AUC which will give power ", pwr, ": ",
sprintf("%.4f", GMR.AUC.lo))
res[1, 3:10] <- c("Cmax", sprintf(fmt, GMR[1]),
sprintf(fmt, CV[1]), sprintf("%.4f", LL),
sprintf("%.4f", 1/LL), n,
sprintf("%.4f", pwr.Cmax), NA)
res[2, 2:10] <- c("ABE", "AUC", sprintf(fmt, GMR[2]),
sprintf(fmt, CV[2]), sprintf("%.4f", 0.8),
sprintf("%.4f", 1.25), n,
sprintf("%.4f", pwr.AUC),
sprintf("%.4f", GMR.AUC.lo))
} else { # sample size driven by AUC
if (des != "2x2x2" & just == TRUE) { # ABEL if justified
pwr.Cmax <- power.scABEL(CV=CV[1], theta0=GMR[1], n=n,
des=des, reg=reg)
GMR.Cmax.lo <- uniroot(f2, interval=c(LL, GMR[1]), tol=1e-6)$root
} else { # ABE
pwr.AUC <- power.TOST(CV=CV[1], theta0=GMR[1], n=n, des=des)
GMR.Cmax.lo <- uniroot(f3, interval=c(LL, GMR[1]), tol=1e-6)$root
}
txt <- paste0("The sample size is ruled by AUC.\n",
"Sample size: ", n, " (ABE, power: ",
sprintf("%.4f", pwr.AUC), ")\n",
"Power of Cmax")
ifelse (CV[1] <= 0.3 | des == "2x2x2" | just == FALSE,
txt <- paste(txt, "(ABE): "),
txt <- paste(txt, "(ABEL): "))
txt <- paste0(txt, sprintf("%.4f", pwr.Cmax), "\n",
"Lowest GMR of Cmax which will give power ", pwr, ": ",
sprintf("%.4f", GMR.Cmax.lo))
res[1, 2:10] <- c("ABE", "AUC", sprintf(fmt, GMR[2]),
sprintf(fmt, CV[2]), sprintf("%.4f", 0.8),
sprintf("%.4f", 1.25), n,
sprintf("%.4f", pwr.AUC), NA)
ifelse (CV[1] <= 0.3, res[2, 2] <- "ABE", res[2, 2] <- "ABEL")
res[2, 3:10] <- c("Cmax", sprintf(fmt, GMR[1]),
sprintf(fmt, CV[1]), sprintf("%.4f", LL),
sprintf("%.4f", 1/LL), n,
sprintf("%.4f", pwr.Cmax),
sprintf("%.4f", GMR.Cmax.lo))
}
txt <- paste(txt, "\nTotal number of treatments in study:",
as.numeric(res[1, 8])*trt0[match(des, designs)], "\n")
res <- data.frame(res)
print(res, row.names=F); cat(txt)
My first example:
Design method metric GMR CV LL UL n power GMRlo
RTRT|TRTR ABE AUC 0.90 0.40 0.8000 1.2500 68 0.8072 <NA>
RTRT|TRTR ABEL Cmax 0.90 0.55 0.6984 1.4319 68 0.9700 0.8435
The sample size is ruled by AUC.
Sample size: 68 (ABE, power: 0.8072)
Power of Cmax (ABEL): 0.9700
Lowest GMR of Cmax which will give power 0.8: 0.8435
Total number of treatments in study: 272
My second example:
Design method metric GMR CV LL UL n power GMRlo
RTRT|TRTR ABEL Cmax 0.90 0.35 0.7723 1.2948 34 0.8118 <NA>
RTRT|TRTR ABE AUC 0.95 0.25 0.8000 1.2500 34 0.9917 0.8892
The sample size is ruled by Cmax.
Sample size: 34 (ABEL, power: 0.8118)
Power of AUC (ABE): 0.9917
Lowest GMR of AUC which will give power 0.8: 0.8892
Total number of treatments in study: 136
And yours:
Design method metric GMR CV LL UL n power GMRlo
RT|TR ABE Cmax 0.95 0.29 0.8000 1.2500 38 0.8202 <NA>
RT|TR ABE AUC 0.94 0.25 0.8000 1.2500 38 0.8756 0.9232
The sample size is ruled by Cmax.
Sample size: 38 (ABE, power: 0.8202)
Power of AUC (ABE): 0.8756
Lowest GMR of AUC which will give power 0.8: 0.9232
Total number of treatments in study: 76
❝ Detlew, what about implementation in PowerTOST both branches?
I would say that’s overkill. In
PowerTOST
almost everything is vectorized (i.e., you can assess different CVs for T and R, calculate power for unbalanced sequences, etc.). I wouldn’t do that.One of the contributing authors of
PowerTOST
(Ben) is working on power for correlated PK-metrics. I guess that’s next we will see.❝ PS: Helmut&Detlew, it seems sometimes that you're thinking on R
Better than to think in R.

To do: Force sample sizes to 12 for low CVs (according to GLs),
reg <- "ANVISA"
(ABEL if CV >0.4), different CVs for T and R in replicate designs, throw a warning if in a RTR|TRT-design the estimated sample size is <24.Dif-tor heh smusma 🖖🏼 Довге життя Україна!
![[image]](https://static.bebac.at/pics/Blue_and_yellow_ribbon_UA.png)
Helmut Schütz
![[image]](https://static.bebac.at/img/CC by.png)
The quality of responses received is directly proportional to the quality of the question asked. 🚮
Science Quotes
Complete thread:
- Power calculation BE-proff 2015-08-13 13:44 [🇷 for BE/BA]
- Power calculation Helmut 2015-08-13 13:59
- Power calculation BE-proff 2015-08-13 14:44
- Example(s) Helmut 2015-08-13 14:58
- Power parallel group: PowerTOST/SAS/PASS d_labes 2015-08-14 10:29
- Power parallel group: PowerTOST/SAS/PASS Helmut 2015-08-14 15:34
- Power parallel group: PowerTOST/SAS/PASS d_labes 2015-08-14 10:29
- Slippery ground d_labes 2015-08-14 10:50
- Advanced example Helmut 2015-08-14 16:41
- Advanced example for 2X2X2 mittyri 2015-08-14 19:40
- Spaghetti vienneseHelmut 2015-08-15 03:22
- Spaghetti viennese d_labes 2015-08-17 08:45
- Spaghetti vienneseHelmut 2015-08-15 03:22
- Advanced example BE-proff 2015-08-17 08:55
- Advanced example for 2X2X2 mittyri 2015-08-14 19:40
- Advanced example Helmut 2015-08-14 16:41
- Example(s) Helmut 2015-08-13 14:58
- Power calculation BE-proff 2015-08-13 14:44
- Power calculation Helmut 2015-08-13 13:59