曲線下面積(AUC)またはc統計を手で計算する方法


78

バイナリロジスティック回帰モデルの曲線下面積(AUC)またはc統計を手動で計算することに興味があります。

たとえば、検証データセットでは、従属変数の真の値である保持(1 =保持、0 =保持されない)、およびモデルである回帰分析により生成された各観測の予測保持ステータスがありますトレーニングセットを使用して構築されます(これは0〜1の範囲です)。

私の最初の考えは、モデル分類の「正しい」数を特定し、「正しい」観測値の数を総観測値の数で単純に割ってc統計量を計算することでした。「正しい」とは、観測の真の保持ステータス= 1であり、予測される保持ステータスが> 0.5である場合、それは「正しい」分類です。さらに、観測の真の保持ステータス= 0で、予測保持ステータスが0.5未満の場合、それも「正しい」分類です。予測値= 0.5のときに「タイ」が発生すると想定していますが、検証データセットではその現象は発生しません。一方、「誤った」分類は、観測の真の保持ステータス= 1であり、予測される保持ステータスが0未満の場合です。5または結果の真の保持ステータス= 0であり、予測保持ステータスが> 0.5である場合。私はTP、FP、FN、TNを知っていますが、この情報を与えられたc統計を計算する方法を知りません。

回答:


115

私は、Hanley's&McNeilの1982年の論文「受信機動作特性(ROC)曲線下の領域の意味と使用」をお勧めします。

これらには、疾患の状態とテスト結果の次の表があります(たとえば、ロジスティックモデルからの推定リスクに対応)。右側の最初の数字は、真の疾患ステータスが「正常」である患者の数であり、2番目の数字は、真の疾患ステータスが「異常」である患者の数です。

(1)完全に正常:33/3
(2)おそらく正常:6/2
(3)疑わしい:6/2
(4)おそらく異常:11/11
(5)確実に異常:2/33

したがって、合計58人の「正常な」患者と「51」人の異常な患者がいます。予測変数が1、「完全に正常」の場合、患者は通常正常であり(36人の患者のうち33人に対して真)、5の場合、「完全に異常」の場合、患者は通常異常です(患者のうち33人について真35人の患者)、予測子は理にかなっています。しかし、スコア2、3、または4の患者をどのように判断する必要がありますか?患者を異常または正常と判断するためのカットオフを設定して、結果のテストの感度と特異度を決定します。

感度と特異性

異なるカットオフの推定感度と特異度を計算できます。(これからは「感度」と「特異性」を記述し、値の推定される性質を暗黙的にさせます。)

カットオフを選択して、テスト結果が何であっても、すべての患者を異常と分類する場合(つまり、カットオフ1+を選択する場合)、51/51 = 1の感度が得られます。特異性は0になります。 / 58 =0。それほど良く聞こえません。

それでは、それほど厳密でないカットオフを選択しましょう。検査結果が2以上の場合にのみ、患者を異常と分類します。その後、3人の異常な患者を見逃し、48/51 = 0.94の感度を持ちます。しかし、33/58 = 0.57の特異性が大幅に向上しています。

さまざまなカットオフ(3、4、5、> 5)を選択して、これを続行できます。(最後のケースでは、最高のテストスコアが5であっても、患者を異常として分類しません。)

ROC曲線

すべての可能なカットオフに対してこれを行い、1から感度を引いて特異性をプロットすると、ROC曲線が得られます。次のRコードを使用できます。

# Data
norm     = rep(1:5, times=c(33,6,6,11,2))
abnorm   = rep(1:5, times=c(3,2,2,11,33))
testres  = c(abnorm,norm)
truestat = c(rep(1,length(abnorm)), rep(0,length(norm)))

# Summary table (Table I in the paper)
( tab=as.matrix(table(truestat, testres)) )

出力は次のとおりです。

        testres
truestat  1  2  3  4  5
       0 33  6  6 11  2
       1  3  2  2 11 33

さまざまな統計を計算できます。

( tot=colSums(tab) )                            # Number of patients w/ each test result
( truepos=unname(rev(cumsum(rev(tab[2,])))) )   # Number of true positives
( falsepos=unname(rev(cumsum(rev(tab[1,])))) )  # Number of false positives
( totpos=sum(tab[2,]) )                         # The total number of positives (one number)
( totneg=sum(tab[1,]) )                         # The total number of negatives (one number)
(sens=truepos/totpos)                           # Sensitivity (fraction true positives)
(omspec=falsepos/totneg)                        # 1 − specificity (false positives)
sens=c(sens,0); omspec=c(omspec,0)              # Numbers when we classify all as normal

これを使用して、(推定)ROC曲線をプロットできます。

plot(omspec, sens, type="b", xlim=c(0,1), ylim=c(0,1), lwd=2,
     xlab="1 − specificity", ylab="Sensitivity") # perhaps with xaxs="i"
grid()
abline(0,1, col="red", lty=2)

AUC曲線

AUCの手動計算

台形の面積の式を使用して、ROC曲線の下の面積を非常に簡単に計算できます。

height = (sens[-1]+sens[-length(sens)])/2
width = -diff(omspec) # = diff(rev(omspec))
sum(height*width)

結果は0.8931711です。

コンコーダンス測定

AUCは、コンコーダンスの測定値とも見なすことができます。一方が正常でもう一方が異常である可能性のあるすべての患者のペアを取得した場合、最も高い(最も「異常に見える」)テスト結果(同じ値を持っている場合、これを「勝利の半分」と数えます):

o = outer(abnorm, norm, "-")
mean((o>0) + .5*(o==0))

答えは再び0.8931711、ROC曲線の下の領域です。これは常に当てはまります。

一致のグラフィカルビュー

ハレルの答えで指摘したように、これにはグラフィカルな解釈もあります。テストスコア(リスク推定値)をy軸にプロットし、真の疾患状態をx軸にプロットします(ここでは、重なり合ったポイントを示すために、多少のジッターがあります)。

plot(jitter(truestat,.2), jitter(testres,.8), las=1,
     xlab="True disease status", ylab="Test score")

真の疾患状態に対するリスクスコアの散布図。

次に、左側の各ポイント(「正常な」患者)と右側の各ポイント(「異常な」患者)の間に線を引きましょう。正の勾配を持つ線の割合(つまり、一致ペアの割合)は一致インデックスです(平坦な線は「50%一致」としてカウントされます)。

同点の数(リスクスコアが等しい)のために、この例の実際の線を視覚化することは少し難しいですが、ある程度のジッターと透明度を使用すると、妥当なプロットを取得できます。

d = cbind(x_norm=0, x_abnorm=1, expand.grid(y_norm=norm, y_abnorm=abnorm))
library(ggplot2)
ggplot(d, aes(x=x_norm, xend=x_abnorm, y=y_norm, yend=y_abnorm)) +
  geom_segment(colour="#ff000006",
               position=position_jitter(width=0, height=.1)) +
  xlab("True disease status") + ylab("Test\nscore") +
  theme_light()  + theme(axis.title.y=element_text(angle=0))

真の疾患状態に対するリスクスコアの散布図。すべての可能な観測ペア間の線で。

ほとんどの線が上向きに傾斜しているため、一致指数が高くなります。また、各タイプの観測ペアからのインデックスへの寄与も確認します。そのほとんどは、リスクスコアが1の正常な患者と、リスクスコアが5の異常な患者(1〜5ペア)のペアですが、1〜4ペアと4〜5ペアのペアもかなり多くあります。また、勾配の定義に基づいて実際の一致指数を計算するのは非常に簡単です。

d = transform(d, slope=(y_norm-y_abnorm)/(x_norm-x_abnorm))
mean((d$slope > 0) + .5*(d$slope==0))

答えは再び0.8931711、つまりAUCです。

ウィルコクソン–マン–ホイットニー検定

コンコーダンス測定とウィルコクソン-マン-ホイットニー検定の間には密接な関係があります。実際、後者は、一致の確率(つまり、「異常に見える」テスト結果が最も出るのはランダムな正常-異常ペアの異常な患者)が正確に0.5であるかどうかをテストします。そして、その検定統計量は、推定一致確率の単純な変換です。

> ( wi = wilcox.test(abnorm,norm) )
    Wilcoxon rank sum test with continuity correction

data:  abnorm and norm
W = 2642, p-value = 1.944e-13
alternative hypothesis: true location shift is not equal to 0

検定統計量(W = 2642)は、一致するペアの数をカウントします。可能なペアの数で割ると、おなじみの数字が得られます。

w = wi$statistic
w/(length(abnorm)*length(norm))

はい、それは0.8931711、ROC曲線の下の面積です。

AUCを計算する簡単な方法(R)

しかし、私たち自身の生活をもっと楽にしましょう。AUCを自動的に計算するさまざまなパッケージがあります。

Epiパッケージ

このEpiパッケージは、さまざまな統計(AUCを含む)が埋め込まれた素晴らしいROC曲線を作成します。

library(Epi)
ROC(testres, truestat) # also try adding plot="sp"

EpiパッケージのROC曲線

pROCパッケージ

またpROC、ROC推定値を平滑化できる(および平滑化されたROCに基づいてAUC推定値を計算できる)パッケージも気に入っています。

pROCパッケージのROC曲線(平滑化および平滑化)

(赤い線は元のROCで、黒い線は平滑化されたROCです。デフォルトの1:1アスペクト比にも注意してください。感度と特異度の両方に0〜1の範囲があるため、これを使用するのは理にかなっています)

平滑化された ROC からの推定AUC は0.9107で、平滑化されていない ROC からのAUC に似ていますが、わずかに大きくなっています(図を見ると、なぜ大きいのか簡単にわかります)。(スムーズなAUCを計算するには、実際のテスト結果値が少なすぎますが)。

rmsパッケージ

Harrellのrmsパッケージは、rcorr.cens()関数を使用して関連するさまざまな一致統計を計算できます。C Indexその出力では、AUCです。

> library(rms)
> rcorr.cens(testres,truestat)[1]
  C Index 
0.8931711

caToolsパッケージ

最後に、caToolsパッケージとそのcolAUC()機能があります。-それは、他のパッケージ(参照主にスピードと多次元データを操作する能力を超えるいくつかの利点がある?colAUCことができます)、時には役に立つことを。しかし、もちろん、繰り返し計算したのと同じ答えが得られます。

library(caTools)
colAUC(testres, truestat, plotROC=TRUE)
             [,1]
0 vs. 1 0.8931711

caToolsパッケージのROC曲線

最後の言葉

多くの人は、AUCがテストの「良い」ことを教えてくれると考えているようです。そして、一部の人々は、AUCがテストが患者を正しく分類する確率であると考えています。そうではありません。あなたは上記の例と計算からわかるように、AUCは私たちについて何か伝え家族のテストの、それぞれの可能なカットオフに1つのテストを。

そして、AUCは実際には決して使用しないカットオフに基づいて計算されます。「無意味な」カットオフ値の感度と特異性に注意する必要があるのはなぜですか?それでも、それはAUCが(部分的に)基づいているものです。(もちろん、AUCが1 に非常に近い場合、ほとんどすべての可能なテストに大きな差別力があり、私たちはすべて非常に満足しています。)

AUCの「ランダムな正常-異常」ペアの解釈は優れています(また、たとえば、生存モデルに拡張することができます。しかし、実際に使用することはありません。健康な人と病気の人が1いることを知っており、どの人が病気であるかを知らず、どの人を治療するかを決定しなければならないまれなケースです。(いずれの場合でも、決定は簡単です。推定リスクが最も高いものを扱います。)

したがって、実際のROC曲線を調べることは、AUCの要約測定値を見るよりも役立つと思います。また、ROCを(推定の)偽陽性および偽陰性のコストと、学習しているものの基本レートと一緒に使用すると、どこかに到達できます。

また、AUCは差別ではなく、キャリブレーションのみを測定することに注意してください。つまり、リスクスコアに基づいて、2人(病気の人と健康な人)を区別できるかどうかを測定します。このために、それだけを見て、相対(あなたは、Wilcoxon-Mann-Whitney検定の解釈を参照されたいかどうか、ランク、)リスク値ではなく、あなたは絶対的なもの、必要があることに興味がある。たとえば、各リスクを分割する場合ロジスティックモデルから2で推定すると、まったく同じAUC(およびROC)が得られます。

リスクモデルを評価する場合、キャリブレーションも非常に重要です。これを調べるには、約0.7のリスクスコアを持つすべての患者を調べ、これらの約70%が実際に病気であったかどうかを確認します。可能性のある各リスクスコアに対してこれを行います(何らかの平滑化/ローカル回帰を使用する可能性があります)。結果をプロットすると、キャリブレーションのグラフィカルな測定値が得られます

優れたキャリブレーションと優れた識別の両方を備えたモデルがある場合優れたモデルができ始めます。:)


8
ありがとう、@ Karl Ove Hufthammer、これは私がこれまでに受け取った最も徹底的な答えです。あなたの「最後の言葉」セクションに特に感謝します。素晴らしい仕事です!再度、感謝します!
マットライヘンバッハ

この詳細な回答をありがとうございます。私はEpi :: ROC()v2.2.6がAUCが1.62であると確信しているデータセットで作業しています(しかし、メンタリストの研究ではありません)が、ROCによれば、上記のコードは0.56インチ
BurninLeo

32

この質問をご覧ください:ROC曲線を理解する

ROC曲線を作成する方法は次のとおりです(その質問から)。

ROC曲線の描画

ランキング分類子によって処理されたデータセットが与えられた場合

  • スコアの減少に関するテスト例のランク付け
  • 00
  • バツ
    • バツ1/pos
    • バツ1/

pos

このアイデアを使用して、次のアルゴリズムを使用してAUC ROCを手動で計算できます。

auc = 0.0
height = 0.0

for each training example x_i, y_i
  if y_i = 1.0:
    height = height + tpr
  else 
    auc = auc + height * fpr

return auc

この素敵なgifアニメーション画像は、このプロセスをより明確に示しているはずです。

曲線を作成する


1
@Alexey Grigorevに感謝します。これは素晴らしいビジュアルであり、将来役に立つ可能性が高いでしょう!+1
マットライヘンバッハ

1
「正と負の例の端数」について少し説明していただけますか、2軸の最小単位値を意味していますか?
アラン遺跡

1
@Allan Ruin:posここで正のデータの数を意味します。20個のデータポイントがあり、そのうち11個のポイントが1であるとします。したがって、グラフを描画するとき、長方形11x9(高さx幅)があります。Alexey Grigorevはスケーリングしましたが、必要に応じてそのままにしてください。次に、各ステップでチャート上で1を移動します。
Catbuilts

5

Karlの投稿には多くの優れた情報があります。しかし、私は過去20年間、誰の考えも良い方向に変わったROC曲線の例をまだ見ていません。私の謙虚な意見では、ROC曲線の唯一の価値は、その面積が偶然に非常に有用な一致確率に等しいということです。ROC曲線自体は、カットオフを使用するように読者を誘惑します。

cY=01バツY=1yY=0Y=1

n

R Hmiscパッケージrcorr.cens関数の場合、結果全体を印刷して、詳細情報、特に標準エラーを表示します。


@フランク・ハレル、ありがとうございます。カットオフが好きではないので、単純にc統計を一致確率として使用します。再度、感謝します!
マットライヘンバッハ

4

台形規則を使用してROC曲線の下の面積を取得するだけで、AUCを計算する自然な方法の代替方法を次に示します。

AUCは、ランダムにサンプリングされた正の観測値が、ランダムにサンプリングされた負の観測値よりも大きい(正である)予測確率を持つ確率に等しくなります。これを使用して、正と負の観測値のすべてのペアワイズ組み合わせを実行することにより、任意のプログラミング言語でAUCを非常に簡単に計算できます。サンプルサイズが大きすぎる場合は、観測値をランダムにサンプリングすることもできます。ペンと紙を使用してAUCを計算する場合、これは、非常に少ないサンプル/多くの時間がない限り、最善のアプローチではないかもしれません。Rの例:

n <- 100L

x1 <- rnorm(n, 2.0, 0.5)
x2 <- rnorm(n, -1.0, 2)
y <- rbinom(n, 1L, plogis(-0.4 + 0.5 * x1 + 0.1 * x2))

mod <- glm(y ~ x1 + x2, "binomial")

probs <- predict(mod, type = "response")

combinations <- expand.grid(positiveProbs = probs[y == 1L], 
        negativeProbs = probs[y == 0L])

mean(combinations$positiveProbs > combinations$negativeProbs)
[1] 0.628723

pROCパッケージを使用して確認できます。

library(pROC)
auc(y, probs)
Area under the curve: 0.6287

ランダムサンプリングの使用:

mean(sample(probs[y == 1L], 100000L, TRUE) > sample(probs[y == 0L], 100000L, TRUE))
[1] 0.62896

1
  1. 観測には真の価値があります。
  2. 事後確率を計算し、この確率で観測値をランク付けします。
  3. PN
    真のランクの合計0.5PNPN+1PNNPN

1
@ user73455 ... 1)はい、観測の真の値があります。2)事後確率は、各観測の予測確率と同義ですか?3)理解した; ただし、「真のランクの合計」とは何ですか?また、この値をどのように計算しますか?おそらく、この答えをより完全に説明するのに役立つ例でしょうか?ありがとうございました!
マットライヘンバッハ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.