進階已經雙重審閱,尚未人工抽查

邏輯迴歸與勝算比

OR 到底是什麼比值、結果不罕見的時候它為什麼一定會誇大、校正後的 OR 與粗 OR 差在哪裡(不只是干擾)、完全分離長什麼樣子怎麼修,以及 EPV 至少 10 這個規矩的來歷與它被質疑的地方。

這個模型在解決什麼問題

臨床研究裡第二大類的結果變項是二元的:有沒有低出生體重、有沒有院內感染、 三十天內有沒有再入院、術後有沒有併發症。

直接用線性迴歸跑 0/1 結果,會壞在兩個地方:預測值跑出 0–1 之外 (負的機率沒有意義),以及殘差的變異數隨預測機率變動(0/1 變項的變異數是 p(1p)p(1-p),本來就不是常數)。

邏輯迴歸(logistic regression)的解法是先換一個尺度。把機率 pp 換成勝算(odds)p/(1p)p/(1-p), 再取對數,範圍就從 [0,1][0,1] 展開成整條實數線,然後在那個尺度上做線性模型:

logp1p=β0+β1x1++βkxk\log \frac{p}{1-p} = \beta_0 + \beta_1 x_1 + \cdots + \beta_k x_k

於是每個 β\beta 的意思是「其他變項固定時,xx 每增加一單位,log-odds 增加 β\beta」, 取指數之後 exp(β)\exp(\beta) 就是勝算比(odds ratio, OR)——這個模型會生出 OR 而不是 RR, 不是誰選的,是模型結構決定的。

這一頁的例子

沿用線性迴歸那一頁的 MASS::birthwt, 但把結果換成二元的 low:新生兒體重是否低於 2500 g。 189 位產婦中有 59 個低出生體重,盛行率 31.2%。

這個盛行率是刻意選的。 它遠遠不算罕見,所以 OR 與 RR 會在同一張表上明顯分家—— 那正是下一節要看的東西。

library(MASS)
data(birthwt, package = "MASS")

bw <- birthwt
bw$race_f  <- factor(bw$race,  levels = 1:3, labels = c("White", "Black", "Other"))
bw$smoke_f <- factor(bw$smoke, levels = 0:1, labels = c("No", "Yes"))
bw$ptl_any <- as.integer(bw$ptl > 0)

# 粗 OR:一個變項
fit_c <- glm(low ~ smoke_f, data = bw, family = binomial)
exp(cbind(OR = coef(fit_c), confint.default(fit_c)))

# 同一張 2x2 的 RR,要自己算——glm 不會給你
tb <- table(bw$smoke_f, bw$low)
(tb[2, 2] / sum(tb[2, ])) / (tb[1, 2] / sum(tb[1, ]))

# 校正後的 OR
fit <- glm(low ~ smoke_f + age + lwt + race_f + ht + ui + ptl_any,
           data = bw, family = binomial)
summary(fit)
exp(cbind(OR = coef(fit), confint.default(fit)))   # Wald,論文格式

# 完全分離長什麼樣子:把 ptl 當成四個 level 的因子
summary(glm(low ~ smoke_f + factor(ptl), data = bw, family = binomial))

驗證環境:R 4.6.0 + MASS 7.3.65。confint() 對 glm 給的是 profile likelihood 區間,論文慣用的 Wald 區間要用 confint.default()。

粗 OR 與 RR:同一張 2×2,兩個答案

先不跑模型,用手算。抽菸與低出生體重的 2×2:

低出生體重正常合計風險勝算
抽菸30447440.5%0.682
未抽菸298611525.2%0.337
  • 相對風險(risk ratio, RR)= 兩個風險相除 = 1.608(1.06–2.44)
  • 勝算比(odds ratio, OR)= 兩個勝算相除 = 2.022(1.08–3.78)

同一張表,同一組人,兩個數字差了將近三成。如果把這個 OR 唸成「風險增加一倍」, 就把效果誇大了。 實際上風險從 25.2% 上升到 40.5%。

曲線圖,橫軸是未暴露組的風險百分比,縱軸是固定 OR 之下對應的相對風險。曲線從左上往右下遞減,在風險很低時貼近 OR = 2.02 的水平虛線,隨著風險上升逐漸遠離。圖上以實心點標出本頁資料的位置:未暴露組風險 25.2%、對應的相對風險 1.61,點旁標著 birthwt: RR = 1.61;另有一條垂直虛線畫在全體低出生體重的比例 31.2% 處。
OR 固定不動,只改變未暴露組的基線風險。結果罕見時 RR 幾乎等於 OR;結果常見時 OR 一定比 RR 遠離 1。本頁的例子落在圖上那個標記點。產圖腳本 figures/scripts/B2-02-logistic.R

道理是代數上的必然,不是巧合。給定 OR 與未暴露組風險 p0p_0,暴露組風險是

p1=ORp0/(1p0)1+ORp0/(1p0)RR=p1p0p_1 = \frac{\mathrm{OR} \cdot p_0 / (1-p_0)}{1 + \mathrm{OR} \cdot p_0 / (1-p_0)} \quad\Longrightarrow\quad \mathrm{RR} = \frac{p_1}{p_0}

把本頁的 OR 固定住,換不同的基線風險:

未暴露組的風險這個 OR 對應的 RR
1%2.001
5%1.924
20%1.679
40%1.435

校正後的 OR

森林圖,八個變項的校正後勝算比與 95% 信賴區間。五個變項的區間不跨過 1:抽菸、族裔為黑人、高血壓病史、曾早產(勝算比都大於 1,橫線整段落在虛線右側),以及產婦體重(勝算比 0.985,橫線整段落在虛線左側,是圖上唯一落在 1 以下的變項)。三個變項的區間跨過 1:年齡、子宮易激性、族裔為其他。
八變項邏輯迴歸的校正後 OR。虛線是 OR = 1。橫線跨過虛線表示本研究未偵測到該變項與低出生體重的關聯。產圖腳本 figures/scripts/B2-02-logistic.R
變項校正後 OR95% CIp
Smoking during pregnancy2.331.048–5.1870.038
Age, per year0.960.894–1.0370.318
Mother's weight, per lb0.990.972–0.9990.034
Race: Black vs White3.361.184–9.5480.023
Race: Other vs White2.230.928–5.3820.073
History of hypertension6.291.585–24.9540.009
Uterine irritability2.040.822–5.0470.125
Previous preterm labour3.391.369–8.4080.008

抽菸的 OR 從粗的 2.022 變成校正後的 2.331。

大部分教科書會說「差別來自干擾因子」。這裡有一半是,但另一半不是,而後者幾乎沒有人講:

其餘幾欄怎麼讀,與線性迴歸相同:連續變項的 OR 一定要寫單位 (年齡的 OR 0.963 是每一歲); 信賴區間跨過 1 的變項要寫成「本研究未偵測到關聯」而不是「無關」; 整體模型檢定(likelihood ratio 37.8,df = 8,p < 0.001) 問的是「全部係數同時為 0 嗎」。

完全分離

有時候 glm() 會給出一個看起來很戲劇化的係數,配一個荒謬的標準誤。這通常不是資料很強, 而是分離(separation):某個變項把結果完美(或幾乎完美)切開了。

這份資料裡就有現成的例子,不必人工製造。把「先前早產次數」ptl 當成四個 level 的因子:

先前早產次數正常體重低出生體重
011841
1816
232
310

最後一列只有 1 個人,而她沒有低出生體重的嬰兒。 這一格是 0,於是「早產 3 次」這個 level 在資料裡與「不會發生低出生體重」完全同義。 模型的反應是:

係數標準誤p
(Intercept)-1.280.23< 0.001
smoke_fYes0.580.340.087
ptl_f11.650.48< 0.001
ptl_f20.520.940.582
ptl_f3-13.86882.740.987

EPV:每個變項至少 10 個事件

邏輯迴歸能放幾個變項,取決於事件數而不是樣本數。 本頁的模型有 59 個事件、8 個參數, EPV(events per variable)= 7.38。

常見誤用

誤用為什麼錯
把 OR 讀成 RR,而結果並不罕見OR 一定比 RR 遠離 1,結果越常見差越多
世代研究 / RCT 有分母卻只報 OR可以直接報 RR 或風險差;報 OR 等於多要一個假設
把「校正後 OR 變大」全部歸給干擾OR 不可塌縮,條件 OR 本來就離 1 更遠
直接比較兩篇論文的 OR 大小校正的變項不同,兩個 OR 定義的對比就不同
拿模型的 OR 去算 NNT 或族群層次的影響需要邊際估計(標準化 / G-computation),不是條件 OR
報連續變項的 OR 卻不寫單位每一歲與每十歲的 OR 完全不同
出現分離仍照樣報那個巨大的 OR該估計值不存在;要合併類別或用 Firth
fitted probabilities numerically 0 or 1 當雜訊略過那通常就是分離的唯一警告
事件數不多卻放進大量共變項過度配適,係數與區間都不可信
先看顯著性再決定放哪些變項選擇後的 p 值與信賴區間失效
用 OR 大小當「重要性」排序尺度取決於變項單位與分布,不是重要性
配對的病例對照用普通邏輯迴歸要用條件式邏輯迴歸,見 病例對照研究
信賴區間跨過 1 還描述效果大小應寫「未偵測到顯著關聯」並附上區間

重跑本頁的所有數字

/opt/homebrew/bin/Rscript figures/scripts/B2-02-logistic.R

讀讀看這張圖

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

這份資料裡低出生體重並不罕見,粗 odds ratio 是 2.02。可以說「抽菸讓風險變成兩倍」嗎?

看答案與解析

正確答案: 不行,風險比其實是 1.61——結果不罕見時 OR 會比 RR 更遠離一

風險比是 1.61,odds ratio 是 2.02,兩者相差不小,因為這個結果一點也不罕見。OR 與 RR 只有在結果很罕見時才會接近,盛行率越高、兩者差距越大,而 OR 永遠偏離一更遠。把 OR 直接讀成「風險是幾倍」會誇大效果,而摘要裡經常就是這樣寫的。3.78 是 OR 的信賴區間上界,它描述的是不確定性,不是另一種效果量。

校正年齡、母親體重與族群之後,抽菸的 odds ratio 從 2.02 變成另一個數字。校正做了什麼?

看答案與解析

正確答案: 變成 2.33——校正可以往任何方向移動估計,這裡是往外

校正後的 OR 是 2.33,比粗估的 2.02 更遠離一。「校正會把數字往一拉」是很常見的直覺,但它不成立:移動的方向取決於共變項跟暴露、跟結果各自的關係,往外、往內、甚至換邊都可能。3.36 是同一個模型裡族群那一列,不是抽菸的。看到校正前後的兩個數字時,該問的是哪些變項進了模型、為什麼,而不是預期它往哪邊走。

抽菸組 74 人中有 30 人生下低出生體重的嬰兒。抽菸組的風險是多少?

看答案與解析

正確答案: 0.405——分母是同組的全部人數

風險的分母是全部的人,所以是 0.405。0.682 是同一組的 odds:分母只有沒發生事件的人,所以它永遠比風險大。事件不罕見時這兩個數字差很多,而 logistic regression 直接給你的是 odds 那一邊——這就是為什麼從 logistic 模型講「風險」之前必須先換算。0.252 是不抽菸組的風險,讀錯了列。

延伸觀看

StatQuest: Logistic Regression
ENStatQuest with Josh Starmer· 9 min九分鐘建立直覺:為什麼要把機率換成 log-odds、那條 S 形曲線從哪來。讀本頁「這個模型在解決什麼問題」那一節前先看。
Logistic Regression Details Pt1: Coefficients
ENStatQuest with Josh Starmer· 19 min專講「係數怎麼變成 OR」,正好是本頁第四、五節在讀的那幾欄。
醫學統計 EP14 羅吉斯迴歸
繁中EDMAN MURMURS· 13 min繁中、臨床醫師視角的完整一集,術語的中文說法在這裡有對照。
醫學統計 EP15 RR vs OR
繁中EDMAN MURMURS· 11 min繁中唯一正面處理 RR 與 OR 差異的一集,對應本頁「粗 OR 與 RR」那一節。
【Hands-on】L9 R: Logistic Regression
繁中MeDA School(洪弘)· 45 min繁中、研究所級的 R 實作,想把整個流程跟著敲一遍再看這支。

素材來源與授權

本頁為原創內容

回報內容問題

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

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

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

一併送出的資訊

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