Power Analysis

Sample size and power calculations for clinical trial planning. Supports t-tests, proportions, log-rank, ANOVA, non-inferiority, equivalence, crossover bioequivalence, and cluster randomized trials.

Validates against R packages: pwr, TrialSize, gsDesign, PowerTOST, samplesize.

Sample size and power calculations for clinical trial planning.

Every clinical trial starts with “how many subjects do we need?” This module provides solve-for-any-one-parameter power functions for common trial designs.

Validates against: R packages pwr, TrialSize, gsDesign, PowerTOST, samplesize.

class pystatsbio.power.PowerSolution(result)[source]

Bases: SolutionReprMixin

Public result of a power/sample size calculation.

A Solution wrapping Result[PowerParams] — exposes every computed value as a read-only property plus the uniform .backend_name / .timing / .warnings / .info metadata and a Jupyter _repr_html_ (via SolutionReprMixin).

Parameters:

result (Result[PowerParams])

property backend_name: str
property timing: dict[str, float] | None
property warnings: tuple[str, ...]
property info: dict
property n: int | None
property power: float | None
property effect_size: float | None
property alpha: float
property alternative: str
property method: str
property note: str
summary()[source]

Human-readable summary, similar to R’s print.power.htest.

Return type:

str

class pystatsbio.power.PowerParams(n, power, effect_size, alpha, alternative, method, note='')[source]

Bases: object

Computed payload of a power/sample size calculation.

Exactly one of n, power, or effect_size will have been solved for (the parameter passed as None). The others are the user-supplied inputs.

Parameters:
n: int | None
power: float | None
effect_size: float | None
alpha: float
alternative: str
method: str
note: str = ''
pystatsbio.power.power_t_test(n=None, effect_size=None, alpha=0.05, power=None, alternative='two-sided', test_type='two-sample')[source]

Power calculation for t-tests.

Exactly one of n, effect_size, power must be None — that parameter is solved for given the others.

Parameters:
  • n (int or None) – Sample size per group (two-sample) or total (one-sample/paired).

  • effect_size (float or None) – Cohen’s d effect size.

  • alpha (float) – Significance level (default 0.05).

  • power (float or None) – Desired statistical power (1 - beta).

  • alternative (str) – 'two-sided', 'less', or 'greater'.

  • test_type (str) – 'two-sample', 'one-sample', or 'paired'.

Return type:

PowerSolution

Examples

>>> r = power_t_test(effect_size=0.5, alpha=0.05, power=0.80)
>>> r.n
64
>>> r = power_t_test(n=50, effect_size=0.5, alpha=0.05)
>>> round(r.power, 3)
0.697

Validates against: R pwr::pwr.t.test()

pystatsbio.power.power_paired_t_test(n=None, effect_size=None, alpha=0.05, power=None, alternative='two-sided')[source]

Convenience wrapper: power_t_test with test_type='paired'.

Validates against: R pwr::pwr.t.test(type=’paired’)

Parameters:
Return type:

PowerSolution

pystatsbio.power.power_prop_test(n=None, effect_size=None, alpha=0.05, power=None, alternative='two-sided')[source]

Power calculation for two-proportion z-test (chi-squared test).

Exactly one of n, effect_size, power must be None.

Parameters:
  • n (int or None) – Sample size per group.

  • effect_size (float or None) – Cohen’s h effect size: effect_size = 2 * (arcsin(sqrt(prop1)) - arcsin(sqrt(prop2))).

  • alpha (float) – Significance level (default 0.05).

  • power (float or None) – Desired power.

  • alternative (str) – 'two-sided', 'less', or 'greater'.

Return type:

PowerSolution

Examples

>>> import math
>>> effect_size = 2 * (math.asin(math.sqrt(0.5)) - math.asin(math.sqrt(0.3)))
>>> r = power_prop_test(effect_size=effect_size, alpha=0.05, power=0.80)
>>> r.n  # ~93
93

Validates against: R pwr::pwr.2p.test()

pystatsbio.power.power_fisher_test(n=None, prop1=None, prop2=None, alpha=0.05, power=None, alternative='two-sided')[source]

Power calculation for Fisher’s exact test (normal approximation).

Uses the arcsine (Cohen’s h) normal approximation. For exact power computation via hypergeometric enumeration, a future version will add method='exact'.

Exactly one of n, power must be None (prop1 and prop2 are always required).

Parameters:
  • n (int or None) – Sample size per group.

  • prop1 (float) – Probability in group 1.

  • prop2 (float) – Probability in group 2.

  • alpha (float) – Significance level.

  • power (float or None) – Desired power.

  • alternative (str) – 'two-sided', 'less', or 'greater'.

Returns:

  • PowerSolution

  • Validates against (R pwr::pwr.2p.test() (via Cohen’s h))

Return type:

PowerSolution

pystatsbio.power.power_logrank(n=None, hazard_ratio=None, alpha=0.05, power=None, alternative='two-sided', p_event=1.0, alloc_ratio=1.0, method='schoenfeld')[source]

Power calculation for the log-rank test.

Exactly one of n, hazard_ratio, power must be None.

Parameters:
  • n (int or None) – Total sample size (both groups combined).

  • hazard_ratio (float or None) – Hazard ratio under the alternative hypothesis. Must be != 1.

  • alpha (float) – Significance level (default 0.05).

  • power (float or None) – Desired power.

  • alternative (str) – 'two-sided' or 'one-sided'.

  • p_event (float) – Probability of observing an event (1.0 = no censoring).

  • alloc_ratio (float) – Allocation ratio (n_treatment / n_control). Default 1:1.

  • method (str) – 'schoenfeld', 'freedman', or 'lachin_foulkes'.

Return type:

PowerSolution

Examples

>>> r = power_logrank(hazard_ratio=0.7, alpha=0.05, power=0.80)
>>> r.n  # total N for both groups
186

Validates against: R gsDesign::nSurv(), TrialSize

pystatsbio.power.power_anova_oneway(n=None, effect_size=None, n_groups=2, alpha=0.05, power=None)[source]

Power calculation for one-way ANOVA (balanced design).

Exactly one of n, effect_size, power must be None.

Parameters:
  • n (int or None) – Sample size per group.

  • effect_size (float or None) – Cohen’s f effect size.

  • n_groups (int) – Number of groups (default 2).

  • alpha (float) – Significance level (default 0.05).

  • power (float or None) – Desired power.

Return type:

PowerSolution

Examples

>>> r = power_anova_oneway(effect_size=0.25, n_groups=3, alpha=0.05, power=0.80)
>>> r.n  # per group
52

Validates against: R pwr::pwr.anova.test()

pystatsbio.power.power_anova_factorial(n=None, effect_size=None, n_levels=(2, 2), alpha=0.05, power=None, effect='interaction')[source]

Power calculation for factorial ANOVA.

Exactly one of n, effect_size, power must be None.

Parameters:
  • n (int or None) – Sample size per cell.

  • effect_size (float or None) – Cohen’s f effect size for the target effect.

  • n_levels (tuple of int) – Number of levels for each factor, e.g. (2, 3) for a 2x3 design.

  • alpha (float) – Significance level (default 0.05).

  • power (float or None) – Desired power.

  • effect (str) – Which effect: 'interaction', 'main-a', 'main-b', etc.

Return type:

PowerSolution

Examples

>>> r = power_anova_factorial(effect_size=0.25, n_levels=(2, 3), alpha=0.05, power=0.80)
>>> r.n  # per cell
36

Validates against: R pwr::pwr.f2.test() (via df conversion)

pystatsbio.power.power_noninf_mean(n=None, delta=None, margin=0.0, std=1.0, alpha=0.025, power=None, alternative='one-sided')[source]

Power for non-inferiority test of means.

Tests H0: treatment - control <= -margin (treatment is inferior) vs H1: treatment - control > -margin (treatment is non-inferior).

Exactly one of n, delta, power must be None.

Parameters:
  • n (int or None) – Sample size per group.

  • delta (float or None) – True difference in means (treatment - control).

  • margin (float) – Non-inferiority margin (>= 0).

  • std (float) – Common standard deviation (> 0).

  • alpha (float) – One-sided significance level (default 0.025).

  • power (float or None) – Desired power.

  • alternative (str) – 'one-sided' (standard for NI trials).

Returns:

  • PowerSolution

  • Validates against (R TrialSize::TwoSampleMean.NIS())

Return type:

PowerSolution

pystatsbio.power.power_noninf_prop(n=None, prop1=None, prop2=None, margin=0.0, alpha=0.025, power=None)[source]

Power for non-inferiority test of proportions.

Exactly one of n, power must be None (prop1 and prop2 are always required).

Parameters:
  • n (int or None) – Sample size per group.

  • prop1 (float) – Expected proportion in treatment group.

  • prop2 (float) – Expected proportion in control group.

  • margin (float) – Non-inferiority margin (>= 0).

  • alpha (float) – One-sided significance level (default 0.025).

  • power (float or None) – Desired power.

Returns:

  • PowerSolution

  • Validates against (R TrialSize::TwoSampleProportion.NIS())

Return type:

PowerSolution

pystatsbio.power.power_equiv_mean(n=None, delta=None, margin=0.0, std=1.0, alpha=0.05, power=None)[source]

Power for equivalence test (TOST) of means.

Tests H01: delta <= -margin AND H02: delta >= +margin. Reject both -> equivalence.

Exactly one of n, delta, power must be None.

Parameters:
  • n (int or None) – Sample size per group.

  • delta (float or None) – True difference in means.

  • margin (float) – Equivalence margin (>= 0, symmetric bounds).

  • std (float) – Common standard deviation (> 0).

  • alpha (float) – Significance level for each one-sided test (default 0.05).

  • power (float or None) – Desired power.

Returns:

  • PowerSolution

  • Validates against (R PowerTOST::power.TOST(), TOSTER)

Return type:

PowerSolution

pystatsbio.power.power_superiority_mean(n=None, delta=None, margin=0.0, std=1.0, alpha=0.025, power=None)[source]

Power for superiority test of means.

Tests H0: treatment - control <= margin (no superiority) vs H1: treatment - control > margin (treatment is superior).

Exactly one of n, delta, power must be None.

Parameters:
  • n (int or None) – Sample size per group.

  • delta (float or None) – True difference in means.

  • margin (float) – Superiority margin (>= 0).

  • std (float) – Common standard deviation (> 0).

  • alpha (float) – One-sided significance level (default 0.025).

  • power (float or None) – Desired power.

Returns:

  • PowerSolution

  • Validates against (R TrialSize)

Return type:

PowerSolution

pystatsbio.power.power_crossover_be(n=None, coef_variation=None, theta1=0.8, theta2=1.25, theta0=0.95, alpha=0.05, power=None)[source]

Power for 2x2 crossover bioequivalence study (TOST on log-scale).

Standard average bioequivalence (ABE) design. Exactly one of n, power must be None.

Parameters:
  • n (int or None) – Total number of subjects (both sequences).

  • coef_variation (float) – Within-subject coefficient of variation (e.g., 0.30 for 30% CV). Always required.

  • theta1 (float) – Lower bioequivalence limit (default 0.80).

  • theta2 (float) – Upper bioequivalence limit (default 1.25).

  • theta0 (float) – Assumed true ratio of geometric means (default 0.95).

  • alpha (float) – Per-test significance level for TOST (default 0.05). Each one-sided test is at alpha, giving a 1 - 2*alpha = 90 % CI. Matches R PowerTOST and FDA convention.

  • power (float or None) – Desired power.

Return type:

PowerSolution

Notes

Power is computed with the noncentral-t approximation — PowerTOST’s method="nct" — which sums the two one-sided noncentral-t tail probabilities. This differs from PowerTOST’s default method="exact" (Owen’s Q), which accounts for the correlation between the two TOST statistics, by up to ~1e-2 in power at low power / high CV; the two agree to ~1e-12 when PowerTOST is also run with method="nct". The sample size is unaffected — nct and exact select the same n.

Examples

>>> r = power_crossover_be(coef_variation=0.30, power=0.80)
>>> r.n  # total subjects
36

Validates against: R PowerTOST::power.TOST(method=”nct”), PowerTOST::sampleN.TOST()

pystatsbio.power.power_cluster(n_clusters=None, cluster_size=None, effect_size=None, icc=0.05, alpha=0.05, power=None)[source]

Power calculation for cluster randomized trial (two-arm parallel design).

Adjusts individual-level sample size by the design effect: DEFF = 1 + (m - 1) * ICC where m = cluster_size.

Exactly one of n_clusters, effect_size, power must be None.

Parameters:
  • n_clusters (int or None) – Number of clusters per arm.

  • cluster_size (int) – Average number of subjects per cluster. Always required.

  • effect_size (float or None) – Cohen’s d effect size.

  • icc (float) – Intraclass correlation coefficient (default 0.05).

  • alpha (float) – Significance level (default 0.05).

  • power (float or None) – Desired power.

Return type:

PowerSolution

Examples

>>> r = power_cluster(cluster_size=20, effect_size=0.5, icc=0.05, alpha=0.05, power=0.80)
>>> r.n  # clusters per arm
8

Validates against: R clusterPower, CRTSize