准确率和召回率之间的反比关系

数据挖掘 准确性 混淆矩阵
2021-10-02 05:11:29

我进行了一些搜索以了解准确率和召回率,我看到一些图表表示准确率和召回率之间的反比关系,我开始考虑它以澄清主题。我想知道反比关系总是成立吗?假设我有一个二元分类问题,并且有正负标记类。在训练之后,一些实际的正例被预测为真正例,其中一些为假负例,一些实际负例被预测为真负例,其中一些为假正例。为了计算精度和召回率,我使用以下公式:

Precision=TPTP+FP
Recall=TPTP+FN
如果我减少假阴性,那么真阳性会增加,在这种情况下,精度和召回率不会增加吗?

3个回答

如果我们减少假阴性(选择更多的阳性),召回率总是会增加,但精度可能会增加或减少。通常,对于比随机更好的模型,精度和召回具有反比关系(@pythinker的答案),但对于比随机更差的模型,它们具有直接关系(@kbrose的示例)。

值得注意的是,我们可以人为地构建一个样本,使在真实分布上优于随机的模型表现得比随机差,因此我们假设样本类似于真实分布。

记起

我们有

TP=PFN
因此,召回将是
r=PFNP=1FNP
它总是随着减少而增加 FN.

精确

为了精确,这种关系并不那么简单。让我们从两个例子开始。

第一种情况:通过减少假阴性来降低精度:

label   model prediction
1       0.8
0       0.2
0       0.2
1       0.2

对于阈值 0.5 (假阴性= {(1,0.2)}),

p=11+0=1

对于阈值 0.0 (假阴性= {}),

p=22+2=0.5

第二种情况:通过减少假阴性来提高精度(与@kbrose示例相同):

label   model prediction
0       1.0
1       0.4
0       0.1

对于阈值 0.5 (假阴性= {(1,0.4)}),

p=00+1=0

对于阈值 0.0 (假阴性= {}),

p=11+2=0.33

值得注意的是,这种情况下的 ROC 曲线是

基于ROC曲线的精度分析

当我们降低阈值时,假阴性减少,真阳性[率]增加,相当于在ROC图中向右移动我对优于随机、随机和劣于随机的模型进行了模拟,并绘制了 ROC、召回率和精度:

如您所见,通过向右移动,对于优于随机模型的模型,精度会降低,对于随机模型,精度有很大的波动,对于差于随机模型的模型精度会增加。并且在这三种情况下都有轻微的波动。所以,

通过增加召回率,如果模型优于随机模型,则精度通常会降低。如果模式比随机差,精度通常会增加。

下面是模拟代码:

import numpy as np
from sklearn.metrics import roc_curve
from matplotlib import pyplot

np.random.seed(123)
count = 2000
P = int(count * 0.5)
N = count - P
# first half zero, second half one
y_true = np.concatenate((np.zeros((N, 1)), np.ones((P, 1))))

title = 'Better-than-random model'
# title = 'Random model'
# title = 'Worse-than-random model'
if title == 'Better-than-random model':
    # GOOD: model output increases from 0 to 1 with noise
    y_score = np.array([p + np.random.randint(-1000, 1000)/3000
                        for p in np.arange(0, 1, 1.0 / count)]).reshape((-1, 1))
elif title == 'Random model':
    # RANDOM: model output is purely random
    y_score = np.array([np.random.randint(-1000, 1000)/3000
                        for p in np.arange(0, 1, 1.0 / count)]).reshape((-1, 1))
elif title == 'Worse-than-random model':
    # SUB RANDOM: model output decreases from 0 to -1 (worse than random)
    y_score = np.array([-p + np.random.randint(-1000, 1000)/1000
                        for p in np.arange(0, 1, 1.0 / count)]).reshape((-1, 1))

# calculate ROC (fpr, tpr) points
fpr, tpr, thresholds = roc_curve(y_true, y_score)
# calculate recall, precision, and accuracy for corresponding thresholds
# recall = TP / P
recall = np.array([np.sum(y_true[y_score > t])/P
                   for t in thresholds]).reshape((-1, 1))
# precision = TP / (TP + FP)
precision = np.array([np.sum(y_true[y_score > t])/np.count_nonzero(y_score > t)
                      for t in thresholds]).reshape((-1, 1))
# accuracy = (TP + TN) / (P + N)
accuracy = np.array([(np.sum(y_true[y_score > t]) + np.sum(1 - y_true[y_score < t]))
                     /len(y_score)
                      for t in thresholds]).reshape((-1, 1))

# Sort performance measures from min tpr to max tpr
index = np.argsort(tpr)
tpr_sorted = tpr[index]
recall_sorted = recall[index]
precision_sorted = precision[index]
accuracy_sorted = accuracy[index]

# visualize
fig, ax = pyplot.subplots(3, 1)
fig.suptitle(title, fontsize=12)

line = np.arange(0, len(thresholds))/len(thresholds)
ax[0].plot(fpr, tpr, label='ROC', color='purple')
ax[0].plot(line, line, '--', label='random', color='black')
ax[0].set_xlabel('fpr')
ax[0].legend(loc='center left', bbox_to_anchor=(1, 0.5))
ax[1].plot(line, recall, label='recall', color='blue')
ax[1].plot(line, precision, label='precision', color='red')
ax[1].plot(line, accuracy, label='accuracy', color='black')
ax[1].set_xlabel('1 - threshold')
ax[1].legend(loc='center left', bbox_to_anchor=(1, 0.5))
ax[2].plot(tpr_sorted, recall_sorted, label='recall', color='blue')
ax[2].plot(tpr_sorted, precision_sorted, label='precision', color='red')
ax[2].plot(tpr_sorted, accuracy_sorted, label='accuracy', color='black')
ax[2].set_xlabel('tpr (1 - fnr)')
ax[2].legend(loc='center left', bbox_to_anchor=(1, 0.5))

fig.tight_layout()
fig.subplots_adjust(top=0.88)
pyplot.show()

你是对的@Tolga,两者都可以同时增加。考虑以下数据:

Prediction | True Class
       1.0 | 0
       0.5 | 1
       0.0 | 0

如果您将截止点设置为 0.75,那么您有

Precision=TPTP+FP=00+1=0
Recall=TPTP+FN=00+1=0

那么如果你将截止点降低到 0.25,你有

Precision=TPTP+FP=11+1=0.5
Recall=TPTP+FN=11+0=1

所以你可以看到,当我们减少假阴性的数量时,准确率和召回率都增加了。

感谢您清楚地说明问题。关键是,如果你想减少假阴性,你应该充分降低你的决策函数的阈值。正如您所提到的,如果假阴性减少,真阳性会增加,但假阳性也会增加。结果,召回率会增加,而准确率会降低。