效果量與變異數
統合分析真正合併的東西是「效果量與它的變異數」這一對數字。哪些效果量可以合併、為什麼比值型一定要在 log 尺度上做、變異數怎麼來又怎麼變成權重、零格該怎麼處理,以及換一個效果量為什麼會讓同一批研究看起來異質性完全不同。
統合分析合併的不是「結果」,是一對數字
一篇統合分析看起來像是把好幾篇研究的結論加起來,但實際被送進模型的東西只有兩個:效果量(effect size / effect measure,每篇研究的效應估計)與它的變異數(variance,這個估計有多不精確)。其餘的一切——樣本數、追蹤長度、事件數——都只透過變異數影響結果。
這件事有兩個直接後果,本頁其餘篇幅都在講它們:
- 選哪一個效果量是一個真正的決定,不是格式問題。同一批四格表用 RR、OR 或 RD 表達,合併值不同、異質性也不同。
- 變異數就是權重。研究之間的相對影響力完全由變異數決定,而變異數又由事件數(不是樣本數)主導。
六種常見效果量,性質不一樣
| 效果量 | 資料型態 | 合併時用的尺度 | 什麼時候選它 | 主要陷阱 |
|---|---|---|---|---|
| RR(risk ratio,相對風險) | 二元 | log | 前瞻性設計、事件率可估計時的首選;臨床最好懂 | 事件很常見時會被「上限效應」壓縮;case-control 算不出來 |
| OR(odds ratio,勝算比) | 二元 | log | case-control、需要迴歸校正、事件罕見 | 事件常見時會系統性地誇大,且不能當成 RR 唸 |
| RD(risk difference,風險差) | 二元 | 原尺度 | 要換算 NNT、要表達絕對效益 | 高度依賴基線風險,跨族群合併通常異質性極高 |
| MD(mean difference,平均差) | 連續、同一量表 | 原尺度 | 所有研究用同一個工具、同一個單位 | 換算單位不同就不能直接合併 |
| SMD(standardised mean difference,標準化平均差) | 連續、不同量表 | 原尺度 | 各研究用不同量表測同一個構念 | 分母是各研究自己的 SD,收案越同質 SMD 越大 |
| HR(hazard ratio,風險比) | 存活 | log | 有時間到事件的資料 | 各研究的追蹤長度不同時 HR 的意義本來就不同;比例風險假設要各自成立 |
為什麼比值型一定要在 log 尺度上合併
這不是慣例,是抽樣分布的形狀決定的。
比值有一個結構性的不對稱:往下最多只能到 0,往上沒有上限。「風險減半」是 0.50,「風險加倍」是 2.00,兩者在臨床上是對稱的兩件事,但在數線上一個離 1 只有 0.50、另一個離 1 有 1.00。取對數之後兩者對 0 就對稱了。
實際模擬一次會更清楚:每組 100 人、對照組事件率 0.20、治療組 0.10(真實 RR = 0.50),重複 40000 次試驗。
figures/scripts/B7-01-effect-size.R差別不只是好不好看。用同一批模擬資料,各算一個 95% 的 Wald 信賴區間:
- 直接在原尺度上做(RR ± 1.96 × SE):實際涵蓋真值的比例是 92.9%
- 在 log 尺度上做再取回指數(exp(log RR ± 1.96 × SE)):95.7%
前者比名目上的 95% 低了約 2.1 個百分點,而且它的下界可以掉到 0 以下——一個「負的相對風險」。所以套件的內部運算全部在 log 尺度上進行,escalc() 給你的 yi 是 log RR 不是 RR,只有最後畫圖與報告時才 exp() 回來。
變異數從哪裡來,又怎麼變成權重
以 log RR 為例,變異數的公式是
其中 、 是兩組的事件數,、 是兩組人數。注意主導項是事件數的倒數,不是樣本數的倒數。 一個收了三萬人但只發生二十件事件的研究,精確度接近一個收了兩百人、也發生二十件事件的研究。統合分析裡「大研究」指的永遠是事件多的研究。
固定效應下的權重就是變異數的倒數,正規化成百分比:
用 metadat::dat.bcg 這 13 篇 BCG 疫苗預防結核的對照試驗實際算一次(其中只有一部分是隨機分配,分配方式在異質性那一頁被當成亞組變項):
| 研究 | 疫苗組 | 對照組 | RR | log RR | Var(log RR) | 權重(固定效應) |
|---|---|---|---|---|---|---|
| Aronson, 1948 | 4/123 | 11/139 | 0.411 | -0.889 | 0.3256 | 0.5% |
| Ferguson & Simes, 1949 | 6/306 | 29/303 | 0.205 | -1.585 | 0.1946 | 0.8% |
| Rosenthal et al, 1960 | 3/231 | 11/220 | 0.260 | -1.348 | 0.4154 | 0.4% |
| Hart & Sutherland, 1977 | 62/13598 | 248/12867 | 0.237 | -1.442 | 0.0200 | 8.2% |
| Frimodt-Moller et al, 1973 | 33/5069 | 47/5808 | 0.804 | -0.218 | 0.0512 | 3.2% |
| Stein & Aronson, 1953 | 180/1541 | 372/1451 | 0.456 | -0.786 | 0.0069 | 23.8% |
| Vandiviere et al, 1973 | 8/2545 | 10/629 | 0.198 | -1.621 | 0.2230 | 0.7% |
| TPT Madras, 1980 | 505/88391 | 499/88391 | 1.012 | 0.012 | 0.0040 | 41.4% |
| Coetzee & Berjak, 1968 | 29/7499 | 45/7277 | 0.625 | -0.469 | 0.0564 | 2.9% |
| Rosenthal et al, 1961 | 17/1716 | 65/1665 | 0.254 | -1.371 | 0.0730 | 2.2% |
| Comstock et al, 1974 | 186/50634 | 141/27338 | 0.712 | -0.339 | 0.0124 | 13.2% |
| Comstock & Webster, 1969 | 5/2498 | 3/2341 | 1.562 | 0.446 | 0.5325 | 0.3% |
| Comstock et al, 1976 | 27/16913 | 29/17854 | 0.983 | -0.017 | 0.0714 | 2.3% |
最大的一篇(TPT Madras, 1980,176782 人)光是它一篇就拿走 41.4% 的權重,權重最小的一篇(Comstock & Webster, 1969)只有 0.31%——相差超過一百倍。要注意「權重最小」不等於「人數最少」:後面這一篇收了 4839 人,在這 13 篇裡人數排在中間,比它人數更少的那幾篇權重全都比它高。權重低的原因是它的事件數少,不是它的人數少。這正是森林圖上方塊大小要盯著看的理由,也是下一頁換成隨機效應之後會被大幅改寫的東西。
連續型結果:MD 與 SMD 不能混用
當各研究用同一個工具測同一件事(住院天數、收縮壓、體重),直接合併平均差即可,單位保留,讀者一看就懂。
各研究用不同量表測同一個構念(三種不同的憂鬱量表、四種不同的疼痛評分)時,就得先除掉單位。SMD 的做法是把每篇研究的平均差除以它自己的組內標準差:
用 metadat::dat.normand1999(9 篇中風照護單位的試驗,結果變項是住院天數)同時跑兩種:
| 效果量 | 合併估計 | 95% CI | I² |
|---|---|---|---|
| MD(天) | -15.1 | -32.6 至 2.4 | 99.0% |
| SMD | -0.537 | -1.142 至 0.068 | 95.5% |
兩個都未達統計顯著(信賴區間都跨過 0),但要注意的不是那個,而是 I² 從 99.0% 變成 95.5%。這兩個 I² 不可以直接比較。 I² 是個比例,換效果量的同時也換掉了它的分子與分母:τ² 的單位從「天的平方」變成無單位,各研究的組內變異數也跟著換算方式改變(SMD 的變異數還多含一項估標準差的不確定性)。所以這裡看到的下降不能讀成「研究之間的真實差異變小了」——要回答那個問題,得在同一個尺度上看絕對量(見異質性那一頁)。
零格:一個沒有標準答案的問題
事件很罕見時,某些研究會出現某一格是 0。這時 log RR 或 log OR 是無限大,變異數也是無限大,模型直接卡住。
metadat::dat.nielweise2007 是個乾淨的例子:18 篇比較抗菌塗層中心靜脈導管與一般導管的試驗,結果是導管相關血流感染。其中 6 篇有零格,而這 6 篇裡有 1 篇是兩組都掛零。四種常見處理方式,跑出來是這樣:
| 處理方式 | 納入篇數 | 合併 OR | 95% CI |
|---|---|---|---|
| 0.5 continuity correction (default) | 18 | 0.383 | 0.240–0.610 |
| drop zero-event studies | 12 | 0.439 | 0.268–0.719 |
| Mantel-Haenszel, no correction | 18 | 0.299 | 0.193–0.462 |
| Peto odds ratio | 18 | 0.331 | 0.227–0.482 |
這張表有兩件事一起在變,讀的時候要拆開。 前兩列是隨機效應模型(REML),差別只在零格怎麼處理;後兩列的 Mantel-Haenszel 與 Peto 本身只有固定效應版本,所以它們與前兩列之間同時差了「零格處理」與「模型」兩件事。要做「只差零格處理」的對照,看的是前兩列。
同一批資料,合併 OR 從 0.299 到 0.439,差距超過四成。四種都是文獻上看得到的做法,沒有一種是錯的,但論文如果不寫他們用了哪一種,這個數字就無法被複製。
換一個效果量,異質性就換一張臉
最後一個容易被忽略的後果:效果量的選擇會改變研究之間看起來有多不一致。 同一批 BCG 試驗,三種效果量:
| 效果量 | 合併估計 | 95% CI | I² | τ² | Q |
|---|---|---|---|---|---|
| RR | 0.489 | 0.344–0.696 | 92.2% | 0.3132 | 152.2 |
| OR | 0.475 | 0.330–0.683 | 92.1% | 0.3378 | 163.2 |
| RD | -0.0252 | -0.0464–-0.0039 | 99.9% | 0.0014 | 276.5 |
figures/scripts/B7-01-effect-size.R理由是這樣:這些試驗的基線結核發生率相差好幾個數量級(都市貧民區與鄉村完全不同)。在比值尺度上,基線率被約分掉了,所以只要疫苗的相對保護力接近,各研究就看起來一致。在差值尺度上,基線率留在效果量裡,基線率高的地方風險差自然大得多,於是研究之間差得很開,而且因為 RD 的變異數很小,那個差異在統計上顯得極其確定。
動手跑一次
library(metafor)
library(metadat)
data(dat.bcg, package = "metadat")
# escalc() 是把原始資料轉成 (yi, vi) 的那一步。
# 回傳的 yi 是 log RR,不是 RR —— 合併全程在 log 尺度上做。
rr <- escalc(measure = "RR", ai = tpos, bi = tneg, ci = cpos, di = cneg,
data = dat.bcg, slab = paste(author, year, sep = ", "))
head(rr[, c("yi", "vi")])
# 同一批四格表換成 OR 與 RD,看合併值與異質性怎麼變
or <- escalc(measure = "OR", ai = tpos, bi = tneg, ci = cpos, di = cneg, data = dat.bcg)
rd <- escalc(measure = "RD", ai = tpos, bi = tneg, ci = cpos, di = cneg, data = dat.bcg)
sapply(list(RR = rr, OR = or, RD = rd), function(d) rma(yi, vi, data = d)$I2)
# 權重就是變異數的倒數(固定效應)
fe <- rma(yi, vi, data = rr, method = "FE")
round(weights(fe), 1)
# ── 連續型結果:MD 與 SMD ──
data(dat.normand1999, package = "metadat")
escalc(measure = "MD", m1i = m1i, sd1i = sd1i, n1i = n1i,
m2i = m2i, sd2i = sd2i, n2i = n2i, data = dat.normand1999)
escalc(measure = "SMD", m1i = m1i, sd1i = sd1i, n1i = n1i,
m2i = m2i, sd2i = sd2i, n2i = n2i, data = dat.normand1999) # 已含小樣本校正
# ── 零格:四種處理方式 ──
data(dat.nielweise2007, package = "metadat")
d <- dat.nielweise2007
# (1) 預設:只對有零格的研究加 0.5
rma(escalc("OR", ai = ai, n1i = n1i, ci = ci, n2i = n2i, data = d,
add = 1/2, to = "only0"))
# (2) 不校正 —— 有零格的研究會變成 NA 被丟掉,這正是問題所在
rma(escalc("OR", ai = ai, n1i = n1i, ci = ci, n2i = n2i, data = d, add = 0))
# (3) Mantel-Haenszel:不需要校正
rma.mh(measure = "OR", ai = ai, n1i = n1i, ci = ci, n2i = n2i, data = d)
# (4) Peto:事件罕見、兩組人數接近時的選擇
rma.peto(ai = ai, n1i = n1i, ci = ci, n2i = n2i, data = d)驗證環境:R 4.6.0 + metafor 5.0.1 + metadat 1.6.0
import numpy as np
from statsmodels.stats.meta_analysis import combine_effects
# metadat::dat.bcg 的四格表,13 篇。帶在這裡,這一段才自己跑得動。
tpos = np.array([4, 6, 3, 62, 33, 180, 8, 505, 29, 17, 186, 5, 27])
tneg = np.array([119, 300, 228, 13536, 5036, 1361, 2537, 87886, 7470, 1699,
50448, 2493, 16886])
cpos = np.array([11, 29, 11, 248, 47, 372, 10, 499, 45, 65, 141, 3, 29])
cneg = np.array([128, 274, 209, 12619, 5761, 1079, 619, 87892, 7232, 1600,
27197, 2338, 17825])
# statsmodels 沒有 escalc(),四格表要自己轉成 log RR 與變異數
a, n1, c, n2 = tpos, tpos + tneg, cpos, cpos + cneg # 各研究的四格
log_rr = np.log((a / n1) / (c / n2))
var = 1 / a - 1 / n1 + 1 / c - 1 / n2 # 主導項是事件數
res = combine_effects(log_rr, var, method_re="dl")
print(res.summary_frame()) # 輸出仍是 log 尺度,要自己 exp() 回來
print("pooled RR =", np.exp(res.mean_effect_re))
# 零格要自己處理,否則 log() 會給 -inf
zero = (a == 0) | (c == 0)
a_c, c_c = a.astype(float).copy(), c.astype(float).copy()
a_c[zero] += 0.5; c_c[zero] += 0.5 # 只是最粗糙的一種做法,見上文的三個問題Python 端沒有與 metafor 同等成熟的統合分析套件。statsmodels 只吃「已經算好的效果量與變異數」,四格表轉效果量、零格處理、SMD 的小樣本校正都要自己寫,所以本主題實務上仍以 R 為主。
怎麼讀報表
看到一篇統合分析,這一頁對應 Methods 裡「Statistical analysis」的頭幾句,重點看四件事:
- 合併的是哪一個效果量,有沒有說為什麼。 只寫「以隨機效應模型合併」而不說合併的是 RR 還是 OR 還是 RD,是實質的漏寫。理由該是機轉或臨床上的,不該是「因為異質性比較低」。
- 原始資料是怎麼轉成效果量的。 論文只給合併值、不給各研究的 與事件數,讀者就無法檢查任何一格。附錄裡該有一張逐篇的四格表或效果量表。
- 有沒有零格,怎麼處理的。 罕見事件的統合分析而完全沒提零格,通常代表用了套件預設而不自知。
- OR 有沒有被當成 RR 唸。 摘要寫「風險降低 X%」但表格裡是 OR,是最常見的過度陳述,尤其在事件不罕見的時候。
常見誤用
| 誤用 | 為什麼錯 |
|---|---|
| 把 OR 直接唸成「風險是幾倍」 | 事件不罕見時 OR 系統性地離 1 更遠,會誇大效果 |
| 在原尺度上對比值做常態近似的信賴區間 | 抽樣分布右偏,涵蓋率低於名目值,下界甚至可能為負 |
| 只報相對效果量(RR/OR)不報絕對效果 | 讀者無法判斷臨床上值不值得;RD 與 NNT 才回答這個問題 |
| 把「大研究」理解成人數多的研究 | 權重由變異數決定,而變異數主要由事件數決定 |
| 沒說明就把有零格的研究刪掉 | 單側零事件的研究通常是方向最強的那幾篇,刪掉會把結果拉向虛無 |
| 用了 0.5 連續性校正卻沒寫,也沒做敏感度分析 | 校正量是任意的,不同做法的合併值可能差好幾成 |
| 混用不同量表卻用 MD 合併 | 單位不同的數字直接平均沒有意義,該用 SMD |
| 把 SMD 的大小當成純粹的療效大小 | 分母是各研究自己的族群變異,收案越同質 SMD 越大 |
| 先跑三種效果量再挑異質性最低的報告 | 選擇性呈現;尺度應由機轉決定,不是由 I² 決定 |
| 合併各研究報告的 HR 卻不管追蹤長度差異 | 追蹤期不同時各研究的 HR 本來就在估不同的東西 |
重跑本頁的所有數字
/opt/homebrew/bin/Rscript figures/scripts/B7-01-effect-size.R讀讀看這張圖
答案取自產生本頁圖表的同一份統計輸出,不是另外打上去的。
這 13 篇 BCG 試驗裡,權重最小的一篇只分到 0.31% 的權重。它的權重為什麼這麼低?
看答案與解析
正確答案: 因為它的事件太少——疫苗組只發生 5 件——而 log RR 的變異數主導項是事件數的倒數
它兩組合計收了 4839 人,在這 13 篇裡人數排在中間,比它人數更少的幾篇權重全部比它高——所以權重最小不等於人數最少。權重低的原因是事件少:log RR 的變異數是兩組事件數倒數減去兩組人數倒數,主導項是事件數那兩項,人數只做小幅修正。2498 是它疫苗組的人數;把權重當成人數佔比是同一個誤讀的另一半。統合分析裡的大研究永遠指事件多的研究,不是收案多的研究。
同一批模擬試驗算兩種 95% 的 Wald 信賴區間:一種直接在原尺度上做,一種在 log 尺度上做完再取回指數。兩者實際涵蓋真值的比例說明了什麼?
看答案與解析
正確答案: 原尺度那一種只涵蓋到 92.93%,低於名目值,而且它的下界可以掉到 0 以下
在 log 尺度上做完再取回指數的區間涵蓋 95.74%,接近名目值;直接在原尺度上做的只有 92.93%,短少約兩到三個百分點。差別的來源正是分布形狀:原尺度相對風險的偏態係數 1.01,右邊拖一條長尾,常態近似在這種分布上不成立,而且相對風險減掉將近兩個標準誤可以是負數,那會給出一個負的相對風險。所以偏態不是外觀問題,它就是涵蓋率短少的原因;套件內部全程在 log 尺度上運算,只在畫圖與報告時才取回指數。
這 18 篇導管試驗裡有幾篇出現零格。保留全部 18 篇、對零格加 0.5 校正時合併勝算比是 0.383。改成把有零格的研究直接刪掉之後,合併值會往哪裡走?
看答案與解析
正確答案: 往 1 靠近,移到 0.439,而且只剩 12 篇——被刪掉的正是治療組零事件、方向最強的那幾篇
刪掉有零格的研究之後合併勝算比從 0.383 移到 0.439,方向是往 1 靠。原因是被刪掉的那幾篇多半是治療組一件事件都沒發生的研究,而那正是最強烈指向治療有利的證據。零事件不是沒有資訊,它是很強的資訊。0.299 是 Mantel-Haenszel 給的值,它不需要任何連續性校正、也保留全部 18 篇,反而比每一種校正法都更遠離 1——所以刪掉會讓效果更強這個說法剛好把方向講反了。至於刪不刪都一樣,這張表本身就是反例:同一個隨機效應模型,只差零格怎麼處理,合併值就差了超過一成。
同一批 9 篇中風照護單位試驗,用平均差合併時 I² 是 98.97%,換成標準化平均差之後是 95.49%。這個下降說明了什麼?
看答案與解析
正確答案: 什麼都不能說明。95.49% 與前一個 I² 分屬兩個尺度,τ² 的單位與各研究的變異數都跟著換掉了
I² 是一個比例,分子是 τ²、分母是 τ² 加上典型的研究內變異。換效果量的時候分子與分母一起換:平均差的 τ² 單位是天的平方,標準化平均差的 τ² 沒有單位,各研究的變異數也換了算法,標準化那一側還多含一項估計標準差的不確定性。所以 98.97% 與 95.49% 不是同一把尺上的兩個刻度,比大小沒有意義。要回答研究之間的真實差異有多大,得在同一個尺度上看絕對量。至於 0.07,那是標準化合併值的區間上界;區間跨過 0,正確的講法是未偵測到差異,而不是接近顯著——差一點就顯著這句話本身沒有統計意義。
同一批 BCG 試驗換一個效果量就換一張異質性的臉:相對風險尺度上 I² 是 92.22%,風險差尺度上跳到 99.94%。為什麼?
看答案與解析
正確答案: 因為風險差把基線風險留在效果量裡,而這些試驗的基線發生率差了好幾個數量級,加上風險差的變異數極小,於是 99.94% 的不一致顯得極其確定
在比值尺度上基線風險被約分掉了,所以只要疫苗的相對保護力接近,各研究就看起來一致——相對風險的 92.22% 與勝算比的 92.07% 幾乎重合正是這個緣故,兩者一起偏低不代表它們低估,而代表效果在比值尺度上比較穩定。風險差把基線留著:都市貧民區與鄉村的結核發生率相差好幾個數量級,風險差自然差很開,而多數研究的風險差又緊貼 0、區間極窄,於是 99.94% 反映的是差異相對於研究內誤差很大,不是算錯。決定的順序應該是先問這個介入的機轉在哪個尺度上比較可能跨族群穩定,再接受那個尺度上算出來的異質性;先跑三種再挑 I² 最低的報告是選擇性呈現。
一篇統合分析的表格報的是勝算比 0.475,摘要卻寫成疫苗使結核風險降低約五成。這樣讀對嗎?
看答案與解析
正確答案: 在這批資料上還可以,因為結核是罕見事件,相對風險 0.489 與勝算比幾乎重合——但那是資料的性質,不是勝算比的性質
勝算比在事件罕見時很接近相對風險,事件常見時則系統性地離 1 更遠。這批試驗的結核發生率很低,所以 0.475 與相對風險的 0.489 幾乎重合,摘要那句話在這裡不會造成實質誤導——但它成立的理由是事件罕見,不是勝算比可以當相對風險唸。換一批對照組事件率三成的資料,同一個勝算比對應的相對風險會明顯往 1 靠。風險差 -0.025 則是另一回事:它是絕對量,回答的是每接種一批人可以少幾個結核,與比值誇不誇大無關,拿它來證明勝算比誇大是拿兩把不同的尺互比。合理的做法是相對量與絕對量都報。
用到這個方法的章節
延伸觀看
【Biostatistics Corner】Meta-analysis 基礎篇
Understand What a Meta-Analysis is in Less Than 5 Minutes
An Introduction to Systematic Review and Meta-analysis素材來源與授權
本頁為原創內容