Kaplan-Meier curves and the log-rank test
Why survival data cannot be summarised by an average survival time, what each step of a KM curve is computing, which questions the log-rank test answers and which it cannot, and how to read the median line.
What problem this method solves
You follow a group of patients and want to know how long it takes for some event to happen. The difficulty is that when the study ends, some people still have not had the event — they may still be alive, may have moved away, may have withdrawn. Their data are not worthless: a patient followed for 400 days without an event tells you plainly that they made it past 400 days.
An observation where only the lower bound is known is called censoring — more precisely, right-censoring. The whole survival analysis toolkit answers one question: how do you estimate the distribution of event times without throwing censored observations away?
Two common ways of handling them are both systematically biased:
- Counting censored patients as event-free and computing a plain proportion → underestimates risk (the event may have happened after you stopped looking)
- Deleting censored patients altogether → usually overestimates risk (everyone left is someone who had the event)
What the KM estimator computes
The Kaplan-Meier estimator cuts time at every point where an event occurs and asks one small question at each of them: of the people still being followed at this instant, what fraction got past it?
Here is the number of events at time and is the number still in the risk set at that time. The whole curve is these conditional survival probabilities multiplied together.
That explains the two things you notice about the curve’s appearance:
- It is a step function, dropping only when an event occurs. Censoring never makes the curve fall.
- It becomes less reliable towards the right, because keeps shrinking and each step is decided by fewer and fewer people. A dramatic drop at the tail is often three or five patients.
Run it yourself
library(survival)
data(cancer, package = "survival") # lung ships inside the cancer help page
lung$sex_f <- factor(lung$sex, levels = c(1, 2),
labels = c("Male", "Female"))
# status: 1 = censored, 2 = dead
fit <- survfit(Surv(time, status) ~ sex_f, data = lung)
summary(fit)$table # n, events, median survival and its CI per group
survdiff(Surv(time, status) ~ sex_f, data = lung) # log-rank
plot(fit, col = c("#4d6a8c", "#c44d4d"), lwd = 2,
conf.int = TRUE, mark.time = TRUE,
xlab = "Days since enrolment", ylab = "Survival probability")Verified with R 4.6.0 and survival 3.8.6
from lifelines import KaplanMeierFitter
from lifelines.statistics import logrank_test
import statsmodels.api as sm
lung = sm.datasets.get_rdataset("cancer", "survival").data
lung["event"] = (lung["status"] == 2).astype(int) # 2 = dead
male = lung[lung["sex"] == 1]
female = lung[lung["sex"] == 2]
kmf = KaplanMeierFitter()
ax = None
for df, label in [(male, "Male"), (female, "Female")]:
kmf.fit(df["time"], df["event"], label=label)
ax = kmf.plot_survival_function(ax=ax, ci_show=True)
print(label, "median:", kmf.median_survival_time_)
result = logrank_test(male["time"], female["time"],
male["event"], female["event"])
print("log-rank p =", result.p_value)lifelines' KaplanMeierFitter uses the same estimator; the numbers match R.
figures/scripts/B3-02-kaplan-meier.RThe data come from the NCCTG advanced lung cancer trial: 228 patients, of whom 165 had an event and 63 were censored.
| Group | n | Events | Median survival (days) | 95% CI |
|---|---|---|---|---|
| Male | 138 | 112 | 270 | 212–310 |
| Female | 90 | 53 | 426 | 348–550 |
How to read median survival
Median survival is the time at which the curve first drops to 0.5 — not the mean of everyone’s survival times, and not a median computed by forcing censored patients into the calculation. It is the horizontal dashed line in the figure above.
Two frequent misreadings:
- “Median survival 270 days” does not mean these patients live about 270 days. The distribution is usually strongly right-skewed, so the mean sits well above the median.
- When the curve never reaches 0.5, median survival is “not reached” (NR), which does not mean infinite. This is common with short follow-up or a good-prognosis population. NR only licenses the statement “longer than the follow-up period”.
What the log-rank test does and does not answer
The log-rank test compares two curves over their whole length; the null hypothesis is that the two survival functions are identical. Here the result is = 10.33 (df = 1), p = 0.0013.
What it cannot answer is worth remembering better than what it can:
| Question | What log-rank cannot give you |
|---|---|
| By how much? | It returns a p-value and no effect size. For an effect size use the HR from a Cox model, or compare survival at a specified time point |
| Which group is better? | The test carries no direction; direction has to be read off the curves |
| When does the difference appear? | It collapses the entire follow-up into a single statistic |
There is a more fundamental limitation too: the log-rank test has poor power when the curves cross. It is designed to be most sensitive when the hazard ratio is constant across follow-up. If one group does worse early and then overtakes — the shape immunotherapy trials keep producing — the early and late differences cancel each other out, and the p-value can be wildly large even though the two curves are obviously different.
Common misuses
| Misuse | Why it is wrong |
|---|---|
| Using 1 − KM as cumulative incidence when the event has competing risks | Competing events make 1 − KM overestimate cumulative incidence; use the cumulative incidence function (CIF) |
| A KM figure with no numbers-at-risk table | The reader cannot tell how many patients the tail rests on |
| Treating the log-rank p-value as evidence of effect size | It contains no effect size; the size of a p-value and the size of a difference are different things |
| Reporting a single HR when the curves cross | Proportional hazards has already failed, so that HR has no clear interpretation |
| Describing median survival as “how long people live on average” | Survival times are right-skewed, and the two can be far apart |
| Splitting KM curves by a variable only knowable after baseline | Grouping by “responded to treatment”, for instance, manufactures immortal time bias |
| Reading p > 0.05 as “the two groups do not differ in survival” | It only means this study did not detect a difference — and log-rank power is low to begin with when curves cross |
Reproducing every number on this page
/opt/homebrew/bin/Rscript figures/scripts/B3-02-kaplan-meier.RRead the figure
The answer comes from the same statistical output that produced this page's figures, not from a number typed in beside them.
The number-at-risk row under a KM plot shows a number for the female arm at day 400. Which statement is right?
Show the answer and why
Correct answer: That cell reads 26, counting the women who have neither had the event nor been censored yet
Number at risk counts people who have neither had the event nor been censored - the next stretch of curve rests on those 26. 53 is the female arm's event count across all of follow-up, which is what has accumulated rather than who is left; 31 is the male arm's number at risk at that same day, not a combined total. When the right-hand tail looks reassuringly flat, read this row first: where two or three people remain, one event drops the curve a long way, and that drop is not evidence that the risk rose.
Someone counts the downward steps on a KM curve to recover how many events were observed. What is wrong with that?
Show the answer and why
Correct answer: It undercounts, because events sharing a time collapse into one step; there were 165 events
The curve steps down only when an event occurs, and two events on the same day draw a single step - so counting steps gives the number of distinct event times, not the number of events, and the two agree only when no times are tied. 228 is the enrolment total, and reading it as the event count reads "how many were recruited" as "how many things were observed"; the 63 censored patients appear as tick marks rather than steps, so they are not overcounted.
Output prints the male arm's median survival, its lower confidence bound, and the female arm's median side by side. Which is the male median, and why?
Show the answer and why
Correct answer: 270 days - the time at which the curve first drops below a survival probability of one half
Median survival is defined as the first time the curve falls below one half, which is 270 days for men. 212 is the lower bound of that median's 95% confidence interval: it describes how uncertain the estimate is, so using it as the point estimate is not "conservative" but a different quantity altogether; 426 is the female arm's median, read off the wrong row. Output prints all three side by side, so the wrong column and the wrong row both yield an answer that looks entirely plausible.
Chapters that use this method
Watch next
Kaplan-Meier-Curve [Simply Explained]
醫學統計 EP16 存活分析:解讀階梯狀 KM 曲線與風險比率
如何看懂 K-M 存活曲線:以 FLAURA 研究為例
Censoring and Truncation [Survival Analysis 2/8]Sources and licences
This page is original writing