import greenwood as gw
# Compute power to detect HR=0.5 with 60 events
gw.logrank_power(hazard_ratio=0.5, n_events=60)0.7656462084964221
Power of the log-rank test given the number of observed events.
Usage
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:
hazard_ratio): Larger effects (HR far from 1.0) → higher poweralpha): More stringent (smaller alpha) → lower powerUnder 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.
hazard_ratio: floatThe 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: floatTotal 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.05Significance 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.5Fraction 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 floatSchoenfeld’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.
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
# Compute power to detect HR=0.5 with 60 events
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:
# Show how power decreases as the effect size shrinks
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):
# Compute one-sided power for the same scenario
gw.logrank_power(hazard_ratio=0.5, n_events=60, sides=1)0.8507589229028263
Use unbalanced allocation if one group is larger. Power decreases with imbalance: