Non-Inferiority

 

Details and examples of other methods are accessible via the menu bar on top of the page and in the online manual of all functions.

library(PowerTOST) # attach the library

Defaults

Parameter Argument Purpose Default
\(\small{\alpha}\) alpha Nominal level of the test 0.025
\(\small{\pi}\) targetpower Minimum desired power 0.80
logscale logscale Analysis on log-transformed or original scale? TRUE
margin margin Non-inferiority margin see below
\(\small{\theta_0}\) theta0 ‘True’ or assumed T/R ratio see below
CV CV CV none
design design Planned design "2x2"
imax imax Maximum number of iterations 100
print print Show information in the console? TRUE
details details Show details of the sample size search? FALSE

Note that contrary to the other functions of the package a one-sided t-test (instead of TOST) is employed. Hence, \(\small{\alpha}\) defaults to 0.025.
Defaults depending on the argument logscale:

Parameter Argument logscale=TRUE logscale=FALSE
margin margin 0.80 –0.20
\(\small{\theta_0}\) theta0 0.95 +0.05

Arguments targetpower, margin, theta0, and CV have to be given as fractions, not in percent.
The CV is generally the within- (intra-) subject coefficient of variation. Only for design = "parallel" it is the total (a.k.a. pooled) CV.

Designs with one (parallel), two (conventional crossover and paired), and three or four periods (replicates) are supported.

#      design                        name   df
#  "parallel"           2 parallel groups  n-2
#       "2x2"               2x2 crossover  n-2
#     "2x2x2"             2x2x2 crossover  n-2
#     "2x2x3"   2x2x3 replicate crossover 2n-3
#     "2x2x4"   2x2x4 replicate crossover 3n-4
#     "2x4x4"   2x4x4 replicate crossover 3n-4
#     "2x3x3"   partial replicate (2x3x3) 2n-3
#     "2x4x2"            Balaam’s (2x4x2)  n-2
#    "2x2x2r" Liu’s 2x2x2 repeated x-over 3n-2
#    "paired"                paired means  n-1

The terminology of the design argument follows this pattern: treatments x sequences x periods. The conventional TR|RT (a.k.a. AB|BA) design can be abbreviated as "2x2". Some call the "parallel" design a ‘one-sequence’ design. The design "paired" has two periods but no sequences, e.g., in studying linear pharmacokinetics a single dose is followed by multiple doses. A profile in steady state (T) is compared to the one after the single dose (R). Note that the underlying model assumes no period effects.

With sampleN.noninf(..., details = FALSE, print = FALSE) results are provided as a data frame 1 with eight columns Design, alpha, CV, theta0, Margin, Sample size, Achieved power, and Target power. To access e.g., the sample size use either sampleN.noninf[1, 6] or sampleN.noninf[["Sample size"]]. We suggest to use the latter in scripts for clarity.

The estimated sample size gives always the total number of subjects (not subject/sequence in crossovers or subjects/group in parallel designs – like in some other software packages).

Non-Inferiority

If the supplied margin is < 1 (logscale = TRUE) or < 0 (logscale = FALSE), then it is assumed that higher response values are better. The hypotheses are with

Example 1

Estimate the sample size for assumed intra-subject CV 0.25. Defaults margin 0.80 and \(\small{\theta_{0}}\) 0.95 employed.

sampleN.noninf(CV = 0.25)
# 
# ++++++++++++ Non-inferiority test +++++++++++++
#             Sample size estimation
# -----------------------------------------------
# Study design: 2x2 crossover 
# log-transformed data (multiplicative model)
# 
# alpha = 0.025, target power = 0.8
# Non-inf. margin = 0.8
# True ratio = 0.95,  CV = 0.25
# 
# Sample size (total)
#  n     power
# 36   0.820330

To get only the sample size:

sampleN.noninf(CV = 0.25, details = FALSE, print = FALSE)[["Sample size"]]
# [1] 36

Note that the sample size is always rounded up to give balanced sequences (here a multiple of two). Since power is higher than our target, likely this was the case here. Let us assess that:
Which power will we get with a sample size of 35?

power.noninf(CV = 0.25, n = 35)
# Unbalanced design. n(i)=18/17 assumed.
# [1] 0.8085908

Confirmed that with 35 subjects we will already reach the target power. That means also that one dropout will not compromise power.

Non-Superiority

If the supplied margin is > 1 (logscale = TRUE) or > 0 (logscale = FALSE), then it is assumed that lower response values are better. The hypotheses are with

Example 2

Estimate the sample size for assumed intra-subject CV 0.25.

sampleN.noninf(CV = 0.25, margin = 1.25, theta0 = 1/0.95)
# 
# ++++++++++++ Non-superiority test +++++++++++++
#             Sample size estimation
# -----------------------------------------------
# Study design: 2x2 crossover 
# log-transformed data (multiplicative model)
# 
# alpha = 0.025, target power = 0.8
# Non-inf. margin = 1.25
# True ratio = 1.052632,  CV = 0.25
# 
# Sample size (total)
#  n     power
# 36   0.820330

Same sample size like in example 1 since reciprocal values of both margin 0.80 and \(\small{\theta_{0}}\) are specified.

Bracketing Approach

Compare a new modified release formulation (regimen once a day) with an intermediate release formulation (twice a day).2 Cmin is the target metric for efficacy (non-inferiority) and Cmax for safety (non-superiority). Margins are 0.80 for Cmin and 1.25 for Cmax. CVs are 0.35 for Cmin and 0.20 for Cmax; \(\small{\theta_{0}}\) 0.95 for Cmin and 1.05 for Cmax. Full replicate design due to the high variability of Cmin.
Which PK metric leads the sample size?

res <- data.frame(design = "2x2x4", metric = c("Cmin", "Cmax"),
                  margin = c(0.80, 1.25), CV = c(0.35, 0.20),
                  theta0 = c(0.95, 1.05), n = NA, power = NA,
                  stringsAsFactors = FALSE) # this line for R <4.0.0)
for (i in 1:2) {
  res[i, 6:7] <- sampleN.noninf(design = res$design[i],
                                margin = res$margin[i],
                                theta0 = res$theta0[i],
                                CV = res$CV[i],
                                details = FALSE,
                                print = FALSE)[6:7]
}
print(res, row.names = FALSE)
#  design metric margin   CV theta0  n     power
#   2x2x4   Cmin   0.80 0.35   0.95 32 0.8077926
#   2x2x4   Cmax   1.25 0.20   1.05 12 0.8406410

The sample size depends on Cmin. Hence, the study is ‘overpowered’ for Cmax.

power.noninf(design = "2x2x4", margin = 1.25, CV = 0.20,
             theta0 = 1.05, n = 32)
# [1] 0.9984996

Therefore, that gives us some ‘safety margin’ for Cmax.

power.noninf(design = "2x2x4", margin = 1.25, CV = 0.25,
             theta0 = 1.10, n = 32) # higher CV, worse theta0
# [1] 0.8279726

The bracketing approach does not necessarily give lower sample sizes than tests for equivalence. In this example we could aim at reference-scaling for the highly variable Cmin and at conventional ABE for Cmax.

res <- data.frame(design = "2x2x4", intended = c("ABEL", "ABE"),
                  metric = c("Cmin", "Cmax"), CV = c(0.35, 0.20),
                  theta0 = c(0.90, 1.05), n = NA, power = NA,
                  stringsAsFactors = FALSE) # this line for R <4.0.0
res[1, 6:7] <- sampleN.scABEL(CV = res$CV[1], theta0 = res$theta0[1],
                              design = res$design[1], print = FALSE,
                              details = FALSE)[8:9]
res[2, 6:7] <- sampleN.TOST(CV = res$CV[2], theta0 = res$theta0[2],
                            design = res$design[2], print = FALSE,
                            details = FALSE)[7:8]
print(res, row.names = FALSE)
#  design intended metric   CV theta0  n     power
#   2x2x4     ABEL   Cmin 0.35   0.90 34 0.8118400
#   2x2x4      ABE   Cmax 0.20   1.05 10 0.8517596

Which method is optimal is a case-to-case decision. Although in this example the bracketing approach seems to be the ‘winner’ (32 subjects instead of 34), we might fail if the CV of Cmin is larger than assumed, whereas in reference-scaling we might still pass due to the expanded limits.

n <- sampleN.scABEL(CV = 0.35, theta0 = 0.90, design = "2x2x4",
                    print = FALSE, details = FALSE)[["Sample size"]]
# CV and theta0 of both metrics worse than assumed
res <- data.frame(design = "2x2x4", intended = c("ABEL", "ABE"),
                  metric = c("Cmin", "Cmax"), CV = c(0.50, 0.25),
                  theta0 = c(0.88, 1.12), n = n, power = NA,
                  stringsAsFactors = FALSE) # this line for R <4.0.0
res[1, 7] <- power.scABEL(CV = res$CV[1], theta0 = res$theta0[1],
                          design = res$design[1], n = n)
res[2, 7] <- power.TOST(CV = res$CV[2], theta0 = res$theta0[2],
                        design = res$design[2], n = n)
print(res, row.names = FALSE)
#  design intended metric   CV theta0  n     power
#   2x2x4     ABEL   Cmin 0.50   0.88 34 0.8183300
#   2x2x4      ABE   Cmax 0.25   1.12 34 0.8258111

See also the vignettes RSABE, ABE, and PA.

Author

Detlew Labes

License

GPL-3 2024-03-18 Helmut Schütz


  1. R Documentation. Data Frames. 2020-10-26. R-manual.↩︎

  2. European Medicines Agency, Committee for Medicinal Products for Human Use. Guideline on the pharmacokinetic and clinical evaluation of modified release dosage forms. London. 20 November 2014. EMA/CPMP/EWP/280/96 Corr1. online.↩︎