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

ROC 曲線與 AUC

ROC 是所有切點的軌跡,AUC 有一個乾淨的機率解釋(隨機取一位有病與一位沒病者,前者分數較高的機率)——這一頁把那個解釋用配對數數驗證一次。也講 AUC 看不見的兩件事:它完全不衡量校準,而且它照定義就不受盛行率影響,所以在極不平衡的資料上它不會惡化,會惡化的是 precision-recall。

一條曲線就是一整排 2×2 表

2×2 表那一頁的每一組敏感度/特異度,都綁在一個特定的切點上。換一個切點,四個格子全部重排。

把切點從最低掃到最高,每一個位置都算一次敏感度與 1 − 特異度,然後把這些點連起來——那條線就是 ROC 曲線(receiver operating characteristic curve,名字來自二戰的雷達訊號研究)。

用同一份 pROC::aSAH 的 S100β 看五個切點:

切點(µg/L)TP / FP / FN / TN敏感度(縱軸)1 − 特異度(橫軸)
0.0540 / 67 / 1 / 50.9760.931
0.1034 / 44 / 7 / 280.8290.611
0.2026 / 14 / 15 / 580.6340.194
0.4017 / 8 / 24 / 640.4150.111
0.609 / 0 / 32 / 720.2200.000

切點愈低,愈容易判成陽性,敏感度愈高、特異度愈低——曲線上的每一點都是一組取捨,沒有哪一點天生比較對。哪一點才對,取決於偽陽性與偽陰性各自的代價,那是下一頁的題目。

ROC 曲線圖,橫軸是 1 減特異度、縱軸是敏感度,兩條階梯狀曲線分別代表 S100B 與 NDKA,對角虛線代表隨機猜測。S100B 的曲線整體較靠左上。
同一批病人的兩個生物標記。對角線是完全沒有資訊的檢驗(敏感度提高多少、偽陽性率就跟著提高多少)。曲線愈靠左上角,代表在同樣的偽陽性率下抓到愈多病人。產圖腳本 figures/scripts/B4-04-roc-auc.R

AUC:曲線底下的面積,以及它真正的意思

AUC(area under the curve,也寫作 C-statistic 或 concordance index)把整條曲線壓成一個數字:

標記AUC95% CI(DeLong)
S100β0.7310.630–0.833
NDKA0.6120.501–0.723

面積本身不好解釋,但它等於一個非常具體的機率:

隨機抽一位結果差的病人與一位結果好的病人,前者的標記值比後者高的機率(平手算一半)。

這不是類比,是恆等式。可以直接數給自己看:41 位結果差的病人與 72 位結果好的病人, 兩兩配對共 2952 對。其中 2124 對是結果差的那位 S100β 較高,70 對平手。 把平手算一半:(2124 + 70 ÷ 2)÷ 2952 = 0.7314, 與 pROC 算出來的 AUC 0.7314 完全相同(產圖腳本裡有一行斷言在守這件事,兩者不符就不會產出檔案)。

同一個恆等式也解釋了幾件常被分開記憶的事:

  • AUC 只看排序,不看數值。 把所有標記值取對數、平方、乘十,AUC 完全不動——只要順序沒變。
  • AUC 等價於 Mann-Whitney U 檢定的統計量(除以樣本數乘積之後)。所以「AUC 顯著大於 0.5」與「兩組的分布位置有差異」是同一個檢定。
  • AUC 0.5 是完全沒有排序能力,1 是完美排序。AUC 不會因為你收了更多沒病的人而變差,這件事在後面談 AUC 碰上不平衡世代那一節會變成一個陷阱。

AUC 看不見的第一件事:校準

AUC 衡量的是鑑別力(discrimination):模型能不能把有病的排在沒病的前面。它完全不管校準(calibration):模型說「這個人有 20% 的機率有病」時,這種人裡是不是真的有 20% 有病。

證明只要一行:把一組預測機率在 log-odds 尺度上整體平移一個常數。排序完全沒變,所以 AUC 完全不會動;但每個人的預測機率都錯了。

用 aSAH 配一個邏輯迴歸(結果差 ~ S100β + NDKA + 年齡),然後把預測值往下平移 1.50 個 log-odds:

原始預測平移後的預測
AUC0.77510.7751
Brier score(愈小愈好)0.1740.222
平均預測機率36.3%15.9%
實際發生率36.3%36.3%
校準截距(0 才是對的)0.001.50
左圖是兩條完全重疊的 ROC 曲線,右圖是校準圖,橫軸平均預測機率、縱軸實際發生比例;原始預測的點貼近對角線,平移後的點整組往左偏離對角線。
左:兩組預測的 ROC 曲線完全重合,AUC 到小數點後四位都一樣。右:同樣這兩組預測的校準圖,平移後那一組整體低估了風險。AUC 對右邊這件事完全沒有反應。(本資料只有百餘人,校準圖分成四組後每組僅二十餘人,點會抖動——這是樣本小的正常表現。)產圖腳本 figures/scripts/B4-04-roc-auc.R

平移後的模型平均預測 15.9%,而實際發生率是 36.3%——系統性地低估了風險,Brier score 從 0.174 惡化到 0.222,AUC 卻毫無反應。

Brier score 在這裡只是佐證,它本身單看沒有尺度——它同時混了鑑別力與校準, 所以一個數值要有意義得跟基準比。而有設限的存活資料直接這樣算是錯的。 完整的說明,以及它與重分類指標(NRI/IDI)的關係,見 Brier score、NRI 與 IDI

AUC 看不見的第二件事:這群人裡有多少病人

常見的說法是「類別極不平衡時 AUC 會誤導,應該改看 PR 曲線」。這句話的結論可以用,但理由通常被講錯,值得看清楚機制。

把 aSAH 的對照組整批複製 20 份(病人維持原來那些),盛行率從 36.3% 降到 2.8%:

原始資料對照組複製後
總人數1131481
盛行率36.3%2.8%
AUC0.73140.7314
PR 曲線下的平均精確度0.6860.343
(沒有資訊的基準線)0.3630.028
左圖兩條 ROC 曲線完全重合;右圖兩條 precision-recall 曲線分開很遠,盛行率低的那條整條下移,兩條水平虛線分別是兩個盛行率的基準線。
左:ROC 曲線一模一樣,AUC 到小數點後四位都相同。右:同一批分數的 precision-recall 曲線,盛行率低的那一條整條掉下去,因為 precision 就是 PPV,而 PPV 跟著盛行率走。產圖腳本 figures/scripts/B4-04-roc-auc.R

動手跑一次

library(pROC)
data(aSAH, package = "pROC")

r1 <- roc(aSAH$outcome, aSAH$s100b,
          levels = c("Good", "Poor"), direction = "<", quiet = TRUE)
r2 <- roc(aSAH$outcome, aSAH$ndka,
          levels = c("Good", "Poor"), direction = "<", quiet = TRUE)

auc(r1); ci.auc(r1, method = "delong")
plot(r1); plot(r2, add = TRUE, col = "steelblue")

# 曲線上任何一點的 2x2
coords(r1, x = c(0.05, 0.10, 0.20, 0.40, 0.60), input = "threshold",
       ret = c("threshold", "sensitivity", "specificity", "tp", "fp", "fn", "tn"),
       transpose = FALSE)

# AUC 的機率解釋,自己數一次
case <- aSAH$s100b[aSAH$outcome == "Poor"]
ctrl <- aSAH$s100b[aSAH$outcome == "Good"]
(sum(outer(case, ctrl, ">")) + 0.5 * sum(outer(case, ctrl, "=="))) /
  (length(case) * length(ctrl))

# 排序不變 => AUC 不變
auc(roc(aSAH$outcome, log(aSAH$s100b), levels = c("Good", "Poor"),
        direction = "<", quiet = TRUE))

# 匯出給下面的 Python 用
write.csv(aSAH, "aSAH.csv", row.names = FALSE)

驗證環境:R 4.6.0 + pROC 1.19.0.1。pROC 的 roc() 建議明確寫出 levels 與 direction,否則它會自己猜方向並印出訊息。

讀論文裡的 AUC 時要問的四件事

  1. 有沒有信賴區間? 本頁 S100β 的 AUC 是 0.731,區間 0.630–0.833,寬度超過 0.2。診斷研究的樣本常常不大,只報點估計會讓讀者高估精確度。
  2. 這個 AUC 是在哪一批資料上算的? 用來配模型的同一批資料算出來的 AUC 是樂觀的;要看內部驗證(bootstrap 或交叉驗證)修正後的值,或外部驗證的值。樂觀有多大,下一頁會用同一份資料量給你看。
  3. 有沒有報校準? 只有 AUC 的預測模型論文,等於只回答了一半。
  4. AUC 提高了多少才有臨床意義? 在既有模型上加一個新標記,AUC 常常只升千分之幾——這種幅度是否值得多抽一管血、多花一筆錢,AUC 本身回答不了。要回答它需要決策分析的工具(net benefit、decision curve analysis),或直接看在臨床決策門檻附近有多少人被重新分類。

常見誤用

誤用為什麼錯
用 AUC 當「這個模型準不準」的唯一答案AUC 只衡量鑑別力,完全不看校準
直接比較兩篇論文的 AUC 大小族群、盛行率、病情組成不同,AUC 不可跨研究直接比
看到兩個 AUC 差很多就宣稱某個標記較好同一批病人的兩條曲線是相關的,要做配對 DeLong 檢定
報 AUC 不報信賴區間樣本不大時區間很寬,點估計會誤導
用訓練模型的同一批資料報 AUC 卻不說樂觀偏誤,要用內部或外部驗證修正
認為 AUC 在不平衡資料上會下降ROC 的兩軸都在疾病狀態內部算,照定義不受盛行率影響
跨盛行率直接比較 PR 曲線的面積PR 的基準線就是盛行率,要跟基準線一起讀
只用 AUC 決定要不要加一個新的生物標記AUC 的微小提升與臨床價值沒有固定關係,需要決策分析
從 ROC 上挑最好看的一點就當成建議切點該點是從同一份資料選出來的,而且「最好看」本身就是一個代價假設——最後是那份資料的盛行率替你做了這個假設
把 AUC 說成「診斷正確率」它是排序正確的機率,不是任何一個切點的正確率
用 covid_testing 的 Ct 值畫 ROC 教學Ct 值來自它要被驗證的那個 PCR 結果,是循環論證

重跑本頁的所有數字

/opt/homebrew/bin/Rscript figures/scripts/B4-04-roc-auc.R

讀讀看這張圖

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

本頁這個生物標記的 AUC 是 0.731。這個數字的意思是什麼?

看答案與解析

正確答案: 隨機抽一位結果差與一位結果好的病人,前者的標記值較高的機率是 0.731,平手算一半,本頁數過 2952 對

AUC 等於一個很具體的機率:隨機抽一位結果差與一位結果好的病人,前者的標記值較高的機率,平手算一半。這不是類比而是恆等式,本頁用 2952 對配對數過一次。所以 AUC 只看排序,把所有標記值取對數或乘十都不會動它。0.634 是切點 0.20 上的敏感度,它綁在某一個操作點上,而 AUC 是整條曲線的摘要;把 AUC 說成診斷正確率,會讓人以為它綁在某個切點上。0.775 是本頁後面那個邏輯迴歸模型的 AUC,而且再高的 AUC 也不保證預測機率本身是對的——那是校準的事。

把一組預測機率在 log-odds 尺度上整體往下平移 1.5,AUC 從 0.7751 變成 0.7751,一動也沒動。這代表平移後的模型一樣好嗎?

看答案與解析

正確答案: 不一樣。平移後的平均預測機率是 0.1591,而實際發生率是 0.3628——每個人的風險都被系統性低估了

平移只改變每個人的預測值大小,不改變他們的先後順序,而 AUC 只看順序,所以它到小數點後四位都一樣。校準管的是另一件事:平移後平均預測 0.1591,實際發生率 0.3628,模型系統性低估風險。Brier score 從 0.1741 惡化到 0.2218,這個方向沒有錯——它同時吃鑑別力與校準,所以校準壞掉時它確實會變差。錯的是把這個惡化讀成鑑別力下降:這批預測沒有任何一對換過順序,AUC 到小數點後四位一模一樣,惡化的整份都來自校準。Brier 告訴你「這個模型變差了」,要知道「差在哪一塊」,得把 AUC 與平均預測對實際發生率的落差擺在一起看。只要決策綁在一個絕對機率門檻上,校準不良的模型就會系統性把病人分錯邊,而 AUC 完全看不出來。

把對照組整批複製 20 份,盛行率從 36.3% 降到 2.8%。AUC 與 PR 曲線的平均精確度各自會怎麼樣?

看答案與解析

正確答案: AUC 一格沒動,平均精確度掉到 0.3426,因為 precision 就是 PPV,它吃進盛行率

ROC 的兩個軸——敏感度與一減特異度——都是在疾病狀態內部算的比例,複製對照組不改變其中任何一個,所以 AUC 照定義不動,仍然是 0.7314。PR 曲線的縱軸 precision 就是 PPV,沿著橫列除,於是從 0.6856 掉到 0.3426。但這不表示模型變差了:沒有資訊的基準線也從 36.3% 掉到 2.8%,以相對於基準線的倍數看,第二個反而拉得更開。所以 PR 的數字同樣不能跨盛行率直接比大小,要跟自己的基準線一起讀。

本頁這個生物標記的 AUC 是 0.731(95% CI 0.630 到 0.833),另一個標記 NDKA 是 0.612(0.501 到 0.723)。可以寫「前者優於 NDKA」嗎?

看答案與解析

正確答案: 不行。前者的下界 0.630 低於 NDKA 的上界,兩個區間重疊很多,而且兩條曲線來自同一批病人

兩個點估計看起來差得不少,但前者的下界 0.630 明顯低於 NDKA 的上界 0.723,兩個區間有相當大的重疊。更重要的是這兩個標記量在同一批病人身上,兩個 AUC 估計值是相關的,不能當成兩個獨立樣本比較——正確的做法是配對的 DeLong 檢定,那在切點那一頁。NDKA 的下界 0.501 講的是另一件事:它問的是 NDKA 自己有沒有鑑別力,不是兩者有沒有差。在做完配對檢定之前,不要寫「優於」。

ROC 表上切點 0.05 那一列,敏感度 0.976、一減特異度 0.931。這一列說明這個檢驗很好嗎?

看答案與解析

正確答案: 說明不了。同一列的偽陽性率是 0.931,這一點幾乎貼在右上角

ROC 的右上角是切點低到把所有人都判成陽性,那一點任何檢驗都有,與檢驗好不好無關。切點 0.05 的座標是敏感度 0.976 配上偽陽性率 0.931,幾乎就在那個角落——敏感度高是用「幾乎不放過任何人」換來的。偽陽性率 0.000 那一列則是另一個極端,靠近左下角,它的敏感度只剩兩成出頭,同樣不是天生比較對。曲線上每一點都是一組取捨,哪一點才對取決於偽陽性與偽陰性各自的代價,不能從圖上挑最好看的那一點。

把每一位病人的標記值取對數之後重畫 ROC。AUC 會變成多少?

看答案與解析

正確答案: 還是 0.7314,取對數不改變任何一對病人的先後順序,而 AUC 只看順序

AUC 等於「隨機一位結果差的病人標記值比一位結果好的病人高」的機率,它完全由排序決定。任何嚴格遞增的變換——取對數、開根號、乘十——都不改變任何一對的先後,所以 AUC 一位小數都不會動,仍然是 0.7314。同一個性質也解釋了為什麼 AUC 等價於 Mann-Whitney U 的統計量。0.7751 是本頁那個三變項邏輯迴歸的 AUC,0.6120 是另一個標記 NDKA 的 AUC,兩個都是真的數字,但都不是這個變換會產生的結果。反過來說,AUC 不動這件事也是它的限制:整組預測機率偏掉,它同樣不會動。

延伸觀看

ROC and AUC, Clearly Explained!
ENStatQuest with Josh Starmer· 16 min把「移動切點」這件事動畫出來,讀本頁第一節前先看,曲線是怎麼長出來的會變得很具體。
How to interpret ROC curves
ENTerry Shaneyfelt· 5 min五分鐘的臨床視角總覽,適合看完 StatQuest 後回到診斷情境。
ROC Curves and Area Under the Curve (AUC) Explained
ENData School· 14 min補上 AUC 的機率解釋與門檻選擇的關係,對應本頁第四節。
ROC 系列 1/6:ROC 曲線是什麼
繁中EDMAN MURMURS· 13 min繁中六集系列的第一集,術語中文說法在這裡有對照。
ROC 系列 4/6:AUC 的兩大臨床陷阱
繁中EDMAN MURMURS· 13 min繁中,正好對應本頁第五、六節談的兩件事。

素材來源與授權

本頁為原創內容

回報內容問題

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

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

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

一併送出的資訊

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