預測值與盛行率
PPV 與 NPV 是病人真正在問的問題,但它們不是檢驗的性質——同一個檢驗在不同盛行率下的 PPV 可以差兩個數量級。這一頁把 Bayes 的算式攤開、用人數講一次、示範為什麼罕見病篩檢的陽性多半是偽陽性,並且處理一個課本很少講的但書:敏感度與特異度的「不隨盛行率變」是關於算式的,不是關於世界的。
病人問的不是敏感度
門診裡沒有人會問「這個檢驗的敏感度是多少」。病人問的是:我的報告是陽性,那我到底有沒有病?
這個問題的答案是陽性預測值(positive predictive value, PPV),而它與敏感度是完全不同的量:
兩個條件機率的條件擺反了方向。把它們當成同一件事,是臨床上最常見也最貴的統計誤解——貴在它會讓一個罕見病的篩檢陽性被當成診斷,然後接上一整串侵入性檢查。
Bayes 把兩者接起來
從 2×2 表直接推:
分子是「真陽性的比重」,分母是「所有陽性的比重」。盛行率 prev 出現在算式的兩邊,而敏感度與特異度裡沒有它。 這就是「預測值不是檢驗的性質」這句話的全部內容——不是玄學,是這條式子。
同一個檢驗,七種盛行率
沿用 2×2 表那一頁的設定:pROC::aSAH 的 S100β,切點 0.20 µg/L,
敏感度 63.4%、特異度 80.6%。把這兩個數字釘死,只動盛行率:
| 盛行率(檢驗前機率) | PPV | 陽性中的偽陽性比例 | NPV | 陰性中的偽陰性比例 |
|---|---|---|---|---|
| 0.1% | 0.3% | 99.7% | 99.95% | 0.05% |
| 0.5% | 1.6% | 98.4% | 99.77% | 0.23% |
| 1% | 3.2% | 96.8% | 99.54% | 0.46% |
| 5% | 14.7% | 85.3% | 97.67% | 2.33% |
| 10% | 26.6% | 73.4% | 95.20% | 4.80% |
| 本研究世代 | 65.0% | 35.0% | 79.45% | 20.55% |
| 50% | 76.5% | 23.5% | 68.77% | 31.23% |
figures/scripts/B4-02-ppv-npv.R盛行率 0.1% 時 PPV 是 0.3%,盛行率 50% 時是 76.5%—— 同一個檢驗、同樣的敏感度與特異度,PPV 差了超過兩個數量級。
值得記住的一個量是這個檢驗的打平盛行率:PPV 剛好到一半(也就是陽性報告讓「有病」與「沒病」勢均力敵)所需要的盛行率,這裡是 23.5%。低於這個盛行率,一張陽性報告最可能的解釋仍然是沒病。
用人數講一次
機率會騙眼睛,人數不會。把 10000 個人送進這個檢驗,盛行率 0.1%:
| 真的有病(10 人) | 真的沒病(9990 人) | 合計 | |
|---|---|---|---|
| 檢驗陽性 | 6.3 | 1942.5 | 1948.8 |
| 檢驗陰性 | 3.7 | 8047.5 | 8051.2 |
1948.8 張陽性報告裡,只有大約 6.3 個人真的有病。 其餘全部是偽陽性,PPV = 0.33%。
原因不在檢驗差,而在分母的大小差太多:沒病的人有 9990 位,就算只有 19.4% 被誤判,也會產生 1942.5 個偽陽性;而有病的人總共才 10 位,全部抓到也不過 10 個真陽性。偽陽性的數量由「沒病的人有多少」決定,真陽性的數量由「有病的人有多少」決定,而這兩個數字在罕見病裡差了好幾個數量級。
換一個近乎完美的檢驗也救不了
直覺的下一步是「那就用更好的檢驗」。把敏感度與特異度都拉到 99%,同樣送 10000 個人進來,盛行率一樣是 0.1%:
| 盛行率 | PPV(S100β 這個檢驗) | PPV(99% / 99% 的檢驗) |
|---|---|---|
| 0.1% | 0.3% | 9.0% |
| 0.5% | 1.6% | 33.2% |
| 1% | 3.2% | 50.0% |
| 5% | 14.7% | 83.9% |
| 10% | 26.6% | 91.7% |
| 本研究世代 | 65.0% | 98.3% |
| 50% | 76.5% | 99.0% |
在盛行率 0.1% 時,這個近乎完美的檢驗會產生 9.9 個真陽性與 99.9 個偽陽性, PPV 是 9.0%。十個陽性裡仍然只有一個是真的。 它的打平盛行率是 1.0%——比原本的 23.5% 好很多,但仍然遠高於這個疾病的盛行率。
NPV 的另一面:不要用高 NPV 說服自己
上面那張表裡 NPV 那一欄在低盛行率時看起來像是好消息:在盛行率 0.1% 時,NPV 是 99.95%。它其實幾乎沒有資訊:在盛行率 0.1% 的族群裡,就算完全不做檢驗、看到誰都說「你沒病」,也會有 99.9% 的正確率。 檢驗把它從 99.9% 推到 99.95%,改變非常有限。
判斷「這個檢驗結果到底改變了什麼」的正確工具,是把檢驗前機率與檢驗後機率並排比較,而不是單看檢驗後的絕對值。這件事有一個專門的量:概似比。
一個課本很少講的但書
寫到這裡,最順的收尾方式是:「所以敏感度與特異度是檢驗的性質,PPV 與 NPV 是族群的性質,記住這句話就好。」
這句話對算式成立,對真實世界則是一個要檢查的假設。 把同一份資料依 WFNS 分級(入院時的神經學嚴重度)拆成兩層,兩層的盛行率差很多——而敏感度與特異度也跟著差很多:
| 分層 | 人數 | 有病 n | 沒病 n | 盛行率 | 敏感度(95% CI) | 特異度(95% CI) |
|---|---|---|---|---|---|---|
| WFNS 1-2 | 71 | 14 | 57 | 19.7% | 28.6%(11.7–54.6) | 94.7%(85.6–98.2) |
| WFNS 3-5 | 42 | 27 | 15 | 64.3% | 81.5%(63.3–91.8) | 26.7%(10.9–52.0) |
嚴重度高的那一層,盛行率是 64.3%,敏感度 81.5%; 嚴重度低的那一層,盛行率 19.7%,敏感度只有 28.6%。 兩個敏感度的 95% 信賴區間完全不重疊,所以這個落差不太可能只是抽樣造成的。
動手跑一次
library(pROC)
data(aSAH, package = "pROC")
pos <- aSAH$s100b >= 0.20
dis <- aSAH$outcome == "Poor"
sens <- sum(pos & dis) / sum(dis)
spec <- sum(!pos & !dis) / sum(!dis)
ppv <- function(prev, sens, spec)
sens * prev / (sens * prev + (1 - spec) * (1 - prev))
npv <- function(prev, sens, spec)
spec * (1 - prev) / (spec * (1 - prev) + (1 - sens) * prev)
prev <- c(0.001, 0.005, 0.01, 0.05, 0.10, mean(dis), 0.50)
round(data.frame(prev,
PPV = ppv(prev, sens, spec),
NPV = npv(prev, sens, spec)), 4)
# 打平盛行率:PPV = 0.5 需要多高的檢驗前機率
(1 - spec) / (sens + 1 - spec)
# 用人數講一次
N <- 10000; p <- 0.001
c(TP = N * p * sens, FN = N * p * (1 - sens),
FP = N * (1 - p) * (1 - spec), TN = N * (1 - p) * spec)
# 匯出給下面的 Python 用
write.csv(aSAH, "aSAH.csv", row.names = FALSE)驗證環境:R 4.6.0 + pROC 1.19.0.1。這一節只用到基本運算,不需要額外套件。
import numpy as np
import pandas as pd
d = pd.read_csv("aSAH.csv") # 由本頁上面那段 R 匯出
pos = d["s100b"] >= 0.20
dis = d["outcome"] == "Poor"
sens = (pos & dis).sum() / dis.sum()
spec = (~pos & ~dis).sum() / (~dis).sum()
def ppv(prev, sens, spec):
return sens * prev / (sens * prev + (1 - spec) * (1 - prev))
def npv(prev, sens, spec):
return spec * (1 - prev) / (spec * (1 - prev) + (1 - sens) * prev)
prev = np.array([0.001, 0.005, 0.01, 0.05, 0.10, dis.mean(), 0.50])
print(pd.DataFrame({"prev": prev,
"PPV": ppv(prev, sens, spec),
"NPV": npv(prev, sens, spec)}).round(4))同一條 Bayes 公式,寫法幾乎一樣;重點是把 sens / spec 與 prevalence 當成三個獨立的輸入,不要從同一份資料同時取。
常見誤用
| 誤用 | 為什麼錯 |
|---|---|
| 把敏感度當成「陽性代表有病的機率」 | 條件擺反了;後者是 PPV,還要吃進盛行率 |
| 引用某篇論文的 PPV 套到自己的病人 | PPV 綁定該研究的盛行率,換族群就不成立 |
| 從病例對照式取樣的資料直接算 PPV | 病例與對照的人數是研究者決定的,PPV 沒有意義 |
| 用高 NPV 說明「這個檢驗很會排除疾病」 | 盛行率低時不做檢驗也有很高的 NPV,要看 LR− |
| 認為「檢驗夠準就能解決罕見病篩檢」 | 偽陽性數量由沒病者人數決定,敏感度再高也不變 |
| 把篩檢陽性當成診斷 | 篩檢的作用是提高檢驗後機率到值得做確診檢查,不是終點 |
| 評估篩檢只算抓到幾個病人 | 偽陽性帶來的侵入性檢查與過度診斷屬於成本欄 |
| 假設文獻的敏感度可以無條件搬到別的場域 | 光譜效應:換族群會換掉病情組成,連敏感度都會動 |
| 用整體正確率評估罕見病的檢驗 | 全部判陰性就有很高的正確率 |
| 在同一份資料上挑切點再報 PPV | 樂觀偏誤,見 切點選擇與兩條 ROC 的比較 |
重跑本頁的所有數字
/opt/homebrew/bin/Rscript figures/scripts/B4-02-ppv-npv.R讀讀看這張圖
答案取自產生本頁圖表的同一份統計輸出,不是另外打上去的。
同一個檢驗、同樣的敏感度 0.634 與特異度 0.806,分別用在盛行率 0.1% 與 50% 的兩個族群上。PPV 會怎麼樣?
看答案與解析
正確答案: 在盛行率 0.1% 的族群裡 PPV 只有 0.0033,換到 50% 的族群就跳到七成六——PPV 綁在盛行率上
Bayes 的算式裡盛行率同時出現在分子與分母,而敏感度 0.634 與特異度 0.806 這兩個輸入裡沒有它——這就是「預測值不是檢驗的性質」的全部內容。盛行率 0.1% 時 PPV 是 0.0033,五成時是 0.7653,同一個檢驗差了兩個數量級。0.6500 是本研究世代量到的 PPV,它只在那個世代成立;把它搬到別的族群,等於把研究者收案的比例當成這位病人的檢驗前機率。
盛行率 0.1% 的一萬人送進這個檢驗(敏感度 0.634、特異度 0.806)。表上真陽性大約 6.3 位、偽陽性 1942.5 位。偽陽性為什麼這麼多?
看答案與解析
正確答案: 因為沒病的人有 9990.0 位,就算只有不到兩成被誤判,人數也遠多於全部的病人
偽陽性的數量等於沒病的人數乘上偽陽性率:9990.0 位沒病的人,特異度 0.806 代表將近兩成會被誤判,於是產生 1942.5 個偽陽性。有病的人總共才 10.0 位,全部抓到也只有十個真陽性,實際抓到 6.3 位。被漏掉的病人是偽陰性,落在陰性那一格,不會變成偽陽性——那是把兩個錯誤格搞混。8047.5 是真陰性,它多不多與偽陽性的絕對數沒有關係。這就是罕見病篩檢的結構:兩個分母差了好幾個數量級。
把敏感度與特異度都拉到 99%,在盛行率 0.1% 的族群再跑一次。陽性報告現在可以當成診斷了嗎?
看答案與解析
正確答案: 不行。PPV 只升到 0.0902,十張陽性報告裡仍然只有一張是真的
換一個更好的檢驗只把偽陽性壓小,沒有改變兩個分母的比例,所以 PPV 只升到 0.0902,十張陽性裡仍有九張是假的。打平盛行率 0.0100 是「PPV 剛好到一半」所需要的檢驗前機率,它比這個族群的盛行率高了一個數量級——低於打平盛行率,一張陽性報告最可能的解釋仍然是沒病。0.9900 只是這個檢驗在病例與非病例對半分的族群裡的 PPV,不是它的固有性質。要提高 PPV,最有效的槓桿通常不是換檢驗,是把受檢對象縮小到檢驗前機率較高的人。
在盛行率 0.1% 的族群裡,這個檢驗的 NPV 是 99.95%。這個數字說明它很會排除疾病嗎?
看答案與解析
正確答案: 說明不了。陰性報告裡的偽陰性比例是 0.0005,而在這個族群裡不做檢驗、看到誰都說沒病,答錯的比例也只有千分之一
NPV 的高低主要由這個族群裡本來就沒病的人佔多少決定。盛行率 0.1% 時,完全不做檢驗、對每個人都說沒病,答錯的比例已經只有千分之一;檢驗把陰性報告的偽陰性比例壓到 0.0005,改變非常有限。0.9995 是檢驗後的絕對值,單看它會把「這個族群本來就很健康」誤讀成「這個檢驗很強」。0.6877 確實是同一個檢驗在對半分族群裡的 NPV,但那不是運氣——那就是盛行率在算式裡的位置。判斷檢驗改變了什麼,要把檢驗前與檢驗後並排比較,而那個量是概似比。
把同一批病人依 WFNS 分級拆成兩層,敏感度一層是 0.286、另一層是 0.815。這與「敏感度不隨盛行率變」矛盾嗎?
看答案與解析
正確答案: 不矛盾。兩層是兩群不同的病人:重症那一層的敏感度較高,而它的特異度掉到 0.267,兩個指標一起被病情組成推動
前一頁的示範是把同一批人整批複製,沒有換人,所以敏感度紋風不動——那是算式的性質。這裡換掉的是病人本身:WFNS 較高那一層腦損傷更重、標記濃度也更高,同一個切點抓得住他們,敏感度升到 0.815;同樣的機制讓那一層連結果好的人也偏高,於是更常跨過切點成為偽陽性,特異度掉到 0.267。兩個指標一起被病情組成推動,這叫光譜效應。0.546 是輕症那一層敏感度的區間上界,而重症那一層的下界比它高,兩個區間其實沒有重疊。0.643 是重症那一層的盛行率,它與敏感度一起改變,但不是敏感度改變的原因。
這個檢驗的打平盛行率是 23.5%。臨床上該怎麼用這個數字?
看答案與解析
正確答案: 檢驗前機率低於 0.2347 時,一張陽性報告最可能的解釋仍然是沒病
打平盛行率是 PPV 剛好到一半所需要的檢驗前機率:低於 0.2347,陽性報告讓有病與沒病的勝算仍然偏向沒病那一邊。這不等於陽性報告沒有意義——它確實把機率往上推了,只是還沒推過一半,後面通常還要接確診檢查。0.3500 是本研究世代裡陽性報告中偽陽性的比例,不是門檻。0.0100 是那個近乎完美的檢驗的打平盛行率,把它當成本檢驗的門檻,等於把一個做不到的標準記在錯的檢驗頭上。
用到這個方法的章節
延伸觀看
Sensitivity, Specificity, PPV, NPV
Sensitivity and Specificity Explained Clearly (Biostatistics)
醫學統計 EP17 敏感度、特異度與預測值
實證醫學-診斷與篩檢
Principles of Epidemiology 10. Diagnosis, Tests, and Screening素材來源與授權
本頁為原創內容