模型评估小册(1) ROC 曲线与 AUC
<p>一点前言:之前完成了吴恩达深度学习的相关内容,最近忙于毕设,更新可能没之前那么频繁。这个新开的分类关于<strong>模型评估的各种指标</strong>的详解,之前翻看书籍总是被一堆很官方化的概念和密密麻麻的符号搞的看不下去,因此,这次的中心思想是以尽可能<strong>通俗的语言、精简的篇幅</strong>来讲解这类概念并辅以实例。<br>不多废话,以下为正文。</p>
<hr>
<h1 id="1-检测问题中的两难情景">1. 检测问题中的“两难情景”</h1>
<p>假设我们在机场负责安检。任务很简单:<strong>把携带危险物品的人拦下来。</strong></p>
<p>但现实远没有这么简单,如果我们把安检<strong>标准定得非常严格</strong>——一点可疑都不放过,那么确实可以拦下几乎所有危险人员。<br>
但代价是,<strong>正常旅客也会被频繁拦下复检</strong>,队伍排到大厅外。</p>
<p>而如果我们<strong>把标准放宽</strong>——只在非常明显的情况下才拦人,旅客通行效率会提高。<br>
但显然,这就<strong>有更大可能漏掉真正的风险</strong>。</p>
<p>这就是一个经典的两难:<strong>选择杀错还是放过</strong>?</p>
<blockquote>
<p><strong>抓得越多,错抓也越多。</strong><br>
<strong>抓得越少,漏抓就越多。</strong></p>
</blockquote>
<p><img src="https://img2024.cnblogs.com/blog/3708248/202602/3708248-20260211191745572-2075288255.png" alt="f2bc31dc-fe19-439e-a7a0-4efb06659caf.png" loading="lazy"></p>
<p>目标检测问题本质上也是如此,在高光谱目标检测、雷达探测、异常检测等目标检测任务中,我们面对的不是“对或错”这么简单,而是<strong>在任务情景中,对“错报”和“漏报”的权衡选择</strong>:</p>
<blockquote>
<p><strong>我的模型,能检测出多少真实目标?但同时会误报多少背景?我的任务要求我更偏向哪边?在哪里二者较为均衡?</strong></p>
</blockquote>
<p>总之,在检测系统中,没有免费的午餐:提高检测率,往往要付出虚警率的代价。<br>
ROC 曲线描述的,正是这两者之间的关系。</p>
<h1 id="2-rocreceiver-operating-characteristic">2. ROC(Receiver Operating Characteristic)</h1>
<p>ROC 的英文全称为 <strong>Receiver Operating Characteristic</strong> ,直译为受试者工作特征曲线,它来源于<strong>统计学中的检测理论</strong>,而最早的应用领域是<strong>雷达探测</strong>。</p>
<p>不同于一些常见指标,<strong>ROC 刻画的是虚警概率和检测概率间的函数关系</strong>。<br>
直接来看一个实例:<br>
<img src="https://img2024.cnblogs.com/blog/3708248/202602/3708248-20260211191746062-1023289789.png" alt="image.png" loading="lazy"><br>
现在,假设一天有 <strong>100 个携带危险物品的旅客</strong>和 <strong>1000 个普通旅客</strong>:</p>
<p>1.<strong>真阳性率(TPR / Pd)</strong>:系统能正确抓住真正危险旅客的比例,即“该抓的抓了多少”。<br>
2.<strong>假阳性率(FPR / Fa)</strong>:系统把普通旅客误判为危险旅客的比例,即“不该抓的抓错了多少”。</p>
<table>
<thead>
<tr>
<th>普通旅客数量</th>
<th>危险旅客数量</th>
<th>通过 / 正常数量</th>
<th>抓到数量</th>
<th>指标及计算过程</th>
</tr>
</thead>
<tbody>
<tr>
<td>—</td>
<td>100</td>
<td>3 漏掉</td>
<td>97抓到</td>
<td><strong>真阳性率 Pd = 97 / 100 = 0.97 (97%)</strong></td>
</tr>
<tr>
<td>1000</td>
<td>—</td>
<td>800 正常通过</td>
<td>200 误抓</td>
<td><strong>假阳性率 Fa = 200 / 1000 = 0.2 (20%)</strong></td>
</tr>
</tbody>
</table>
<p>实际上二者的计算还是对四类基础统计量的应用。<br>
这样,我们就得到了 ROC 曲线中的一个点:<span class="math inline">\((0.2,0.97)\)</span> ,我们称之为<strong>Pd @ Fa 或 Pd / Fa</strong> ,它说明了<strong>在特定虚警率下能抓到多少目标</strong>,展开如下:<br>
<img src="https://img2024.cnblogs.com/blog/3708248/202602/3708248-20260211191743792-444019702.png" alt="image.png" loading="lazy"><br>
到这里,就会发现: <strong>ROC 曲线中的一个点就是一种决策阈值下的模型表现。</strong><br>
我们不断测试不同的阈值计算,最终就会得到 ROC 曲线,列举几种情况如下:</p>
<table>
<thead>
<tr>
<th>阈值 t</th>
<th>判定规则</th>
<th>危险旅客抓到情况 (Pd)</th>
<th>普通旅客误抓情况 (Fa)</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>0.8</td>
<td>只有概率 ≥ 0.8 判为危险</td>
<td>80 / 100 = 0.80</td>
<td>50 / 1000 = 0.05</td>
<td>严格判定,只抓最明显的危险旅客,虚警很少</td>
</tr>
<tr>
<td>0.5</td>
<td>概率 ≥ 0.5 判为危险</td>
<td>95 / 100 = 0.95</td>
<td>200 / 1000 = 0.20</td>
<td>中等判定,抓到大部分危险旅客,虚警适中</td>
</tr>
<tr>
<td>0.3</td>
<td>概率 ≥ 0.3 判为危险</td>
<td>99 / 100 = 0.99</td>
<td>400 / 1000 = 0.40</td>
<td>宽松判定,几乎抓到全部危险旅客,但虚警明显增加</td>
</tr>
<tr>
<td>0.1</td>
<td>概率 ≥ 0.1 判为危险</td>
<td>100 / 100 = 1.00</td>
<td>800 / 1000 = 0.80</td>
<td>极度宽松,抓到全部危险旅客,但绝大部分普通旅客也被误抓</td>
</tr>
</tbody>
</table>
<p>观察下来,你会发现:<strong>误报率越高往往代表阈值越低。</strong><br>
而到了这里,你可能会有一个问题:<strong>那在实际运行中,我总不能一个个阈值去试吧?要多少次才能拼出来完整曲线?</strong></p>
<p>实际上,我们<strong>在真实运行中只需要运行一次模型就可以得到完整 ROC 曲线。</strong><br>
<strong>用一句话概括其算法:存储模型对每个样本的输出概率并排序,从高到低依次确认为正类(抓捕)并计算 Pd @ Fa ,加入图像。</strong><br>
来看个例子:</p>
<table>
<thead>
<tr>
<th>排名</th>
<th>旅客 ID</th>
<th>是否危险</th>
<th>模型概率 p</th>
<th>挨个抓</th>
<th>累计 TP</th>
<th>累计 FP</th>
<th>Pd = TP / 3</th>
<th>Fa = FP / 7</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>A</td>
<td>✅ 危险</td>
<td>0.95</td>
<td>抓</td>
<td>1</td>
<td>0</td>
<td>0.33</td>
<td>0</td>
</tr>
<tr>
<td>2</td>
<td>B</td>
<td>❌ 普通</td>
<td>0.90</td>
<td>抓</td>
<td>1</td>
<td>1</td>
<td>0.33</td>
<td>0.14</td>
</tr>
<tr>
<td>3</td>
<td>C</td>
<td>✅ 危险</td>
<td>0.85</td>
<td>抓</td>
<td>2</td>
<td>1</td>
<td>0.67</td>
<td>0.14</td>
</tr>
<tr>
<td>4</td>
<td>D</td>
<td>❌ 普通</td>
<td>0.70</td>
<td>抓</td>
<td>2</td>
<td>2</td>
<td>0.67</td>
<td>0.29</td>
</tr>
<tr>
<td>5</td>
<td>E</td>
<td>❌ 普通</td>
<td>0.60</td>
<td>抓</td>
<td>2</td>
<td>3</td>
<td>0.67</td>
<td>0.43</td>
</tr>
<tr>
<td><strong>6</strong></td>
<td><strong>F</strong></td>
<td><strong>✅ 危险</strong></td>
<td><strong>0.50</strong></td>
<td><strong>抓</strong></td>
<td><strong>3</strong></td>
<td><strong>3</strong></td>
<td><strong>1.00</strong></td>
<td><strong>0.43</strong></td>
</tr>
<tr>
<td>7</td>
<td>G</td>
<td>❌ 普通</td>
<td>0.45</td>
<td>抓</td>
<td>3</td>
<td>4</td>
<td>1.00</td>
<td>0.57</td>
</tr>
<tr>
<td>8</td>
<td>H</td>
<td>❌ 普通</td>
<td>0.30</td>
<td>抓</td>
<td>3</td>
<td>5</td>
<td>1.00</td>
<td>0.71</td>
</tr>
<tr>
<td>9</td>
<td>I</td>
<td>❌ 普通</td>
<td>0.20</td>
<td>抓</td>
<td>3</td>
<td>6</td>
<td>1.00</td>
<td>0.86</td>
</tr>
<tr>
<td>10</td>
<td>J</td>
<td>❌ 普通</td>
<td>0.10</td>
<td>抓</td>
<td>3</td>
<td>7</td>
<td>1.00</td>
<td>1.00</td>
</tr>
</tbody>
</table>
<p>在这里,<strong>当把旅客F抓捕时,计算得到的 Pd @ Fa 较优,也就是说,其对应的模型概率 p=0.5 就是一个可能较优的决策阈值选择。</strong></p>
<p>到这里 ROC 的内容就基本结束,但是你会发现:<strong>曲线里我光看不同阈值的情况了,那这个模型本身到底好不好?有多好?能不能给我一个明确的评估呢?</strong><br>
这就是与 ROC 曲线相关联的内容:AUC 。</p>
<h1 id="3-aucarea-under-curve">3. AUC(Area Under Curve)</h1>
<p>AUC 的全称是 Area Under Curve,直译就是ROC 曲线下面积。它用一个<strong>单一指标</strong>来衡量模型整体能力。<br>
在得到 ROC 曲线后,AUC的计算非常简单:<br>
<img src="https://img2024.cnblogs.com/blog/3708248/202602/3708248-20260211191744270-1543306405.png" alt="image.png" loading="lazy"><br>
显然,AUC面积越大,模型越能在低虚警率下实现高检测率,模型的检测效果就越好。<br>
并且,我们不需要提前选定决策阈值,就可以知道模型整体的好坏。</p>
<p>总结一句话:<strong>ROC 告诉我们在不同标准下模型表现如何,而 AUC 则给出一个整体评分,实现不用盯着每个阈值也能知道模型好不好,从而帮助相关任务的调优和部署。</strong></p><br><br>
来源:https://www.cnblogs.com/Goblinscholar/p/19605705
頁:
[1]