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

校正後的相對風險:log-binomial 與 modified Poisson

結果不罕見時 OR 會誇大效果,但想直接估校正後的 RR,log-binomial 常常跑不動。這一頁按照真實會發生的順序走一次:收斂、失敗、給起始值、換 modified Poisson,並說明穩健標準誤在這裡修的到底是什麼。

為什麼需要這一頁

邏輯迴歸那一頁的結論是:世代研究與 RCT 有分母, 可以直接算相對風險,這時候還報 OR 等於多要一個假設。那一頁也順手指出, 想要校正後的 RR 可以用 log-binomial 迴歸或 Poisson 配穩健標準誤。

聽起來像是換個 family 參數就好。實際上不是——log-binomial 很常跑不動, 而它跑不動的方式會讓第一次遇到的人以為是自己寫錯。

所以這一頁不按照教科書的順序寫(先講原理、再講方法、最後提一句「有時候不收斂」), 而是按照你在自己的電腦上會遇到的順序寫:先成功一次、再失敗一次、再修好、 再換一條路。中間那次失敗是這一頁的重點之一,不是插曲。

這一頁的例子

同一份 MASS::birthwt:189 位產婦,59 個低出生體重, 盛行率 31.2%。抽菸組 30 / 74, 未抽菸組 29 / 115, 所以未暴露組的風險是 25.2%——這個數字整頁都會用到。

校正的變項是年齡、產婦體重、族裔,跟邏輯迴歸那一頁重疊, 好讓兩邊的估計可以直接對照。

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"))
ADJ <- low ~ smoke_f + age + lwt + race_f

# 第一步:單變項的 log-binomial,直接收斂
fit_uni <- glm(low ~ smoke_f, data = bw, family = binomial(link = "log"))
exp(coef(fit_uni))["smoke_fYes"]

# 第二步:加共變項,預設起始值會失敗
# try() 只是讓下面幾步接得下去;直接呼叫會中止,那正是這一步的重點。
try(glm(ADJ, data = bw, family = binomial(link = "log")))

# 第三步:給起始值。log(0.3) 是「基線風險約三成」,斜率都從 0 開始
fit_lb <- glm(ADJ, data = bw, family = binomial(link = "log"),
              start = c(log(0.3), rep(0, 5)))
exp(cbind(RR = coef(fit_lb), confint.default(fit_lb)))
max(fitted(fit_lb))                 # 收斂後有沒有貼在 1 附近

# 第四步:modified Poisson。三明治估計手寫版(HC0)
fit_p <- glm(ADJ, data = bw, family = poisson)
robust_vcov <- function(model) {
  X <- model.matrix(model)
  r <- model$y - fitted(model)
  bread <- solve(crossprod(X, X * model$weights))   # (X'WX)^-1
  bread %*% crossprod(X, X * r^2) %*% bread         # 夾住 X'diag(r^2)X
}
se <- sqrt(diag(robust_vcov(fit_p)))
cbind(RR = exp(coef(fit_p)),
      lcl = exp(coef(fit_p) - 1.96 * se),
      ucl = exp(coef(fit_p) + 1.96 * se))
summary(fit_p)$coefficients[, 2]     # 對照:Poisson 的裸標準誤

# 第五步:對照 logistic 的 OR
exp(coef(glm(ADJ, data = bw, family = binomial)))["smoke_fYes"]

驗證環境:R 4.6.0 + MASS 7.3.65。sandwich 套件可以一行給出穩健變異數,本站不安裝額外套件,所以下面把三明治估計手寫出來。

第一步:單變項的 log-binomial,直接收斂

模型只換一個地方——連結函數從 logit 換成 log:

logp=β0+β1x1++βkxk\log p = \beta_0 + \beta_1 x_1 + \cdots + \beta_k x_k

於是 exp(β)\exp(\beta) 直接就是相對風險,不再需要任何換算。 只放抽菸一個變項時,R 完全不抗議:

  • RR 1.608 (95% CI 1.06–2.44, p 0.026), 6 次疊代收斂。

第二步:加共變項,預設就失敗

把年齡、產婦體重、族裔加進去,同樣的寫法,R 直接報錯:

語系訊息
英文no valid set of coefficients has been found: please supply starting values
本站產圖機器(zh_TW找不到有效的係數:請提供初始值

兩句是同一個錯誤。 R 會依照系統語系翻譯自己的訊息,所以你在網路上搜尋時 要用英文那句才找得到東西;如果你的環境是中文,看到的會是下面那句。 (順帶一提,這也是為什麼把錯誤訊息貼到 issue 或問人時最好附上英文版。)

錯誤的內容是「找不到有效的起始係數」。原因是 log 連結沒有把預測值限制在 1 以內: logit 的反函數怎麼樣都落在 0 與 1 之間,而 exp(β0+β1x1+)\exp(\beta_0 + \beta_1 x_1 + \cdots) 可以大於 1,那就不是機率了。R 用來猜起始值的預設規則在這裡猜出一組會讓某些人的預測機率超過 1 的係數, 疊代第一步就無處可去。

第三步:給起始值就收斂了

起始值只要落在合法範圍內就行,不必接近答案。一組很好用的通用起始值是: 截距設成「大約的基線風險取對數」,所有斜率設成 0—— 意思是「先假設沒有任何關聯,基線風險大概這麼多」。

這樣設之後,7 次疊代就收斂:

  • 校正後 RR 1.786 (95% CI 1.18–2.71, p 0.006)

第四步:modified Poisson,不必調任何參數

另一條路更省事:明知故犯地用錯的概似。把 0/1 結果丟給 Poisson 迴歸配 log 連結, 點估計仍然是一致的相對風險估計,然後用穩健(三明治)標準誤去修變異數。 這個組合就是文獻上的 modified Poisson(Zou 2004)。

跑起來完全不用調參:

  • 校正後 RR 1.915 (95% CI 1.26–2.92, p 0.002), 5 次疊代,沒有給任何起始值。

穩健標準誤在這裡修的是什麼

三明治估計的形狀是「兩片麵包夾一塊肉」:

V=(XWX)1[Xdiag((yiμ^i)2)X](XWX)1V = (X^\top W X)^{-1} \left[ X^\top \mathrm{diag}\big((y_i - \hat\mu_i)^2\big) X \right] (X^\top W X)^{-1}

麵包是模型假設下的資訊矩陣,肉是實際觀察到的殘差平方。 所以它的作用是:把「變異數等於模型說的那樣」這個假設,換成「變異數等於資料實際表現的那樣」。

第五步:對照 logistic 的 OR

同一份資料、同一組共變項,改用 logistic:

  • 校正後 OR 2.870 (95% CI 1.36–6.05, p 0.006)
森林圖,四個估計值與 95% 信賴區間,橫軸為對數尺度,虛線畫在 1。由上而下:log-binomial 只放抽菸的 RR 1.61(1.06–2.44)、log-binomial 校正後的 RR 1.79(1.18–2.71)、modified Poisson 校正後的 RR 1.91(1.26–2.92),三者為藍色;最下面是 logistic 校正後的 OR 2.87(1.36–6.05),以紅色標示為不同的量,它的點與整段區間都往右偏移、區間也比上面三者長,但仍與它們有重疊。四條橫線整段都落在虛線右側。
三個相對風險與一個勝算比並排。最下面那一列是不同的量,不是同一把尺上比較大的數字——並排只是為了看清楚誤讀它會發生什麼事。產圖腳本 figures/scripts/B2-09-adjusted-rr.R
模型估計值95% CIp
log-binomial,只放抽菸RR1.6081.06–2.440.026
log-binomial,校正後RR1.7861.18–2.710.006
modified Poisson,校正後RR1.9151.26–2.920.002
logistic,校正後OR2.8701.36–6.050.006

在盛行率 31.2% 的這份資料上, OR 比 log-binomial 的 RR 大了約 61% (比 modified Poisson 的 RR 大約 50%)。

「罕見疾病假設」在哪裡開始失效

兩格圖,橫軸都是未暴露組的風險百分比(0 到 50)。左格:把校正後的 OR 2.87 固定成一條水平虛線,紅色曲線是這個 OR 所對應的相對風險,從基線風險 0.5% 時的約 2.84 一路遞減到基線風險 50% 時的約 1.48;一條垂直虛線畫在 10% 處標為 rule of thumb,一個實心點畫在本頁資料的未暴露風險 25.2% 處,對應相對風險約 1.95。右格:同一件事換成「OR 比那個相對風險大了百分之多少」,是一條由左下往右上、通過原點的紅色直線,從約 1% 升到約 94%;水平與垂直虛線交會在 10% 基線風險、落差約 19% 處,實心點標出本頁資料的 25.2% 基線風險對應落差約 47%。
左:同一個 OR 在不同基線風險下對應到完全不同的相對風險。右:兩者的落差隨基線風險嚴格線性上升(是一條直線,不是看起來像直線),10% 那條慣用門檻並不是落差消失的地方,只是落差還算小的地方。產圖腳本 figures/scripts/B2-09-adjusted-rr.R

右邊那條線是嚴格的直線,不是碰巧看起來像。把換算式整理一下就看得出來: 給定 OR 與未暴露組風險 p0p_0

RR=OR(1p0)+ORp0ORRR=1+p0(OR1)\mathrm{RR} = \frac{\mathrm{OR}}{(1 - p_0) + \mathrm{OR} \cdot p_0} \quad\Longrightarrow\quad \frac{\mathrm{OR}}{\mathrm{RR}} = 1 + p_0 (\mathrm{OR} - 1)

也就是說,「OR 比 RR 大多少」與未暴露組風險成正比,比例常數就是 OR1\mathrm{OR} - 1。 所以沒有任何一個基線風險是「安全門檻」——落差是從 0 開始一路線性長上去的, 只是低基線風險那一段長得慢。p00p_0 \to 0 時落差趨近 0,這才是罕見疾病假設真正的內容。

把校正後的 OR 固定住,看它在不同基線風險下對應的 RR:

未暴露組風險這個 OR 對應的 RROR 比它大了
1%2.8182%
5%2.6259%
10%2.41819%
20%2.08937%
本頁資料 25.2%1.95047%

該用哪一個

情況建議
世代研究 / RCT,結果不罕見,要報 RR先試 log-binomial;不收斂就用 modified Poisson
log-binomial 收斂但預測機率貼近 1解在邊界,改用 modified Poisson 或改報風險差
病例對照研究只能報 OR,分母是研究者選的,見病例對照研究
要族群層次的量、要算 NNT報邊際風險差,見邊際估計與 G-computation
結果真的罕見(未暴露組風險遠低於 10%)logistic 的 OR 讀成 RR 誤差有限,但仍應寫明是 OR

常見誤用

誤用為什麼錯
log-binomial 報錯就回頭報 OR,說「RR 估不出來」給起始值或換 modified Poisson 都能估
看到收斂就當作沒事要檢查最大預測機率有沒有貼近 1,那是邊界解的徵兆
用 Poisson 的裸標準誤報二元結果的 RR二元結果的變異數比 Poisson 假設小,區間會偏寬
把「不用穩健標準誤會太窄」套到這一頁那是群集資料的情形,這裡方向相反
把 OR 當成「比較大的 RR」是不同的量,不是同一把尺上的不同刻度
用整體盛行率判斷能不能把 OR 當 RR 讀判準是未暴露組的風險
說「未暴露風險低於 10% 就相等」是近似不是等式,該處落差已有一定幅度
只報點估計說「風險降低 N%」而區間跨過 1應寫「未偵測到差異」並附上區間
拿不同論文的 RR 與 OR 直接比大小量不同、校正的變項也不同
modified Poisson 的點估計拿去當勝算比解讀它估的是相對風險,log 連結給的就是相對風險

延伸

重跑本頁的所有數字

/opt/homebrew/bin/Rscript figures/scripts/B2-09-adjusted-rr.R

讀讀看這張圖

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

同一批人、同一組共變項,logistic 給的校正 odds ratio 是 2.87。可以把它當成校正後的風險比嗎?

看答案與解析

正確答案: 不行,log-binomial 給的校正風險比是 1.79,OR 明顯更遠離一

log-binomial 給的校正風險比是 1.79,而 odds ratio 是 2.87——把 2.87 讀成「風險是 2.87 倍」會把效果誇大將近一半。低出生體重在這份資料裡接近三成,一點都不罕見,而 OR 與 RR 只有在結果罕見時才會接近。1.91 是 modified Poisson 給的校正風險比:它與 log-binomial 估的是同一個量,兩者的小差距來自模型形式而不是定義,所以它也不是「另一個 OR」。

modified Poisson 如果不用 sandwich、直接照 Poisson 的公式算 log 尺度的標準誤,結果會偏哪一邊?

看答案與解析

正確答案: 偏大,naive 是 0.285——Poisson 假設變異數等於平均,用在二元結果上會高估變異

naive 的 0.285 明顯大於 HC0 穩健標準誤的 0.215。Poisson 假設變異數等於平均值,而二元結果的變異數是 p(1-p),一定小於平均,所以 naive 標準誤必然偏大、區間偏寬。這個方向是保守的,但保守不等於正確:區間太寬同樣會讓一個真實的效果被讀成未達顯著,而報表上不會有任何提示。0.218 是加了小樣本修正的 HC1,它與 HC0 只差一點點。

log-binomial 模型用預設起始值直接失敗,手動給起始值才跑得動。哪一個數字最能說明它為什麼勉強收斂得了?

看答案與解析

正確答案: 最大的預測機率是 0.795,仍然在一以下

關鍵是配適出來的最大預測機率 0.795 還沒超過一。log link 不保證預測機率有上界,只要有任何一列被推過一,概似就沒有定義,IRLS 也找不到合法的起點——這個模型正是因此在預設起始值下失敗的。0.405 是抽菸組的粗風險、0.312 是整體盛行率:它們描述觀察到的資料,而收斂與否取決於模型在共變項空間的邊緣推到多高,那可以遠高於任何一個粗風險。

素材來源與授權

本頁為原創內容

回報內容問題

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

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

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

一併送出的資訊

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