專家已經雙重審閱,尚未人工抽查

時間相依共變項

暴露會變動時,Cox 模型要吃的是 (start, stop] 長表而不是一人一列;tmerge() 怎麼把它建起來、重複事件的 Andersen-Gill 模型為什麼一定要換成穩健變異數、重複測量的檢驗值該用基線值還是當下值、landmark 分析什麼時候是更好的選擇,以及為什麼一個時間相依的 HR 不能拿來做預測。

兩件常被混為一談的事

中文都叫「時間相依」,但它們是完全不同的兩個問題:

時間相依共變項(time-dependent covariate)時間相依係數(time-varying coefficient)
變的是什麼xx 會變:這個人今天的暴露狀態與三個月後不同β\beta 會變:暴露沒變,但它的效果隨時間放大或衰減
模型長相h(tx)=h0(t)exp(βx(t))h(t \mid x) = h_0(t) \exp(\beta \, x(t))h(tx)=h0(t)exp(β(t)x)h(t \mid x) = h_0(t) \exp(\beta(t) \, x)
典型例子換心、開始洗腎、當下的血中膽紅素、當下的用藥手術的早期風險、免疫治療的延遲效果、疫苗保護力衰退
它在解決「基線那一刻的值不能代表整段追蹤」比例風險假設被違反了」
在哪一頁本頁B3-04

(start, stop] 長表:一個人可以有很多列

一般的存活資料一人一列:一個時間、一個事件指標、若干個固定共變項。暴露會變動的時候這個形狀就不夠了,因為「這個人的 xx 是多少」在不同時刻有不同答案。

解法是把每個人切成若干段,每一段內部 xx 是常數。每一段一列,欄位是 (tstart, tstop] 這個左開右閉的區間、該段結束時有沒有發生事件、以及該段適用的共變項值。

兩張並排的時間軸圖。左圖取六位史丹佛換心研究的病人,每人一條橫線;接受移植的人在移植那一刻換色,形成前後兩段,線末的紅點代表死亡。右圖取六位 PBC 病人,每條線被切成很多小段,段與段之間有白色細縫,顏色深淺代表該段期間的血中膽紅素落在分布的哪個三分位。
左:一個只會切換一次的暴露,一個人最多兩列。右:定期回診測到的檢驗值,每次回診就切一段——同一個人可能有十幾列。兩者送進模型的資料結構完全一樣。產圖腳本 figures/scripts/B3-06-time-varying.R

關鍵在於,這個結構沒有把一個人變成很多人。Cox 模型的估計完全發生在「每一個事件時點的風險集合」上(見B3-01):在時間 tt 這一刻,模型只問「此刻還在追蹤的這些人,各自的 xx 現在是多少」。長表的每一列只是回答這個問題的查詢表;一個人在時間 tt 只會有一列涵蓋那一刻,所以他只會被算進去一次。

tmerge():把寬表變成長表

手動切區間很容易出錯(重疊、漏段、事件記在錯的那一列),survival 套件的 tmerge() 就是專門做這件事的。它的心智模型是:先建一個只有追蹤區間與結果的骨架,再一層一層把事件與時間相依變項疊上去。

三個主要動詞:

函數意思用在哪
event(time, status)time 這一刻記一個事件,並把追蹤切到那裡主要結果
tdc(time, value)time 起共變項變成 value(time-dependent covariate)檢驗值、用藥、手術
cumevent(time)累積計數,從 time 起加一「至今發生過幾次」

用史丹佛換心資料(103 位等待名單上的病人,其中 69 位接受了移植)跑一次,會得到 170 列:34 位從未移植的人各一列,67 位移植的人各兩列,剩下 2 位是在第 0 天就移植的——tdc() 在時間零切不出區間,所以他們也只有一列,而且那一列的 transplant 已經是 1。

34 + 2 = 36 位只有一列的人,加上 67 位有兩列的人,正好是 103 位病人;而 67 + 2 = 69 位接受移植。建好長表就把這兩條加法算一次——本頁下面的「常見誤用」表說長表建錯不會報錯、只會靜靜給出錯的答案,這兩位第 0 天移植的病人就是那句話的活教材。

重複測量:基線值還是當下值

pbcseq 是原發性膽汁性膽管炎的追蹤資料:312 位病人、定期回診驗血,中位回診 5 次、最多 16 次,最長追蹤 12.5 年,期間 125 人死亡。轉成長表後有 1807 列。

膽紅素是 PBC 最重要的預後指標,而它會隨疾病進展上升。用基線那一次的值,跟用「當下最近一次測到的值」,跑出來差很多:

共變項只用基線值:HR95% CI用當下值:HR95% CI
log(膽紅素)2.9202.387–3.5724.0043.169–5.058
log(白蛋白)0.0320.008–0.1220.0080.003–0.021
年齡(進入研究時)1.0401.023–1.0571.0471.028–1.067
Concordance(C 統計量)0.8330.910
兩張並排的圖。左圖是 24 位隨機抽出的 PBC 病人的血中膽紅素軌跡(取對數),紅線是追蹤期間死亡的人、多數呈上升趨勢並在末期急遽攀高,淺藍線是最後仍存活的人、大致平坦。右圖是兩條水平的信賴區間,上方是只用基線膽紅素的 HR 2.920,下方是用當下值的 HR 4.004,兩個區間在 3.169 到 3.572 之間有一小段重疊,但當下值的點估計落在基線區間之外。
左:膽紅素不會停在它開始的地方,而且死亡者與存活者的軌跡形狀不同。右:同一批病人、同一個結果,換一個共變項定義,log 膽紅素的 HR 從 2.920 變成 4.004。產圖腳本 figures/scripts/B3-06-time-varying.R

基線膽紅素的 HR 比較小,理由不神祕:基線值是當下值的一個逐漸失效的代理。 追蹤越久,基線那一次抽血離「此刻的病情」越遠,於是關聯被稀釋(regression dilution)。用當下值就把那層稀釋拿掉了。

重複事件:Andersen-Gill 與穩健變異數

有些結果會反覆發生:感染、氣喘發作、心衰竭再住院、癲癇。一人一列的做法只能留下第一次,其餘全部丟掉。

cgd 是慢性肉芽腫病(chronic granulomatous disease)的隨機試驗,比較干擾素 gamma 與安慰劑對嚴重感染的預防效果。128 位孩子,追蹤期間共發生 76 次感染,其中 17 位發生不只一次,最多的一位發生了 7 次。

只取第一次事件,等於丟掉 32 次事件,佔全部的 42.1%。

Andersen-Gill(AG)模型的做法非常樸素:把每個人的追蹤切成「上一次事件之後到下一次事件」的區間,全部丟進同一個 Cox 模型,就當作是不同的觀察。資料結構與上一節的長表完全一樣。

分析方式用到的事件數HR(干擾素 vs 安慰劑)95% CI係數的標準誤
只取第一次事件440.3350.174–0.6450.335
Andersen-Gill,未用穩健變異數760.334(與下列相同)0.201–0.558(過窄)0.261(低估)
Andersen-Gill + 穩健(叢集)變異數760.3340.181–0.6160.312

Landmark 分析:更笨但更容易講清楚的替代方案

時間相依模型不是唯一的解。landmark 分析(landmark analysis)的做法是:挑一個時點 LL只保留活過 LL 的人,依他們在 LL 那一刻的狀態分組,時間從 LL 重新起算。

它為什麼避開了 immortal time bias:分組所需的資訊在 LL 那一刻全部已知,LL 之前的時間對兩組一視同仁地被排除。

用史丹佛換心資料,在第 30 天設 landmark:

兩張並排的圖。左圖是第 30 天 landmark 之後的兩條 Kaplan-Meier 曲線,藍線是尚未移植、綠線是已移植,兩條曲線在整段追蹤中反覆交錯、沒有明顯分開。右圖是三個 landmark 時點(14、30、60 天)各自估出的風險比與信賴區間,點估計從大於 1 移到小於 1,三個區間都跨過 1。
左:79 位活過第 30 天的病人,依當天是否已移植分兩組。右:換一個 landmark 時點,點估計就跟著移動——這不是統計雜訊而已,三個分析各自定義了不同的族群與不同的分組。產圖腳本 figures/scripts/B3-06-time-varying.R
landmark 時點保留人數排除人數該時點已移植HR95% CIp
第 14 天8815211.4410.812–2.5580.212
第 30 天7924350.9150.527–1.5890.752
第 60 天6439450.8080.407–1.6040.542

三個 landmark 的結果都未達統計顯著(信賴區間都跨過 1),與 B3-01 那個時間相依模型的結論一致——一致的是「都未達統計顯著」這一點,不是點估計的方向(B3-01 的 HR 大於 1,這裡三個裡有兩個小於 1)。但點估計從第 14 天的 1.441 移到第 60 天的 0.808,而且保留的人數從 88 掉到 64。

時間相依共變項Landmark 分析
用到的資料全部只有活過 LL 的人,且只用 LL 之後的追蹤
分組定義每一刻都在更新LL 那一刻凍結(LL 之後才轉換的人被誤分類)
統計效率較高較低,LL 越晚丟得越多
對讀者的可解釋性較差(那個 HR 不對應到任何基線分組)較好(就是兩組人的 KM 曲線)
主要風險資料整理錯誤(區間重疊、共變項偷看未來)LL 的選擇;事後挑 LL 就是 data dredging

解讀上的限制:時間相依的 HR 不能拿來預測

這是本頁最重要、也最容易被跳過的一節。

一個時間相依共變項的 HR 是同時期的關聯(contemporaneous association):它說的是「在時間 tt 這一刻,x(t)x(t) 高的人在該刻的風險較高」。它不是一個預測陳述。

理由是:要用這個模型算「某人未來五年的存活機率」,你必須知道他未來五年每一刻的 x(t)x(t)——而那正是你沒有的東西。膽紅素會怎麼變,本身就是未知的;如果你知道,你多半也已經知道結局了。

動手跑一次

library(survival)

# ── 1. 長表長什麼樣 ──
data(cgd, package = "survival")
head(cgd[cgd$id %in% c(1, 2), c("id", "tstart", "tstop", "status", "treat", "enum")])

# ── 2. tmerge():從寬表建長表 ──
# 骨架:一人一列的追蹤區間 + 結果
base <- subset(pbc, id <= 312, select = c(id:sex, stage))
d <- tmerge(base, base, id = id, death = event(time, status == 2))
# 疊上時間相依的檢驗值;tdc() 預設「該時刻之後」才生效
d <- tmerge(d, pbcseq, id = id,
            bili = tdc(day, bili), albumin = tdc(day, albumin))
head(d[d$id == 2, c("id", "tstart", "tstop", "death", "bili", "albumin")])

# ── 3. 基線值 vs 當下值 ──
b <- merge(base, pbcseq[!duplicated(pbcseq$id), c("id", "bili", "albumin")], by = "id")
coxph(Surv(time, status == 2) ~ log(bili) + log(albumin) + age, data = b)
coxph(Surv(tstart, tstop, death) ~ log(bili) + log(albumin) + age, data = d)

# ── 4. 重複事件:Andersen-Gill ──
coxph(Surv(tstart, tstop, status) ~ treat, data = cgd)                  # 標準誤是錯的
coxph(Surv(tstart, tstop, status) ~ treat + cluster(id), data = cgd)    # 穩健變異數
# PWP:依事件次序分層,第 k 次事件有自己的基線風險
coxph(Surv(tstart, tstop, status) ~ treat + strata(enum) + cluster(id), data = cgd)

# ── 5. landmark 分析 ──
data(heart, package = "survival")
L <- 30
lm <- subset(jasa, futime >= L)
lm$g <- factor(ifelse(!is.na(lm$wait.time) & lm$wait.time <= L, "tx", "no"))
coxph(Surv(futime - L, fustat) ~ g, data = lm)
plot(survfit(Surv(futime - L, fustat) ~ g, data = lm))

# ── 6. 檢查資料整理有沒有出錯(一定要做)──
# 區間不可重疊、不可有 tstop <= tstart、每個人的區間要接得起來
with(cgd, tapply(seq_along(id), id, function(i)
  all(tstart[i][-1] == tstop[i][-length(i)]))) |> table()

驗證環境:R 4.6.0 + survival 3.8.6

怎麼讀報表

  1. 暴露是什麼時候決定的。 只要分組依據要等到基線之後才知道(接受手術、有無反應、完成療程、開始某個藥),就去 Methods 找他們用了時間相依變項、landmark、還是什麼都沒做。
  2. 時間相依的共變項是什麼時候測的、怎麼帶進模型。 「最近一次的值」「該區間的平均」「lag 一週的值」是三種不同的定義,結果會不同。都沒寫,就是不可複製。
  3. 重複事件有沒有用穩健變異數。 找 “robust”、“sandwich”、“cluster”、“covs(aggregate)” 這些字。沒有,信賴區間就要自己在心裡放寬約兩成。
  4. 重複事件用的是哪一種模型。 AG、PWP、WLW、frailty 的假設不同,只寫「Cox model for recurrent events」不夠。
  5. landmark 的 LL 是怎麼決定的、丟掉了多少人。 有沒有寫在計畫書裡;被排除的那些人(死於 LL 之前)的特徵有沒有交代。
  6. 有沒有拿時間相依模型去做預測。 出現「本模型的 C 統計量為 X,優於基線模型」而模型含時間相依共變項,那個比較不公平。

常見誤用

誤用為什麼錯
用基線之後才知道的狀態做基線分組Immortal time bias;見 B3-01
把時間相依共變項與時間相依係數搞混前者是暴露會變,後者是比例風險被違反,解法完全不同
長表建好卻不檢查區間重疊、負長度、事件記在錯的一列都不會報錯,只會靜靜給出錯的答案
讓共變項在事件當刻生效等於把結果的資訊寫進暴露;瀕死狀態會被誤讀成強預測因子
重複事件用 AG 卻不加穩健變異數把相關的重複觀察當成獨立資訊,標準誤明顯低估
只取第一次事件卻不說明丟掉的事件往往佔多數,而且丟掉的多半來自最嚴重的病人
沒說明就在 AG/PWP/WLW 之間選一個三者的假設與風險集合定義不同,結果可以差很多
事後才挑 landmark 時點點估計會隨 L 移動,事後挑就是選擇性呈現
landmark 分析不交代被排除了多少人讀者無法判斷剩下的族群還代不代表原本的問題
用時間相依模型算存活曲線或 n 年存活率那需要未來的共變項軌跡,而那正是未知的
用時間相依模型的 C 統計量宣稱預測較準用到了預測時點之後才產生的資訊,比較不公平
把受暴露影響的時間相依變項當一般共變項校正中介兼混淆,標準 Cox 處理不了,要用邊際結構模型

重跑本頁的所有數字

/opt/homebrew/bin/Rscript figures/scripts/B3-06-time-varying.R

讀讀看這張圖

答案取自產生本頁圖表的同一份統計輸出,不是另外打上去的。

Andersen-Gill 模型的兩種變異數估計給出同一個風險比,但標準誤不同。哪一個標準誤該報,為什麼?

看答案與解析

正確答案: 0.312——它不假設同一個人的多次感染彼此獨立

0.312 是穩健標準誤。naive 的 0.261 假設同一個人的多次感染彼此獨立,而那不成立——有些病人就是特別容易反覆感染,他們的第二次事件帶來的新資訊比獨立假設以為的少。忽略這件事會讓信賴區間太窄、p 值太小,而點估計看起來完全一樣,所以從風險比那一欄看不出任何異狀。0.335 是只取第一次事件那個模型:它確實避開了相關性,代價是丟掉一半以上的事件,這是換了一個問題而不是修好了原來那個。

同一份 CGD 資料,如果只取每個人的第一次感染來分析,代價是什麼?

看答案與解析

正確答案: 丟掉 32 個事件,全都是同一個人的第二次以後

76 是全部的事件數,44 是每人只算第一次之後剩下的,差額 32 全是「第二次以後」的感染——接近全部事件的一半,而它們並不是隨機的一半,而是恰好落在最常復發的那些病人身上。所以只看第一次事件不只是樣本變小,而是把「容易反覆發作」這件事整個排除在分析之外。這種分析通常不會在方法段落裡提到丟掉了什麼,讀者只會看到一個比較小的事件數。

landmark 分析會把在 landmark 日之前就發生事件的人排除掉。把 landmark 從第 14 天移到第 30 天,會發生什麼?

看答案與解析

正確答案: 排除 24 人,而被排除的正是最早發生事件的那一群

landmark 設在第 30 天時排除了 24 人,設得更早的版本只排除 15 人——landmark 越晚,被排除的越多。關鍵不在人數而在是誰:被排除的是最早發生事件的人,所以 landmark 之後的族群已經比原本的族群健康。這不是偏誤,是刻意的設計,它換來的是免疫時間偏誤的消除;代價是結論只能對「活到 landmark 日的人」說話,不能直接套回原本的族群。79 是第 30 天版本留下來的人數。

延伸觀看

存活分析(Survival Analysis)第二部分
繁中Ming-Chieh Shih· 18 min繁中,接續第一部分講 Cox 模型與資料結構。它沒有專門的時間相依共變項段落,但把「模型吃的是什麼形狀的資料」講清楚了,是進本頁第二節前的暖身。
【Hands-on】L12 R:Survival Analysis
繁中MeDA(臺大公衛洪弘教授)· 19 min繁中的 R 實作課,示範存活資料在 R 裡怎麼整理與建模。想把本頁的程式碼真的跑起來,先看這支熟悉 survival 套件的操作。
The Statistics of Life and Death | Survival Analysis
ENVery Normal· 15 min英文,從風險函數的定義出發重講一次存活分析。本頁「風險集合在每個事件時點被重新組成」的說法,看完這支會比較有感。

素材來源與授權

本頁為原創內容

回報內容問題

這個站的統計內容由 AI 撰寫、AI 互審,人工只做抽查。你看得出來的錯,我們不一定看得出來。

寫得越具體越修得動,例如哪一句話跟哪本教科書/哪篇論文的說法不一致。

留了才回得了信;不留也會看。

一併送出的資訊

這些是自動帶上的,每一項都可以取消。