Helmut
★★★
avatar
Homepage
Vienna, Austria,
2020-05-14 20:36
(1670 d 23:26 ago)

Posting: # 21437
Views: 2,853
 

 Pseudo-validation [🇷 for BE/BA]

Dear R-Users,

we had already a couple of times the discussion whether [image] can be used in regulated environments, and the answer was always: Yes – if the code is validated.

When it comes to the package PowerTOST, in the /tests sub-folder of the library you find scripts which you can use to black-box validate your installation, i.e., compare the results with the respective reference tables.
If you are an expe[image]t, you can inspect the code for correctness (white-box validation). Given, pretty difficult.

Another approach is to perform simulations, like in ElMaestro’s famous EFG.
I started with sample sizes for ABE.

library(PowerTOST)
compl.seq <- function(n, size) {
  # round (up) to complete sequence
  size <- as.integer(size)
  return(size * (n %/% size + as.logical(n %% size)))
}
sampleN.TOST.sim <- function(alpha = 0.05, CV = CV, theta0 = 0.95,
                             theta1 = 0.80, theta2 = 1.25, targetpower = 0.80,
                             design = "2x2x2", nsims = 1e5) {
  # sample size by simulations which gives at least targetpower
  if (missing(CV)) stop("CV must be given!")
  if (missing(theta2) & !missing(theta1)) theta2 <- 1/theta1
  if (missing(theta1) & !missing(theta2)) theta1 <- 1/theta2
  design <- as.character(design)
  fun1 <- function(x) { # the workhorse
    suppressWarnings(
      suppressMessages(
        power.TOST.sim(n = x, CV = CV, theta1 = theta1, theta2 = theta2,
                       theta0 = theta0, design = design, nsims = nsims))) -
                       targetpower
  }
  tmp <- uniroot(fun1, interval = c(4L, 64L), extendInt = "upX", tol = 0.1)
  n   <- ceiling(tmp$root)                  # next integer
  n   <- compl.seq(n, substr(design, 3, 3)) # ensure balance
  pwr <- power.TOST.sim(n = n, CV = CV, theta1 = theta1, theta2 = theta2,
                        theta0 = theta0, design = design, nsims = nsims)
  res <- data.frame(Design = design, alpha = alpha, CV = CV, theta0 = theta0,
                    theta1 = theta1, theta2 = theta2, n = n, pwr = pwr,
                    target = targetpower, nsims = nsims, Iterations = tmp$iter)
  names(res)[7:9] <- c("Sample size", "Achieved power", "Target power")
  return(res)
}


Comparison with sampleN.TOST(), exact method:
CV     <- 0.4
design <- "2x2x4"
print(sampleN.TOST(CV = CV, design = design,
      print = FALSE, details = FALSE), row.names = FALSE)
 Design alpha  CV theta0 theta1 theta2 Sample size Achieved power Target power
  2x2x4  0.05 0.4   0.95    0.8   1.25          34      0.8193438          0.8

print(sampleN.TOST.sim(CV = CV, design = design), row.names = FALSE)
 Design alpha  CV theta0 theta1 theta2 Sample size Achieved power Target power nsims Iterations
  2x2x4  0.05 0.4   0.95    0.8   1.25          34        0.81812          0.8 1e+05         10

print(sampleN.TOST.sim(CV = CV, design = design, nsims = 1e6), row.names = FALSE)
 Design alpha  CV theta0 theta1 theta2 Sample size Achieved power Target power nsims Iterations
  2x2x4  0.05 0.4   0.95    0.8   1.25          34       0.819263          0.8 1e+06         10


Well, these simulation are based on the statistics (lognormal-distributed PE, χ²-distributed s²). If you believe that only the ‘gold-standard’ of subject-simulations are valid, we can misuse the function sampleN.scABEL.sdsims() – only for the 3- and 4-period full replicates and the partial replicate:
# define a reg_const where all scaling conditions are ‘switched off’
abe    <- reg_const("USER", r_const = NA, CVswitch = Inf,
                    CVcap = Inf, pe_constr = FALSE)
CV     <- 0.4
design <- "2x2x4"
print(sampleN.scABEL.sdsims(CV = CV, theta0 = 0.95, design = design,
      regulator = abe, print = FALSE, details = FALSE)[1:10], row.names = FALSE)
 Design alpha CVwT CVwR theta0 theta1 theta2 Sample size Achieved power Target power
  2x2x4  0.05  0.4  0.4   0.95    0.8   1.25          34        0.81737          0.8

print(sampleN.scABEL.sdsims(CV = CV, theta0 = 0.95, design = design,
      regulator = abe, nsims = 1e6, print = FALSE, details = FALSE)[1:10], row.names = FALSE)
 Design alpha CVwT CVwR theta0 theta1 theta2 Sample size Achieved power Target power
  2x2x4  0.05  0.4  0.4   0.95    0.8   1.25          34       0.819161          0.8


Since the sample sizes obtained by all simulations match the exact method, we can be confident that it is correct. As usual with a higher number of simulations power gets closer to the exact value.

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
UA Flag
Activity
 Admin contact
23,336 posts in 4,902 threads, 1,668 registered users;
43 visitors (0 registered, 43 guests [including 11 identified bots]).
Forum time: 19:03 CET (Europe/Vienna)

Every man is fully satisfied that there is such a thing as truth,
or he would not ask any question.    Charles Sanders Peirce

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