19  Clinical Sample-Size Calculation

Sample size is determined by effect size, variability, confidence level, power, and study design; it is not a fixed constant. This chapter covers the three sample-size problems implemented by ivdtools: Bland–Altman agreement precision/power, precision of a single-proportion confidence interval, and a one-arm test of a proportion against a target.

ImportantScope of Use

The functions do not add attrition, invalid samples, minimum numbers per stratum, design effects, clustering, or multiplicity adjustments. delta in a Bland–Altman calculation is the clinically acceptable limit, not the observed LoA. Confidence-interval methods and one- or two-sided directions must be prespecified. Preserve all assumptions and sensitivity analyses, not only the final integer.

Code
library(ivdtools)

19.1 Main Functions

Function Main purpose Solving direction
sample_size_bland_altman() Bland–Altman agreement evaluation Solve for n from target power
sample_size_proportion_ci() Single-proportion confidence interval Solve for n from the target half-width
sample_size_proportion() One-arm target-value test Solve for n from the target alpha and power

All three functions are parameter-driven and do not require raw data. They return structured results; the sample size is in result$n, and print() shows target and achieved quantities. Round-up, attrition, invalid samples, and minimum stratum counts must be handled separately.

19.1.1 Interfaces

Code
sample_size_bland_altman(
  power = 0.80, mu, sd, delta,
  conf.level = 0.95, agree.level = 0.95,
  method = "lu", n.min = 3, n.max = 1e5
)
sample_size_proportion_ci(
  p, half_width, conf.level = 0.95,
  interval = c("two.sided", "lower", "upper"),
  method = "wilson", n.max = 1e6
)
sample_size_proportion(
  p0, p1, alpha = 0.05, power = 0.80,
  alternative = c("greater", "less", "two.sided"),
  test = "exact", power_method = "binomial", n.max = 1e6
)

For Bland–Altman, the target LoA are

\[ \mu\pm z_{(1+\gamma)/2}\sigma, \]

where $γ=agree.level. The function uses the Lu et al. noncentral-t calculation for the probability that both LoA confidence bounds remain within \(±\delta\) and searches for the smallest integer meeting target power. It requires \(δ>|\mu|+z_{(1+γ)/2}σ\).

For a proportion interval, the target is a half-width \(d\). For two-sided intervals,

\[\frac{U-L}{2}\le d,\]

and for one-sided intervals the distance from the expected proportion to the relevant limit is at most \(d\). The interval method affects the required sample size and must be stated in the protocol.

For a one-arm test, test determines the rejection region and power_method chooses continuous normal planning or discrete binomial enumeration. The final integer sample size is checked using actual alpha and achieved power; binomial planning additionally controls actual alpha rather than relying on an approximation.

19.2 Analysis Examples

19.2.1 Bland–Altman Agreement

Code
n_ba <- sample_size_bland_altman(
  power = 0.80, mu = 0.2, sd = 1, delta = 2.5
)
print(n_ba)
Sample size for Bland-Altman agreement assessment
  Method            : Lu et al. (2016), noncentral-t approximation
  Mean difference   : 0.2000
  SD of differences : 1.0000
  Clinical limit    : 2.5000
  Confidence level  : 0.9500
  Agreement level   : 0.9500
  Sample size (n)   : 201
  Target power      : 0.800000
  Achieved power    : 0.800300

Under these teaching parameters, approximately 201 pairs are needed for 80% power. mu is mean difference, sd is difference SD, and delta is the clinical agreement limit. conf.level and agree.level describe different layers: reliability of the LoA estimate versus coverage of the LoA itself.

19.2.2 Single-Proportion Confidence Interval

Code
n_pci <- sample_size_proportion_ci(p = 0.3, half_width = 0.05)
print(n_pci)
Sample size for a single-proportion confidence interval
  Method                : wilson
  Interval              : two.sided
  Anticipated proportion: 0.3000
  Confidence level      : 0.9500
  Sample size (n)       : 320
  Target half-width     : 0.050000
  Achieved half-width   : 0.049967
  Target total width    : 0.100000
  Achieved total width  : 0.099934
  Planning interval     : [0.252406, 0.352339]
  Actual coverage       : 0.956096
  Actual alpha          : 0.043904

For expected proportion 0.3 and a 95% Wilson half-width of 0.05, approximately 320 observations are needed. Available methods include Wilson, Wald, continuity-corrected Wald/Wilson, Agresti–Coull, Jeffreys, and Clopper–Pearson.

19.2.3 One-Arm Target-Value Test

Code
n_sp <- sample_size_proportion(
  p0 = 0.2, p1 = 0.35, alpha = 0.05, power = 0.8,
  alternative = "greater", test = "exact", power_method = "binomial"
)
print(n_sp)
Sample size for a single-proportion target-value test
  Test                  : Exact binomial test
  Power calculation     : Binomial enumeration
  H0: p <= 0.2000
  H1: p > 0.2000
  Expected p            : 0.3500
  Sample size (n)       : 56
  Target alpha          : 0.050000
  Actual alpha          : 0.043209
  Alpha criterion       : met
  Target power          : 0.800000
  Achieved power        : 0.806416 (binomial evaluation)
  Critical successes    : >= 17

alternative="greater" requires \(p_1>p_0\); use "less" or "two.sided" as appropriate. Exact, score, continuity-corrected score, Wald, and related test definitions are not interchangeable. Specify both test and power_method in the protocol.

19.2.4 Standard and Guidance Cross-Checks

The supplied examples compare the functions with PASS, SAS, and CMDE calculations. Small differences can arise from continuous normal planning versus discrete binomial enumeration, exact quantiles versus rounded handbook quantiles, interval definitions, and integer search rules. For example, a handbook may report a rounded approximate sample size while the package returns the first integer whose actual operating characteristics meet the stated constraint. Report both the selected method and achieved alpha/power.

19.3 Interpretation Checklist

  1. Define the primary endpoint, analysis unit, expected proportion or difference, allowable error, and tail direction.
  2. Run sensitivity analyses for uncertain SDs, proportions, prevalence, and agreement limits.
  3. Select interval and test methods before calculating the sample size.
  4. Add attrition, invalid-sample, stratification, clustering, and multiple-endpoint allowances outside these functions.
  5. Save parameters, function calls, outputs, and the software version in the protocol.

19.4 Complete Standard Cases

19.4.1 Bland–Altman: PASS Examples 1 and 2

PASS Example 1 fixes mu = 0.5, delta = 7, and conf.level = agree.level = 0.95, then crosses two power levels with three difference SDs. The comparison below keeps every row, including rows that do not agree, and reports both sample-size and achieved-power differences.

Code
ba_manual <- data.frame(
  target_power = c(0.8, 0.8, 0.8, 0.9, 0.9, 0.9),
  sd = c(2.5, 2.6, 2.7, 2.5, 2.6, 2.7),
  pass_n = c(60L, 82L, 118L, 78L, 108L, 156L),
  pass_power = c(0.8059, 0.8019, 0.8024, 0.9014, 0.9003, 0.9002)
)
ba_results <- lapply(
  seq_len(nrow(ba_manual)),
  function(i) sample_size_bland_altman(
    power = ba_manual$target_power[i],
    mu = 0.5, sd = ba_manual$sd[i], delta = 7,
    conf.level = 0.95, agree.level = 0.95
  )
)
All parameter combinations in PASS Bland–Altman Example 1
Standard location Statistic Standard ivdtools
PASS BA Example 1 / power=0.8 / SD=2.5 sample size 60.0000 59.000000
PASS BA Example 1 / power=0.8 / SD=2.5 achieved power 0.8059 0.803126
PASS BA Example 1 / power=0.8 / SD=2.6 sample size 82.0000 82.000000
PASS BA Example 1 / power=0.8 / SD=2.6 achieved power 0.8019 0.803997
PASS BA Example 1 / power=0.8 / SD=2.7 sample size 118.0000 118.000000
PASS BA Example 1 / power=0.8 / SD=2.7 achieved power 0.8024 0.803101
PASS BA Example 1 / power=0.9 / SD=2.5 sample size 78.0000 78.000000
PASS BA Example 1 / power=0.9 / SD=2.5 achieved power 0.9014 0.901856
PASS BA Example 1 / power=0.9 / SD=2.6 sample size 108.0000 108.000000
PASS BA Example 1 / power=0.9 / SD=2.6 achieved power 0.9003 0.900492
PASS BA Example 1 / power=0.9 / SD=2.7 sample size 156.0000 156.000000
PASS BA Example 1 / power=0.9 / SD=2.7 achieved power 0.9002 0.900235

For power = 0.8 and SD = 2.5, PASS reports 60, while the Lu noncentral-t formula as listed in the manual gives 59 as the first searched integer meeting the target. PASS does not publish its internal values at n = 59, so this comparison does not attribute the difference to rounding or force the package result upward. The power column is retained as reported: several small-n rows differ by approximately 0.00004–0.0028, with the difference shrinking as n increases.

PASS Example 2 uses mu = 0.2, SD = 1, and delta = 2.5 to validate the result in the Lu et al. paper. The paper table gives 203, while PASS and ivdtools both obtain 201 when searching for the first integer that reaches the target; this difference is between the paper’s approximate result and an integer search.

19.4.2 Proportion Confidence Intervals: PASS Examples 1–4

PASS two-sided cases specify total width, whereas the package takes half_width, so the comparison uses half_width = target_width / 2. Example 1 gives three widths and five expected proportions for 15 Clopper–Pearson combinations.

Code
ci_manual <- expand.grid(
  p = seq(0.1, 0.5, by = 0.1),
  target_width = c(0.04, 0.06, 0.10)
)
ci_manual$pass_n <- c(
  914L, 1585L, 2065L, 2353L, 2449L,
  417L, 715L, 928L, 1056L, 1098L,
  158L, 264L, 341L, 387L, 402L
)
ci_results <- lapply(
  seq_len(nrow(ci_manual)),
  function(i) sample_size_proportion_ci(
    p = ci_manual$p[i],
    half_width = ci_manual$target_width[i] / 2,
    conf.level = 0.95,
    interval = "two.sided",
    method = "clopper-pearson"
  )
)
The 15 combinations in PASS exact proportion-interval Example 1
Standard location Statistic Standard ivdtools
PASS CI Example 1 / p=0.1 / width=0.04 sample size 914 914
PASS CI Example 1 / p=0.2 / width=0.04 sample size 1585 1585
PASS CI Example 1 / p=0.3 / width=0.04 sample size 2065 2065
PASS CI Example 1 / p=0.4 / width=0.04 sample size 2353 2353
PASS CI Example 1 / p=0.5 / width=0.04 sample size 2449 2449
PASS CI Example 1 / p=0.1 / width=0.06 sample size 417 417
PASS CI Example 1 / p=0.2 / width=0.06 sample size 715 715
PASS CI Example 1 / p=0.3 / width=0.06 sample size 928 928
PASS CI Example 1 / p=0.4 / width=0.06 sample size 1056 1056
PASS CI Example 1 / p=0.5 / width=0.06 sample size 1098 1098
PASS CI Example 1 / p=0.1 / width=0.10 sample size 158 158
PASS CI Example 1 / p=0.2 / width=0.10 sample size 264 264
PASS CI Example 1 / p=0.3 / width=0.10 sample size 341 341
PASS CI Example 1 / p=0.4 / width=0.10 sample size 387 387
PASS CI Example 1 / p=0.5 / width=0.10 sample size 402 402

The package also enumerates coverage at the final n; this is a diagnostic separate from the width condition used to select n in PASS.

Code
ci_special <- data.frame(
  case = c("PASS Example 2", "PASS Example 3", "PASS Example 4"),
  design = c(
    "one-sided lower limit, Clopper--Pearson",
    "two-sided, Wilson continuity correction",
    "one-sided upper limit, Clopper--Pearson, p=0"
  ),
  pass_n = c(25L, 29L, 299L)
)
ci_special_results <- list(
  sample_size_proportion_ci(
    p = 0.92, half_width = 0.15104,
    interval = "lower", method = "clopper-pearson"
  ),
  sample_size_proportion_ci(
    p = 0.034483, half_width = 0.1945 / 2,
    interval = "two.sided", method = "wilson-cc"
  ),
  sample_size_proportion_ci(
    p = 0, half_width = 0.01,
    interval = "upper", method = "clopper-pearson"
  )
)
One-sided, continuity-corrected, and boundary cases from PASS
Standard location Statistic Standard ivdtools
PASS Example 2 sample size 25 25
PASS Example 3 sample size 29 29
PASS Example 4 sample size 299 299

Example 3 shows that Wilson continuity correction must use the corrected score-inversion formula; mechanically adding or subtracting 1/(2n) from ordinary Wilson endpoints does not reproduce PASS. Example 4 validates a one-sided exact interval with p = 0, so the package allows expected proportions of 0 and 1 for interval planning.

19.4.3 One-Sample Proportion Target Tests: SAS and PASS Comparison

The software options map to package parameters as follows.

SAS/PASS option ivdtools parameter Meaning
SAS TEST=Z VAREST=NULL; PASS Z-test using S(P0) test = “score” p0 variance in the alpha term
SAS TEST=ADJZ; PASS S(P0) with C.C. test = “score-cc” S(P0) Z test with continuity correction
PASS Z-test using S(Phat) test = “wald” Wald approximation using p1 variance in the alpha term
METHOD=NORMAL; Normal Approximation power_method = “normal” Continuous normal approximation
Exact; Binomial Enumeration power_method = “binomial” Discrete binomial rejection region and power

The comparison covers the uncorrected and corrected SAS Example 90.2 results, PASS Examples 9 and 11, and six effect sizes from PASS Example 2.

Code
target_manual <- data.frame(
  case = c(
    "SAS 90.2 Z", "SAS 90.2 ADJZ", "PASS 9", "PASS 11",
    paste0("PASS 2, p1=", sprintf("%.2f", seq(0.55, 0.80, 0.05)))
  ),
  alternative = c(
    "less", "less", "greater", "two.sided", rep("two.sided", 6)
  ),
  test = c(
    "score", "score-cc", "score", "wald", rep("score", 6)
  ),
  p0 = c(0.30, 0.30, 0.50, 0.30, rep(0.50, 6)),
  p1 = c(0.20, 0.20, 0.60, 0.50, seq(0.55, 0.80, 0.05)),
  target_power = c(0.80, 0.80, 0.80, 0.80, rep(0.90, 6)),
  manual_n = c(119L, 129L, 153L, 50L, 1047L, 259L, 113L, 62L, 38L, 25L),
  manual_power = c(
    0.80000, 0.80100, 0.80125, 0.80743,
    0.90011, 0.90055, 0.90120, 0.90286, 0.90249, 0.90321
  )
)
target_results <- lapply(
  seq_len(nrow(target_manual)),
  function(i) sample_size_proportion(
    p0 = target_manual$p0[i], p1 = target_manual$p1[i],
    alpha = 0.05, power = target_manual$target_power[i],
    alternative = target_manual$alternative[i],
    test = target_manual$test[i], power_method = "normal"
  )
)
SAS and PASS one-sample proportion target-test comparison
Standard location Statistic Standard ivdtools
SAS 90.2 Z sample size 119.00000 119.00000
SAS 90.2 Z normal planning power 0.80000 0.80032
SAS 90.2 ADJZ sample size 129.00000 129.00000
SAS 90.2 ADJZ normal planning power 0.80100 0.80094
PASS 9 sample size 153.00000 153.00000
PASS 9 normal planning power 0.80125 0.80125
PASS 11 sample size 50.00000 50.00000
PASS 11 normal planning power 0.80743 0.80743
PASS 2, p1=0.55 sample size 1047.00000 1047.00000
PASS 2, p1=0.55 normal planning power 0.90011 0.90011
PASS 2, p1=0.60 sample size 259.00000 259.00000
PASS 2, p1=0.60 normal planning power 0.90055 0.90055
PASS 2, p1=0.65 sample size 113.00000 113.00000
PASS 2, p1=0.65 normal planning power 0.90120 0.90120
PASS 2, p1=0.70 sample size 62.00000 62.00000
PASS 2, p1=0.70 normal planning power 0.90286 0.90286
PASS 2, p1=0.75 sample size 38.00000 38.00000
PASS 2, p1=0.75 normal planning power 0.90249 0.90249
PASS 2, p1=0.80 sample size 25.00000 25.00000
PASS 2, p1=0.80 normal planning power 0.90321 0.90321

Check the discrete operating characteristics at the final integer sample size:

Discrete binomial check of continuous-normal planning
Standard location Statistic Standard ivdtools
SAS 90.2 Z binomial achieved power NA 0.80363
SAS 90.2 Z actual alpha 0.05 0.04776
SAS 90.2 ADJZ binomial achieved power NA 0.79446
SAS 90.2 ADJZ actual alpha 0.05 0.03595
PASS 9 binomial achieved power NA 0.80944
PASS 9 actual alpha 0.05 0.05280
PASS 11 binomial achieved power NA 0.83888
PASS 11 actual alpha 0.05 0.06532
PASS 2, p1=0.55 binomial achieved power NA 0.89681
PASS 2, p1=0.55 actual alpha 0.05 0.04789
PASS 2, p1=0.60 binomial achieved power NA 0.89499
PASS 2, p1=0.60 actual alpha 0.05 0.04656
PASS 2, p1=0.65 binomial achieved power NA 0.91362
PASS 2, p1=0.65 actual alpha 0.05 0.05943
PASS 2, p1=0.70 binomial achieved power NA 0.91073
PASS 2, p1=0.70 actual alpha 0.05 0.05590
PASS 2, p1=0.75 binomial achieved power NA 0.86830
PASS 2, p1=0.75 actual alpha 0.05 0.03355
PASS 2, p1=0.80 binomial achieved power NA 0.89088
PASS 2, p1=0.80 actual alpha 0.05 0.04329

binomial_power and actual_alpha are additional diagnostics at the final integer n; they do not change the normal-approximation sample size. Wald and some score designs can have actual alpha above 0.05; for example PASS Example 11 is approximately 0.06532. If the protocol requires actual alpha control, use power_method = “binomial”; the resulting n may differ from the manual’s continuous approximation because the design method is different.

test power_method = “normal” power_method = “binomial” Standard cross-check
exact Supported; infinite-population planning equals score Supported PASS Examples 5 and 12 for discrete rejection; Example 13 for normal power
score Supported Supported SAS 90.2; PASS 2/5/9
score-cc Supported Supported SAS 90.2 ADJZ; PASS 5
wald Supported Supported PASS 5/11
wald-cc Supported Supported PASS 5; no separate manual sample-size case
agresti-coull, jeffreys Not supported Supported No matching PASS one-sample-test procedure found

The testing layer also reproduces PASS Example 5: six fixed n values across five tests, for 30 discrete power values and 30 actual-alpha values. These validate rejection-region implementation and do not change the public sample-size interface.

19.4.4 CMDE Appendix Case 1: Target-Value Method with Clinical Acceptance Criteria

The appendix uses the normal-approximation formula

\[ n=\frac{\left[Z_{1-\alpha/2}\sqrt{P_0(1-P_0)}+ Z_{1-\beta}\sqrt{P_T(1-P_T)}\right]^2}{(P_T-P_0)^2}. \]

The case uses two-sided alpha = 0.05 and power = 1 - beta = 0.80. The acceptable-standard/expected-value pairs are 85%/90% for positive agreement and 90%/94% for negative agreement. Using Z0.975 = 1.96 and Z0.80 = 0.84, the appendix reports 362 positive cases and 388 negative cases, for 750 total; after a 10% dropout allowance, at least 834 participants are enrolled.

sample_size_proportion(test = “score”, power_method = “normal”) performs the same continuous normal approximation. The package uses unrounded normal quantiles and rounds the theoretical result upward; actual alpha and power are then recalculated separately from the discrete binomial rejection region.

Code
cmde_target_value <- data.frame(
  group = c("Positive group", "Negative group"),
  p0 = c(0.85, 0.90),
  p1 = c(0.90, 0.94),
  cmde_n = c(362L, 388L)
)

cmde_target_results <- lapply(
  seq_len(nrow(cmde_target_value)),
  function(i) {
    sample_size_proportion(
      p0 = cmde_target_value$p0[i],
      p1 = cmde_target_value$p1[i],
      alpha = 0.05,
      power = 0.80,
      alternative = "two.sided",
      test = "score",
      power_method = "normal"
    )
  }
)
CMDE target-value method: published and ivdtools normal-approximation results
Standard location Statistic Standard ivdtools
CMDE target-value / Positive group sample size 362 363.00000
CMDE target-value / Positive group actual alpha NA 0.05552
CMDE target-value / Negative group sample size 388 388.00000
CMDE target-value / Negative group actual alpha NA 0.05094
CMDE target-value / Total sample size 750 751.00000
CMDE target-value / Total actual alpha NA NA

The positive-group formula value is 362.7756, so the smallest integer meeting the target power is 363; the appendix writes 362 because it uses approximate quantiles and ordinary rounding. actual_alpha is a diagnostic obtained by placing the continuous-approximation sample size back into the discrete rejection region; it is not part of the CMDE formula’s sample-size search.

19.4.5 CMDE Appendix Case 2: Allowable Error Method Requiring CI Precision

The appendix formula is

\[ n=\frac{Z_{1-\alpha/2}^2P(1-P)}{\Delta^2}. \]

The expected sensitivity is 85%, the expected specificity is 90%, and the allowable error is Delta = 0.05. This corresponds to sample_size_proportion_ci(method = “wald”). The package uses the exact qnorm(0.975) and rounds upward to the smallest integer satisfying the half-width requirement.

Code
cmde_ci_precision <- data.frame(
  group = c("Positive group (sensitivity)", "Negative group (specificity)"),
  p = c(0.85, 0.90),
  cmde_n = c(196L, 138L)
)
cmde_ci_precision$ivdtools_n <- vapply(
  cmde_ci_precision$p,
  function(p) sample_size_proportion_ci(
    p = p, half_width = 0.05, conf.level = 0.95, method = "wald"
  )[["n"]],
  integer(1)
)
CMDE allowable-error method and 10% addition
Standard location Statistic Standard ivdtools
CMDE allowable-error / Positive group (sensitivity) sample size 196 196
CMDE allowable-error / Negative group (specificity) sample size 138 139
CMDE allowable-error / Total sample size 334 335
CMDE allowable-error / 10% addition enrolment 371 373

The package gives 139 for the negative group while the appendix reports 138. The difference has two causes: the appendix substitutes the approximate value 1.96 and reports 138.30 as 138, whereas the package uses the exact quantile and rounds upward. The appendix then reports 371 after adding 10% to 334 cases; if “at least enroll” is handled conservatively, the package’s 335 analyzable cases require ceil(335 / 0.90) = 373. This is a quantile-precision and integer-rounding difference, not a difference in the CI method.

When the expected proportion is close to 100%, the guidance also warns that the normal approximation may be unsuitable. Use sample_size_proportion_ci(method = “clopper-pearson”) or another method for sensitivity analysis, but label the result as a supplementary analysis under a different interval method rather than as a recalculation of the appendix’s Wald formula.