Claude
Skills
Sign in
Back

bio-clinical-biostatistics-power-sample-size

Included with Lifetime
$97 forever

Computes sample size and power for clinical trials including continuous, binary, and time-to-event endpoints; superiority, non-inferiority, and equivalence designs; FDA 2016 non-inferiority margin selection with M1/M2 framework; Schoenfeld 1981 and Lakatos 1988 for survival; Schuirmann TOST and 80-125% bioequivalence; minimum clinically important difference (MCID) vs δ distinction. Use when justifying trial size in protocol or SAP per CONSORT 2025 item 7.

General

What this skill does


## Version Compatibility

Reference examples tested with: statsmodels 0.14+, scipy 1.12+, numpy 1.26+, pandas 2.1+. R packages cited: pwr, gsDesign (Anderson/Merck), gsDesign2, rpact (Wassmer/Brannath), presize, npsurvSS, nph, simtrial.

Before using code patterns, verify installed versions match. If versions differ:
- Python: `pip show <package>` then `help(module.function)` to check signatures
- R: `packageVersion('<pkg>')` then `?function_name`

If code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.

# Power and Sample Size for Clinical Trials

**"Justify the trial's sample size"** -> Compute the n needed to detect a pre-specified alternative δ with power 1-β at significance α, accounting for endpoint distribution, design (superiority/NI/equivalence), expected dropout, multiplicity, and stratification — and distinguish δ (the effect the trial is powered to detect) from MCID (the clinically meaningful difference).

## The Foundational Distinction -- δ vs MCID

**δ (the alternative effect):** what the trial is *powered to detect*. Usually set above the MCID because sponsors want a strong signal that exceeds noise + design uncertainty.

**MCID (Minimum Clinically Important Difference):** the smallest effect size considered clinically meaningful. Jaeschke-Singer-Guyatt 1989 *Control Clin Trials* 10:407 (anchor-based) and Norman-Sloan-Wyrwich 2003 *Med Care* 41:582 ("the remarkable universality of half a standard deviation") established the modern conventions.

**Confusing the two has produced both:**

- Underpowered trials where sponsor sets δ = MCID and gets a CI straddling zero
- Overgenerous NI margins where sponsor sets M2 = full MCID (NI margin should be a fraction of MCID)

**Postdoc rule of thumb:** for superiority, δ >= 1.5 × MCID; for NI, M2 <= 0.5 × MCID.

## Algorithmic Taxonomy

| Design | Formula / approach | Software | Strength | Fails when |
|--------|--------------------|----------|----------|------------|
| Two-sample t-test, continuous | Cohen's d; n = 2 × (z_α/2 + z_β)² / d² | `pwr::pwr.t.test` (R); `statsmodels.power.tt_ind_solve_power` (Py) | Standard | Heteroscedasticity; non-normal outcomes |
| Two-sample proportions (Fleiss) | Asymptotic normal approximation with/without continuity correction | `power.prop.test` (R) -- uncorrected; `pwr::pwr.2p.test`; statsmodels | Standard | n < 100/arm: continuity correction debate (D'Agostino 1988) |
| Survival (Schoenfeld 1981) | events ≈ 4(z_α/2 + z_β)² / (log HR)² for 1:1 | `gsDesign::nSurv`; `npsurvSS::size_two_arm` | Standard PH-conformant | PH violated (immuno-oncology) under-estimates by 20-50% |
| Survival under non-PH (Lakatos 1988) | Markov chain accommodating time-varying HR, accrual, dropout | `gsDesign::nSurv`; `npsurvSS`; `simtrial` | Handles immuno-oncology delayed effects | Requires explicit specification of HR(t) and accrual |
| MaxCombo SS under NPH | Simulation-based; pre-specify weight family | `nphRCT`; `simtrial` | Robust to NPH pattern | Computationally heavier |
| Non-inferiority fixed-margin | n = (z_α + z_β)² × variance / M² | `pwr::pwr.t2n.test` adapted; `rpact::getSampleSizeMeans` | Pre-discounted M | Constancy assumption violation invisible |
| Non-inferiority synthesis | Pool historical control-vs-placebo + current test-vs-control | `gsDesign::ssTwoArmTest` | More efficient than fixed-margin | Constancy assumption MUST hold exactly |
| Equivalence TOST | Two one-sided tests at α each | `pwr::pwr.t.test` adapted; `presize` | No multiplicity adjustment needed | Wrong question when superiority/NI is intended |
| Group-sequential | Lan-DeMets spending function | `rpact`; `gsDesign` | Interim analyses; early stopping | More complex SAP |
| Sample-size re-estimation (Mehta-Pocock) | Promising-zone conditional power | `rpact::getSampleSizeMeans` with reestimation | Recovers power if interim shows promise | Unblinded SSR scares FDA |
| Cluster-randomised | Adjust for design effect = 1 + (m-1)ICC | `clusterPower`; `pwr` adapted | Standard | ICC misspecification |

**Postdoc reading list:**

- Fleiss JL 1981 *Statistical Methods for Rates and Proportions* (with/without continuity correction tables)
- Schoenfeld DA 1981 *Biometrika* 68:316 (canonical TTE formula)
- Lakatos E 1988 *Biometrics* 44:229 (Markov chain SS for complex survival)
- Schuirmann DJ 1987 *J Pharmacokinet Biopharm* 15:657 (TOST)
- Jaeschke R, Singer J, Guyatt GH 1989 *Control Clin Trials* 10:407 (MCID anchor-based)
- Norman GR, Sloan JA, Wyrwich KW 2003 *Med Care* 41:582 (0.5 SD heuristic)
- Snapinn SM 2000 *Curr Control Trials Cardiovasc Med* 1:19 (NI biocreep)
- Temple R, Ellenberg SS 2000 *Ann Intern Med* 133:455 + 133:464 (NI assay sensitivity; **Ann Intern Med NOT NEJM** — common citation error)
- Hung HMJ, Wang SJ, O'Neill RT 2005 *Biom J* (NI within-trial Type-I not guaranteed)
- Mehta CR, Pocock SJ 2011 *Stat Med* 30:3267 (promising zone)
- Lin RS, Lin J, Roychoudhury S et al 2020 *Stat Biopharm Res* (NPH Working Group)

## Decision Tree by Scenario

| Scenario | Recommended approach | Why |
|----------|---------------------|-----|
| Continuous outcome, two-arm parallel, superiority | Fleiss / Cohen's d formula via `power.t.test` or statsmodels | Standard; cite Fleiss 1981 |
| Binary outcome, n > 100/arm | Uncorrected normal approximation via `power.prop.test`; statsmodels `power_proportions_2indep` | Adequate for n > 100 |
| Binary outcome, n < 100/arm | Fisher exact-based simulation OR Fleiss with continuity correction | Continuity correction debate; cite D'Agostino 1988 if uncorrected |
| Time-to-event with PH | Schoenfeld 1981 via `gsDesign::nSurv` | Standard; pre-specify hazards |
| Time-to-event under expected NPH (immuno-oncology) | Lakatos 1988 OR simulation via `simtrial::simtrial`/`nphRCT` | Schoenfeld under-estimates by 20-50%; cite Lin 2020 |
| Non-inferiority continuous | Fixed-margin with M2 = 0.5 × historical M1 (discounted) | FDA 2016 NI guidance; cite Temple-Ellenberg 2000 |
| Non-inferiority binary | Fixed-margin with Miettinen-Nurminen CI for RD | Cite EMA NI guidance; MN-CI standard |
| Bioequivalence (Cmax/AUC) | TOST with 80-125% margins on geometric mean ratio | FDA 1992 BE guidance; Schuirmann 1987 |
| Cluster-randomised | n × design effect = 1 + (m-1)ICC | Cite Murray 1998 cluster RCT methodology |
| Group-sequential | Lan-DeMets spending function | `rpact` or `gsDesign` |
| Pilot for sample size re-estimation | Blinded SSR (Friede-Kieser 2006) | No Type-I inflation; safer than unblinded |
| Promising-zone reestimation | Mehta-Pocock 2011 with pre-specified increase rule | Recovers power; cite caveat re Jennison-Turnbull 2015 critique |

## Continuous Outcomes -- Two-Sample t-Test

```python
from statsmodels.stats.power import tt_ind_solve_power

# Solve for n per group
n = tt_ind_solve_power(
    effect_size=0.5,  # Cohen's d = (mu1 - mu2) / sigma
    alpha=0.05,
    power=0.80,
    alternative='two-sided'
)
print(f'n per arm = {np.ceil(n):.0f}')

# Solve for power given n
power = tt_ind_solve_power(effect_size=0.5, alpha=0.05, nobs1=100, alternative='two-sided')
```

**Cohen's d benchmarks:** small = 0.2, medium = 0.5, large = 0.8. Choose d to detect based on prior literature or clinically meaningful effect, NOT post-hoc to fit the affordable n.

**Inflate for dropout:** if dropout rate is q, multiply final n by 1/(1-q). For q=0.20, n_total = n/0.80.

**Stratified randomisation efficiency:** if randomisation stratifies on prognostic factors with combined R² = r against outcome, the effective n is n/(1-r²). Senn 2013 *Stat Med* 32:1439 makes the precision argument explicit.

## Binary Outcomes -- The Continuity Correction Debate

```python
from statsmodels.stats.power import NormalIndPower
import math

# Without continuity correction
p1, p2 = 0.30, 0.20
pbar = (p1 + p2) / 2
z_alpha = 1.96  # two-sided alpha=0.05
z_beta = 0.84   # power=0.80
n = ((z_alpha * math.sqr

Related in General