Kaplan-Meier 曲線與 log-rank 檢定
為什麼存活分析不能直接算平均存活時間、KM 曲線的每一階在算什麼、log-rank 回答與不回答哪些問題,以及那條中位數線該怎麼讀。
這個方法在解決什麼問題
追蹤一群病人,想知道「多久會發生某個事件」。麻煩在於研究結束時,總有人還沒發生事件——他們可能還活著、可能搬走失聯、可能中途退出。這些人的資料不是沒有價值:一個追蹤了 400 天還沒發生事件的人,明確告訴你「他至少撐過了 400 天」。
把這種「只知道下界」的觀察叫做設限(censoring,更精確說是右設限 right-censoring)。存活分析的整套工具,本質上都是在回答同一個問題:怎麼在不丟掉設限資料的前提下估計事件發生的時間分布。
兩種常見的錯誤處理方式,都會系統性地偏掉:
- 把設限的人當作沒發生事件、直接算比例 → 低估風險(他們可能在你沒看到的時候發生了)
- 把設限的人整個刪掉 → 通常高估風險(留下來的都是已經發生事件的人)
KM 估計在算什麼
Kaplan-Meier 估計把整段時間切在每一個事件發生的時點上,在每個時點問一個很小的問題:在這一刻還在追蹤的人裡面,有多少比例撐過了這一刻?
其中 是時點 發生事件的人數、 是該時點仍在風險集合(at risk)裡的人數。整條曲線就是這些條件存活機率連乘起來。
這解釋了曲線的兩個外觀特徵:
- 它是階梯狀的,只在有事件發生時往下掉一階,設限不會讓曲線下降。
- 越往右越不可靠,因為 越來越小,每一階的跌幅由越來越少的人決定。曲線尾端劇烈的落差常常只是剩下三五個人造成的。
動手跑一次
library(survival)
data(cancer, package = "survival") # lung 放在 cancer 這包資料裡
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 # 各組人數、事件數、中位存活與其信賴區間
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")驗證環境:R 4.6.0 + 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 用的是同一個估計式,數值與 R 一致。
figures/scripts/B3-02-kaplan-meier.R資料是 NCCTG 的晚期肺癌試驗,共 228 人,其中 165 人發生事件、63 人設限。
| 組別 | n | 事件數 | 中位存活(天) | 95% CI |
|---|---|---|---|---|
| Male | 138 | 112 | 270 | 212–310 |
| Female | 90 | 53 | 426 | 348–550 |
中位存活怎麼讀
中位存活時間是曲線第一次降到 0.5 的那個時間點——不是所有人存活時間的平均,也不是把設限的人硬塞進去算出來的中位數。上圖那條水平虛線畫的就是這個位置。
兩個常見誤解:
- 「中位存活 270 天」不代表這群人大約活 270 天。 分布通常嚴重右偏,平均會遠大於中位數。
- 曲線降不到 0.5 時,中位存活「無法估計」(NR, not reached),不是無限大。 這在追蹤期短或預後好的族群很常見。看到 NR 只能說「超過追蹤期」。
log-rank 檢定回答與不回答什麼
log-rank 檢定比較兩條整條曲線,虛無假設是兩組的存活函數完全相同。這個例子的結果是 = 10.33(df = 1),p = 0.0013。
它不回答的問題,比它回答的更值得記住:
| 問題 | log-rank 給不了 |
|---|---|
| 差多少? | 它只給 p 值,沒有效果量。要效果量請用 Cox 模型的 HR,或直接比較特定時點的存活率 |
| 哪一組比較好? | 檢定本身不帶方向,方向要看曲線 |
| 差異在什麼時候出現? | 它把整段時間加總成一個統計量 |
還有一個更根本的限制:log-rank 在兩條曲線交叉時檢定力很差。 它的設計對「整段時間裡風險比固定」的情境最敏感;如果一組前期較差、後期反超(免疫治療試驗常見的形狀),前後段的差異會互相抵消,p 值可能大得離譜,即使兩條曲線明顯不同。
常見誤用
| 誤用 | 為什麼錯 |
|---|---|
| 用 1 − KM 估計累積發生率,而該事件有競爭風險 | 競爭事件會讓 1 − KM 高估累積發生率,應改用累積發生函數(CIF) |
| KM 圖不附風險人數表 | 讀者無法判斷曲線尾端是根據幾個人畫的 |
| 把 log-rank 的 p 值當作效果量的證據 | 它沒有效果量;p 值大小與差異大小是兩回事 |
| 曲線交叉還是報單一 HR | 比例風險假設已經不成立,那個 HR 沒有清楚的解釋 |
| 中位存活寫成「平均活多久」 | 存活時間分布右偏,兩者差距可能很大 |
| 依基線後才知道的變項分組畫 KM | 例如依「有沒有對治療反應」分組,會製造 immortal time bias |
| p > 0.05 就說「兩組存活沒有差異」 | 只能說本研究未偵測到差異;尤其 log-rank 在曲線交叉時檢定力本來就低 |
重跑本頁的所有數字
/opt/homebrew/bin/Rscript figures/scripts/B3-02-kaplan-meier.R讀讀看這張圖
答案取自產生本頁圖表的同一份統計輸出,不是另外打上去的。
KM 圖底下那一列風險人數(number at risk),女性組在第 400 天寫著一個數字。哪一個說法對?
看答案與解析
正確答案: 那一格是 26,算的是女性組還沒發生事件、也還沒被設限的人
風險人數是「到這個時間點為止還沒發生事件、也還沒被設限」的人數,下一段曲線就是由這 26 人撐起來的。53 是女性組整段追蹤的事件數——那是累積發生了什麼,不是還剩下誰;31 是同一時間點男性組的風險人數,不是兩組合計。曲線右端看起來平穩時先讀這一列:只剩兩三個人的區段,一個事件就會讓曲線掉一大階,而那一階不代表風險真的變高了。
有人數了 KM 曲線上往下的階梯,想用階梯數回推觀察到幾個事件。這個做法有什麼問題?
看答案與解析
正確答案: 會少算,因為同一個時間點發生的多個事件會併成一階,實際事件數是 165
曲線只在事件發生時往下掉,而同一天發生的兩個事件只會畫出一階——所以數階梯得到的是「有事件的時間點個數」,不是事件數,兩者只有在沒有任何同時間事件時才相等。228 是收案人數,把它當成事件數是把「收了幾個人」讀成「觀察到幾件事」;63 是被設限的人,他們在圖上是小豎線而不是階梯,所以不會被多算。
報表把男性組的中位存活、它的信賴區間下界,以及女性組的中位數並排印在一起。男性組的中位存活是哪一個,為什麼?
看答案與解析
正確答案: 270 天——曲線第一次跌破存活機率一半的那個時間
中位存活的定義是曲線第一次掉到一半以下的時間,男性組是 270 天。212 是同一個中位數的 95% 信賴區間下界:它描述的是這個估計有多不確定,把它當成點估計不是「比較保守」,而是報了一個不同的量;426 是女性組的中位數,讀錯了列。報表把這三個數字並排印出來,所以讀錯欄或讀錯列都會得到一個看起來完全合理的答案。
用到這個方法的章節
延伸觀看
Kaplan-Meier-Curve [Simply Explained]
醫學統計 EP16 存活分析:解讀階梯狀 KM 曲線與風險比率
如何看懂 K-M 存活曲線:以 FLAURA 研究為例
Censoring and Truncation [Survival Analysis 2/8]素材來源與授權
本頁為原創內容