ROC曲線とAUCを理解しよう！ - 二値分類モデルの性能評価

# ROC曲線とAUCの基礎

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">こんにちは！
今日はROC曲線について学んでいきましょう。
ROC曲線は二値分類モデルの性能を評価する上で非常に重要なツールです。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">こんにちは。
よろしくお願いします。
ROC曲線は名前は聞いたことがあるくらいで、詳しくは知りません。少し難しそうですね。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">心配いりません。一緒に理解していきましょう。
まず、ROCは **Receiver Operating Characteristic** の略です。
日本語だと、**受信者動作特性** となりますが、耳慣れない言葉ですよね。

実は、最初は、第二次世界大戦中にレーダー信号の検出に使用されました。
レーダー操作員 (Receiver Operator) が、実際の航空機の信号とノイズを区別する能力を評価するために使われました。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">もとは軍事目的だったのですね！

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">そうなんです。
現在では一般的な性能評価指標として、元の文脈を超えて幅広く使用されています。

ROC曲線は、一言で言うと、二値分類モデルの性能を様々な区切る値でグラフ化したものです。

具体的な例を使って説明しましょう。がんのスクリーニングを考えてみましょう。
ある血液検査の結果から、人ががんかどうかを分類したいとします。高い検査値ががんの可能性を示すとします。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">なるほど。でも、どの値を基準にがんと判断するのでしょうか？

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">そこが重要なポイントです！その基準値を「閾値」と呼びます。この閾値の選び方によって、モデルの性能が変わってきます。

例として、以下のような30人の血液検査の結果とその人が実際にがんかどうかのデータをもとに考えてゆきましょう。

| ID | 検査値 | がん | &emsp; | ID | 検査値 | がん | &emsp; | ID | 検査値 | がん |
|----|--------|------|--|----|--------|------|--|----|--------|------|
| 1  | 12     | 健康 |  | 11 | 48     | 健康 |  | 21 | 68     | がん |
| 2  | 15     | 健康 |  | 12 | 50     | がん |  | 22 | 70     | がん |
| 3  | 20     | 健康 |  | 13 | 52     | がん |  | 23 | 72     | がん |
| 4  | 25     | 健康 |  | 14 | 53     | 健康 |  | 24 | 75     | がん |
| 5  | 30     | 健康 |  | 15 | 55     | がん |  | 25 | 78     | がん |
| 6  | 35     | 健康 |  | 16 | 57     | がん |  | 26 | 80     | がん |
| 7  | 38     | 健康 |  | 17 | 60     | がん |  | 27 | 82     | がん |
| 8  | 40     | 健康 |  | 18 | 62     | 健康 |  | 28 | 85     | がん |
| 9  | 42     | 健康 |  | 19 | 65     | がん |  | 29 | 88     | がん |
| 10 | 45     | がん |  | 20 | 67     | がん |  | 30 | 90     | がん |

[データをダウンロード (CSV) ](https://www.emuyn.net/_media/stats/chat/roc_sample.csv)

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">このデータを使ってROC曲線について説明していきます。

データの分布を確認するために、**ヒストグラム**と**箱ひげ図**を作成してみましょう。

ヒストグラム
![ヒストグラム](https://www.emuyn.net/_media/stats/chat/roc_sample_histogram.png)

箱ひげ図
![箱ひげ図](https://www.emuyn.net/_media/stats/chat/roc_sample_boxchart.png)

[Reactive stat の 対応のない群間の検定](https://www.emuyn.net/stats/basic_statistics)を使って描画できます

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">健康な人とがんの人の検査値が重なっている部分がありますね。
どこかで区切ったとしても、きれいに分けることはできないようです。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">その通りです。では、閾値を45に設定してみましょう。この場合、どうなると思いますか？

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">えーと、45より高い値の人をがんと判断するんですよね。グラフを見ると...がんの人16人のうち15人が正しく「がん」と判断されそうです。でも、健康な人2人が「がん」と誤って判断されてしまいますね。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">そうなります。
表にすると下のようになります。

| 実際の状態 | 「がん」と判断 | 「健康」と判断 | 合計 |
|------------|----------------|----------------|------|
| **がん**       | 15 (真陽性)    | 1 (偽陰性)     | 16   |
| **健康**       | 2 (偽陽性)     | 12 (真陰性)    | 14   |
| 合計       | 17             | 13             | 30   |

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">表にするとわかりやすいですね。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">では、ここで重要な2つの指標を導入しましょう。

1. **真陽性率 (True Positive Rate, TPR)**: 実際にがんの人のうち、正しく「がん」と判定できた割合です。
   TPR = 真陽性 / (真陽性 + 偽陰性)
   この例では、15 / (15 + 1) = 15/16 ≈ 0.9375 です。

2. **偽陽性率 (False Positive Rate, FPR)**: 実際には健康な人のうち、誤って「がん」と判定してしまった割合です。
   FPR = 偽陽性 / (偽陽性 + 真陰性)
   この例では、2 / (2 + 12) = 2/14 ≈ 0.1429 です。

**真陽性率** は **感度 (sensitivity)**、**1 - 偽陽性率 (1 - FPR)** は **特異度 (specificity)** とも呼ばれます。

その他の重要な指標には以下のようなものがあります。

3. **陽性的中率 (Positive Predictive Value, PPV)**: 「がん」と判断された人のうち、本当にがんである人の割合です。
  PPV = 真陽性 / (真陽性 + 偽陽性)
  この例では、15 / (15 + 2) = 15/17 ≈ 0.882 (88.2%) です。

4. **陰性的中率 (Negative Predictive Value, NPV)**: 「健康」と判断された人のうち、実際に健康である人の割合です。  
  NPV = 真陰性 / (真陰性 + 偽陰性)
  この例では、12 / (12 + 1) = 12/13 ≈ 0.923 (92.3%) です。

5. **精度 (Accuracy)**: 全体の中で正しく判定された割合です。
  精度 = (真陽性 + 真陰性) / 全体
  この例では、(15 + 12) / 30 = 27/30 = 0.9 (90%) です。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">なるほど。よくわかりました。

特異度は、健康な人（つまり「がんではない人」）を正しく「健康」と判定できた割合ということですね。
具体的には、「1 - 偽陽性率」で計算されるので、健康な人を誤って病気だと判定してしまう割合が減るほど、特異度が高くなるんですね。
検査が正確に病気を見分けられれば、特異度は高くなりますし、偽陽性を多く出してしまうと特異度は低くなるというわけですね。

COVID-19 のパンデミックの初期には、PCR検査や抗原検査でこれらの指標がテレビのニュースなどでも言われていましたが、きちんとは理解していませんでした。
みんなわかって使っていたのかな？

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">おそらく正確に理解しないで使っていた人が多かったと思います。
思い返せば、不毛な論争もありましたよね。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">そうですね。
それはさておき、閾値を変えるとこれらの値も変わりそうですね。
詳しく教えてください。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">鋭い観察ですね。実は、ROC曲線はまさにそれを可視化したものなんです。

閾値を変えながら各指標の値を計算してみましょう。

| 閾値 | 感度 (sensitivity)<br>真陽性率 (TPR) | 偽陽性率 (FPR) | 特異度 (specificity) |
|------|---------------|---------------|---------------|
| 最小値 (12) | 1.00 | 1.00 | 0.00 |
| 少し上げると (40) | 1.00 | 0.29 | 0.71 |
| さらに上げると (50) | 0.94 | 0.071 | 0.93 |
| さらに上げると (60)   | 0.75 | 0.00 | 1.00 |
| 最大値 (90) | 0.00 | 0.00 | 1.00 |

域値と感度・特異度
![域値と感度・特異度](https://www.emuyn.net/_media/stats/chat/roc_sample_域値と感度・特異度.png)

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">これらの点をつないだ曲線が、ROC曲線というわけです。
Reactive stat の機能を使えば、簡単に描くことができます。

ROC曲線
![ROC曲線](https://www.emuyn.net/_media/stats/chat/roc_sample_roc曲線.png)

[Reactive stat で ROC曲線 を実行](https://www.emuyn.net/stats/roc)

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">ROC曲線は左上に膨らんでいますね。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">その通りです。ROC曲線は**左上に膨らむほど良い性能**を示します。
完璧な分類器であれば、曲線は左上の角を通ります (TPR = 1, FPR = 0) 。

曲線の下の面積を**AUC (Area Under the Curve)** と呼び、これもモデルの性能を示す指標として使われます。
解釈する上での注意点は次の通りです。

- **AUCの定義**:
  AUCは、ROC曲線の下の面積を表します。0から1の間の値をとり、1に近いほど優れたモデルであることを示します。

- **AUCの解釈**:

| AUC 値            | モデルの評価                                         |
|-------------------|----------------------------------------------------|
| AUC = 1.0         | 完璧な分類器。<br>全ての陽性例を正しく識別し、偽陽性がゼロ。 |
| 0.9 < AUC < 1.0   | 非常に優れたモデル                                   |
| 0.8 < AUC < 0.9   | 良好なモデル                                         |
| 0.7 < AUC < 0.8   | まずまずのモデル                                     |
| 0.6 < AUC < 0.7   | あまり良くないモデル                                 |
| AUC = 0.5         | ランダムな予測と同程度（無意味なモデル）               |
| AUC < 0.5         | ランダムよりも悪い予測（予測を逆にした方が良い）       |

- **AUCの利点**:
  - 閾値に依存しない評価指標であるため、異なるモデル間の比較が容易。
  - データの不均衡（陽性・陰性の比率が大きく異なる場合）に対してロバスト。

- **AUCの計算方法**:
  - 数学的には、正例を陽性と予測する確率が、負例を陽性と予測する確率より大きい確率として解釈できます。
  - 実際の計算では、ROC曲線下の面積を数値積分によって求めます。

- **AUCの限界**:
  - 非常にアンバランスなデータセットでは、誤解を招く可能性があります。
  - 予測の信頼度（確率）を考慮しないため、確率の較正が重要な場合は他の指標も併用すべきです。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">例えば、先ほどのがん診断の例では、AUC = 0.954 でした。これは非常に優れたモデルであることを示しています。つまり、このテストは健康な人とがんの人を高い精度で区別できると言えます。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">AUCが高ければ高いほど、良いモデルだとわかるんですね！
ROC曲線とAUCの関係が少しずつ理解できてきました。

ところで、実際にモデルを使う時には、どのように閾値を設定すればいいのでしょうか？

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">とても良い質問です！
閾値の設定は非常に重要で、モデルの実用性に大きく影響します。
閾値設定の基本的な考え方を、がんの診断を例に説明しましょう。

1. **リスクとコストのバランス**:
   - 偽陽性 (健康な人を誤ってがんと判断) と偽陰性 (がんを見逃す) のリスクを考えます。
   - 例: 一次スクリーニングでは、見逃しを減らすために感度を高く (閾値を低く) 設定することがあります。

2. **目的に応じた調整**:
   - スクリーニングの段階によって、閾値を変えることがあります。
   - 例: 一次スクリーニングでは感度を重視し、追加検査では特異度を上げて (閾値を高くして) より確実な診断を目指します。

3. **専門家の意見を取り入れる**:
   - 医療専門家の経験や知識を基に、現実的な閾値を設定します。

4. **定期的な見直し**:
   - 新しいデータが集まったら、閾値の適切さを再評価します。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">実際の例を見てみましょう:

がん検診の場合: 
- 一次スクリーニング (例: 血液検査) 
  - 目的: 可能性のあるケースを広く拾い上げる
  - 戦略: 感度を高く設定 (閾値を低めに) 
  - 理由: 見逃すことなく精密検査に回すため

- 追加検査 (例: 精密検査、生検) 
  - 目的: より確実な診断
  - 戦略: 特異度を高く設定 (閾値を高めに) 
  - 理由: 陽性であれば手術などの治療を行うことになるため。陰性の場合は、一定期間後に再検査することで、偽陰性に対応できる

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">このように、検査の目的や段階によって適切な閾値は変わります。
常に検査の目的を念頭に置き、最善の結果を導けるよう閾値を設定することが大切です。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">なるほど。
そうだとすれば、域値を変えたときに指標がどうなるのか、簡単にわかると便利ですよね。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">はい。Reactive stat では、スライダーで域値を変えながら、指標の変化を数値とグラフで確認できますので、すごくわかりやすいですよ。

![閾値を変更](https://www.emuyn.net/_media/stats/chat/roc_sample_閾値変更_small.gif)

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">なるほどわかりやすいですね。

では、このROC曲線を使って異なる分類モデルを比較することもできるんですか？

<img src="https://www.emuyn.net/_media/stats/chat/avatar_robot.png" alt="mentor" class="avatar" style="box-shadow: none;">もちろんできます。
Reactive stat では、異なるモデルのROC曲線を同じグラフ上にプロットすることで、モデルの性能を視覚的に比較できます。
各検査法に対する AUC、閾値の評価を R で行うことができます。

[Reactive stat の ROC曲線](https://www.emuyn.net/stats/roc)には、2つのROCを比較するサンプルデータが用意されています。

<img src="https://www.emuyn.net/_media/stats/chat/avatar_%E5%A5%B3%E6%80%A7%E5%8C%BB%E5%B8%AB.png" alt="mentor" class="avatar" style="box-shadow: none;">そうですか。ぜひ試して勉強してみます。

今日はROC曲線の意味と重要性がよくわかりました。
ありがとうございました！