logrank_power()

Power of the log-rank test given the number of observed events.

Usage

Source

logrank_power(
    hazard_ratio,
    n_events,
    *,
    alpha=0.05,
    allocation=0.5,
    sides=2,
)

Computes the statistical power to detect a specified hazard ratio using the log-rank test, given a fixed number of observed events in a two-group survival study. This is the inverse calculation of logrank_n_events: instead of finding the events needed for a target power, this function finds the power achieved with a given number of events.

Power depends on three factors:

  1. Number of events (n_events): More events → higher power
  2. Effect size (hazard_ratio): Larger effects (HR far from 1.0) → higher power
  3. Significance level (alpha): More stringent (smaller alpha) → lower power

Under the proportional hazards assumption, power depends only on the total event count, not the follow-up duration, censoring rate, or sample size separately. This makes it a practical tool for updating power calculations as events accumulate during a trial.

Parameters

hazard_ratio: float

The hazard ratio to detect (group 2 versus group 1). Can be < 1 (group 2 has lower hazard/better survival) or > 1 (group 2 has higher hazard/worse survival). The result is symmetric: HR=0.5 and HR=2.0 give the same power.

n_events: float

Total number of observed events. Must be positive. Power increases with more events; even small trials can have high power if many events occur.

alpha: float = 0.05

Significance level (Type-I error rate, default 0.05). The probability of rejecting the null hypothesis when it’s true. Use alpha=0.05 for two-sided tests with p < 0.05 threshold.

allocation: float = 0.5

Fraction of subjects in one group (default 0.5, a balanced design). For unbalanced designs (e.g., 0.3, 0.7), power decreases; balanced allocation minimizes the total sample size needed for a target power.

sides: int = 2
1 (one-sided) or 2 (two-sided, default). One-sided tests have higher power but test directional hypotheses only. Two-sided tests are standard but require more events for the same power.

Returns

float
Statistical power, a value between 0 and 1. Power of 0.8 (80%) is conventional in many fields; higher power (0.9, 0.95) requires more events.

Details

Schoenfeld’s formula: Under proportional hazards, the power of the log-rank test is

\[ \mathrm{Power} = \Phi\!\left(\sqrt{d \, p \, (1-p)} \; |\ln(\mathrm{HR})| - z_{1-\alpha/\mathrm{sides}}\right), \]

where \(d\) is the number of events, \(p\) is the allocation fraction, and \(\Phi\) is the cumulative normal distribution function. This formula is exact under proportional hazards and asymptotically valid for finite samples.

Practical use: During a running trial, as events accumulate, you can use this function to assess interim power. If interim power is low despite many events, the effect size may be smaller than anticipated.

Examples

A study expects to observe 60 events over its follow-up period. What power does it have to detect a hazard ratio of 0.5 (50% hazard reduction)?

import greenwood as gw

gw.logrank_power(hazard_ratio=0.5, n_events=60)
0.7656462084964221

This power (~0.9) is typical for a well-designed trial. Lower power suggests more events are needed, or the effect size is smaller than assumed. Compute power for different effect sizes to understand study sensitivity:

for hr in [0.5, 0.6, 0.7, 0.8]:
    power = gw.logrank_power(hazard_ratio=hr, n_events=60)
    print(f"HR {hr}: power = {power:.2%}")
HR 0.5: power = 76.56%
HR 0.6: power = 50.74%
HR 0.7: power = 28.14%
HR 0.8: power = 13.66%

Use sides=1 for a one-sided test (higher power, but assumes direction is known):

gw.logrank_power(hazard_ratio=0.5, n_events=60, sides=1)
0.8507589229028262

Use unbalanced allocation if one group is larger. Power decreases with imbalance:

gw.logrank_power(hazard_ratio=0.5, n_events=60, allocation=0.3)
0.691625951433357