
在临床研究和流行病学中,我们经常面对一个现实问题:随访时间长短不一,有人中途失访,有人研究结束时还没有发生终点事件。这时候如果简单用“死亡率”或“平均生存时间”来总结数据,很容易产生偏差。Kaplan-Meier 生存曲线(简称KM曲线)正是为解决这类“不完整观察”而生的经典工具。它自1958年由Edward L. Kaplan和Paul Meier提出后,已经成为医学论文中最常见的图形之一。
本文尽量用通俗但准确的方式,把这张“阶梯状”的曲线讲清楚,并给出实际绘图思路。
生存分析的核心是“时间到事件”数据。事件不一定是死亡,也可以是疾病进展、复发、再入院、设备故障,甚至客户流失。关键难点在于删失(censoring):有些研究对象在研究结束时还没发生事件,或者中途失访、退出。如果直接剔除这些人,会损失信息;如果把他们当成“没发生事件”硬算,又会高估生存概率。
Kaplan-Meier方法通过“乘积限估计”巧妙地处理了删失,让我们在不完全数据下仍能得到无偏的生存概率估计。它不需要假设生存时间服从某种特定分布(非参数方法),因此在样本量中等、分布未知时特别实用。理解并正确绘制KM曲线,是科研人员做生存分析、读懂临床论文的基本功。
什么是Kaplan-Meier 生存曲线?
简单来说,Kaplan-Meier曲线描述的是:在任意时间点t,研究对象尚未发生终点事件的概率,即生存函数S(t)。
曲线从时间0、生存概率1.0(100%)出发。每当有事件发生,曲线就向下“掉一格”(阶梯状下降);删失的个体则用小竖线或“+”标记在对应时间点,但不会引起曲线下降。水平段表示这段时间内没有事件发生。
其计算公式本质是条件概率的连乘:
在每个事件发生时间点ti,用“当时仍处于风险中的人数中,未发生事件的比例”去更新之前的累计生存概率。具体来说:

其中di是ti时刻发生事件的人数,ni是ti时刻仍处于风险集中的人数(包括后续会删失的人)。
这种“只在事件发生时更新”的特性,造就了它独特的阶梯外观。曲线右侧往往变得更“平坦”,因为剩余风险集人数变少,估计也更不稳定——这正是读图时需要警惕的地方。
下面是一张典型的KM曲线示例(带95%置信区间和删失标记):

(来源:Wikimedia Commons,CC0公共领域,作者Accountalive)
而接下来这张图,是根据肿瘤反应分层的实体瘤化疗后生存率。该图摘自 Coltman等人的论文。该研究可能是第一个典型的“阶梯式”Kaplan-Meier 生存曲线医学生存表现形式。

从曲线上我们还能直接读出中位生存时间(曲线穿过0.5时对应的时间点),以及特定时间点的生存率(如1年、3年、5年生存率)。
Kaplan-Meier 生存曲线适用场景
KM曲线几乎出现在所有涉及“时间到事件”的临床研究中,尤其是:
1. 肿瘤学:总生存(OS)、无进展生存(PFS)、无病生存(DFS)是最常见的终点。比较不同治疗组、不同分子分型、不同分期的患者生存差异时,几乎必画KM曲线。
2. 心血管疾病与重症医学:再入院时间、主要不良心血管事件(MACE)发生时间、机械通气撤机时间等。
3. 移植与感染病学:移植物存活、病毒清除、抗生素治疗失败时间。
4. 非医学领域:可靠性工程(设备故障时间)、社会学(失业持续时间)、市场营销(客户流失时间)等。
它特别适合以下情况:
- 存在右删失数据;
- 不需要(或不适合)假设参数分布;
- 主要目的是描述和比较组间生存差异(后续可用Log-rank检验)。
需要注意的是,当存在竞争风险(例如研究癌症特异性死亡时,患者先死于其他原因)时,普通KM曲线会高估事件发生率,这时应改用累计发生率函数(Aalen-Johansen估计)。另外,KM曲线本身不直接处理协变量影响,若要同时调整多个因素,通常需要进一步做Cox比例风险回归。
如何画Kaplan-Meier 生存曲线
实际绘图并不复杂,关键是数据准备正确。通常需要三列核心数据:
- 观察时间(Time):从起点到事件或删失的时间;
- 状态(Status/Event):1=发生事件,0=删失;
- 分组变量(可选):用于比较不同组别。
1. 用R绘制(推荐,学术期刊最常见)
R
library(survival)
library(survminer)
# 假设数据框df中有time, status, group三列
fit <- survfit(Surv(time, status) ~ group, data = df)
ggsurvplot(fit,
conf.int = TRUE, # 显示置信区间
risk.table = TRUE, # 显示风险表
pval = TRUE, # 显示Log-rank P值
legend.title = "组别",
xlab = "时间(月)",
ylab = "生存概率",
break.time.by = 6)
2. 用Python(lifelines库)
python
from lifelines import KaplanMeierFitter
import matplotlib.pyplot as plt
kmf = KaplanMeierFitter()
kmf.fit(df['time'], event_observed=df['status'], label='整体')
kmf.plot_survival_function()
plt.xlabel('时间')
plt.ylabel('生存概率')
plt.show()
分组比较时循环拟合不同组别即可。
3. 其他常用软件
- GraphPad Prism:菜单里直接选“Survival”,操作最友好,适合不写代码的研究者。
- SPSS:Analyze → Survival → Kaplan-Meier,勾选相应选项即可输出曲线和表格。
- Stata、SAS也都有成熟命令。
绘图时建议注意几点:
- 始终标注删失点;
- 附上风险表(Number at risk),让读者知道每个时间点还剩多少人;
- 报告中位生存时间及其置信区间;
- 组间比较用Log-rank检验,并给出P值;
- 如果曲线后期风险集很小,可考虑截断显示,并在图注中说明。
最后
Kaplan-Meier曲线看起来只是一张阶梯图,背后却承载着对“不完整数据”的严谨处理。它既直观又强大,是连接原始随访数据与临床结论的重要桥梁。真正用好它,不仅要会画,更要会读——理解每一步下降的含义、删失的影响、以及曲线后期的不确定性。
如果你正在做生存分析,建议从模拟小数据开始手动算一遍生存概率,再对照软件输出,这样印象会深刻很多。希望这篇介绍能帮你在读文献和写论文时更从容一些。
