ISR (Hoffman 2009) [🇷 for BE/BA]

posted by Helmut Homepage – Vienna, Austria, 2013-04-26 17:22 (4415 d 20:13 ago) – Posting: # 10500
Views: 5,075

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]
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,424 posts in 4,927 threads, 1,673 registered users;
77 visitors (0 registered, 77 guests [including 17 identified bots]).
Forum time: 13:35 CEST (Europe/Vienna)

It’s difficult to work in a group
when you are omnipotent.    John de Lancie (as Q)

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