To whom it may concern…
#################################################
# D Hoffman #
# Statistical Considerations for Assessment of #
# Bioanalytical Incurred Sample Reproducibility #
# AAPS J 11(3), 570–80 (2009) #
# ###############################################
debug <- FALSE # display some intermediate results
valid <- FALSE # T: use Hoffman's fixed values in some places
example <- 2
ISR2 <- function(Y0, YR, debug=F, valid=F, example, main)
{
Delta <- log(YR)-log(Y0)
Delta.m <- mean(Delta)
if (debug) {
cat("\u2206:", round(Delta.m, 5), "[paper:")
if (example == 1) cat("0.11274]\n")
if (example == 2) cat("-0.03350]\n")
}
Delta.v <- var(Delta)
if (debug) {
cat("\u03c3²:", round(Delta.v, 5), "[paper:")
if (example == 1) cat("0.01722]\n")
if (example == 2) cat("0.01034]\n")
}
Delta.s <- sd(Delta)
n <- length(Delta)
sig <- c(-1, +1)
alpha <- 0.1
ifelse (valid,
beta <- 0.667, # Hoffman's
beta <- 2/3 # exact
)
ifelse (valid,
Limit <- 21.2, # Hoffman's
Limit <- 15*sqrt(2) # exact
)
AL <- sig*(log(1+Limit/100))
A <- AL[1]; B <- AL[2]
if (debug) cat("Z:", round(qnorm((1+beta)/2), 5), "(", (1+beta)/2, ") [paper: 0.96809 (0.8335)]\n")
if (debug) {
cat("\u03c7²:", round(qchisq(alpha, n-1), 4), "(", n-1, alpha, ") [paper: ")
if (example == 1) cat("35.0814 (47 0.10)]\n")
if (example == 2) cat("24.7966 (35 {typo: 47} 0.10)]\n")
}
TL <- Delta.m+sig*(qnorm((1+beta)/2)*sqrt(1+1/n)*sqrt((n-1)*Delta.v/qchisq(alpha, n-1)))
TL.assessment <- "failed" # default
if (TL[1] >= A & TL[2] <= B) TL.assessment <- "passed"
omega <- sqrt(n/(n-1))
pi.hat <- pnorm(omega*(B-Delta.m)/Delta.s)-pnorm(omega*(A-Delta.m)/Delta.s)
if (debug) {
cat("\u03c0:", round(pi.hat, 4), "[paper:")
if (example == 1) cat("0.7205]\n")
if (example == 2) cat("0.9312]\n")
}
phi.A <- dnorm(omega*(A-Delta.m)/Delta.s)
phi.B <- dnorm(omega*(B-Delta.m)/Delta.s)
var.pi <- (1/(n-1))*(phi.A-phi.B)^2+(omega^2/(2*(n-1)*Delta.v))*((B-Delta.m)*phi.B-(A-Delta.m)*phi.A)^2
if (debug) {
cat("\u03c3²\u03c0:", round(var.pi, 6), "[paper:")
if (example == 1) cat("0.002715]\n")
if (example == 2) cat("0.00110]\n")
}
if (debug) cat("Z:", round(qnorm(1-alpha/2), 4), "(", 1-alpha/2, ") [paper: 1.6448 (0.90)]\n")
eta <- (qnorm(1-alpha/2)^2*var.pi)/(pi.hat*(1-pi.hat))
if (debug) {
cat("\u03b7:", round(eta, 5), "[paper:")
if (example == 1) cat("0.03647]\n")
if (example == 2) cat("0.04631]\n")
}
pi.L <- (1/(1+eta))*((pi.hat+0.5*eta)-sqrt(eta*pi.hat*(1-pi.hat)+0.25*eta^2))
if (debug) {
cat("\u03c0L:", round(pi.L, 4), "[paper:")
if (example == 1) cat("0.6282]\n")
if (example == 2) cat("0.8556]\n")
}
CL.assessment <- "failed" # default
if (pi.L > beta) CL.assessment <- "passed"
###########
# Results #
###########
cat("\n", sprintf("%s%s %i %s", main, ":", n, "repeated samples\n"),
"\u2206:", sprintf("%+.5f %s%.2f%%%s %.5f", Delta.m, "(", 100*exp(Delta.m), "); \u03c3²:", Delta.v),"\n",
"Acceptance range:", paste0(sprintf("%+.4f ", AL), "(", sprintf("%.2f%%", 100*exp(AL)), ")"),"\n",
"Tolerance limits:", paste0(sprintf("%+.4f ", TL), "(", sprintf("%.2f%%", 100*exp(TL)), ")"),"\n",
"ISR test", TL.assessment, "tolerance-interval acceptance criterion.\n\n",
"\u03c0:", sprintf("%.4f %s%.2f%%%s %.6f", pi.hat, "(", 100*pi.hat, "); \u03c3²\u03c0:", var.pi),"\n")
if (valid) {
cat(" Required proportion:", sprintf("%.3f %s%.1f%%%s", beta, "(", 100*beta, ")"), "\n")
} else {
cat(" Required proportion:", sprintf("%.4f %s%.2f%%%s", beta, "(", 100*beta, ")"), "\n")
}
cat(" Lower confidence bound:", sprintf("%.4f %s%.2f%%%s", pi.L, "(", 100*pi.L, ")"), "\n",
"ISR test", CL.assessment, "containment proportion acceptance criterion.\n\n")
}
Gives with …
# Example Table II.
Reported <- c(4030,14100,2120,21.6,859,192,2710,13000,886,9.46,401,123,
3520,3430,2580,13.7,1410,437,3240,11000,879,6.68,384,57,
2930,11400,2310,6.11,881,193,3870,16600,1250,10.3,581,196)
Repeated <- c(4070,12600,1530,19.9,761,215,2790,10000,787,9.01,381,122,
3370,3410,2630,13.2,1320,433,3250,12200,799,6.24,313,64.8,
3150,11600,2270,6.22,900,169,4340,16200,1180,9.62,673,188)
ISR2(Reported, Repeated, debug=F, valid=F, example=2, main="Example 2, LC/MS-MS")
Example 2, LC/MS-MS: 36 repeated samples
∆: -0.03350 (96.71%); σ²: 0.01034
Acceptance range: -0.1924 (82.50%) +0.1924 (121.21%)
Tolerance limits: -0.1520 (85.90%) +0.0850 (108.87%)
ISR test passed tolerance-interval acceptance criterion.
π: 0.9314 (93.14%); σ²π: 0.00109
Required proportion: 0.6667 (66.67%)
Lower confidence bound: 0.8558 (85.58%)
ISR test passed containment proportion acceptance criterion.
In the function call use debug=T to display intermediate results and/or valid=T for reproducing Hoffman’s examples (he used 0.667 instead of ⅔ and 21.2% instead of the exact value 15×√ 2).
The suggested testing strategy should only applied to data generated from a confirmatory ISR test (in the event of an initial ISR failure based on the regulatory 4–6–20 rule) – which is not the case with both of his examples (evaluated with this code):
Example 1, LC/MS-MS: 48 repeated samples
∆: 5 negative, 0 zero, 43 positive
Maximum |∆|: 57.09%
18.75% of samples showed >20% |∆| – passed regulatory criterion (≥2/3 within ±20%).
Example 2, LC/MS-MS: 36 repeated samples
∆: 23 negative, 0 zero, 13 positive
Maximum |∆|: 32.33%
8.33% of samples showed >20% |∆| – passed regulatory criterion (≥2/3 within ±20%).—
Dif-tor heh smusma 🖖🏼 Довге життя Україна! ![[image]](https://static.bebac.at/pics/Blue_and_yellow_ribbon_UA.png)
Helmut Schütz
The quality of responses received is directly proportional to the quality of the question asked. 🚮
Science Quotes |