Scikit-learn混淆矩阵

38

我无法确定是否正确设置了我的二元分类问题。我将正类标记为1,负类标记为0。然而,据我了解,默认情况下scikit-learn在混淆矩阵中使用类别0作为正类(与我的设置相反)。这让我感到困惑。在scikit-learn的默认设置中,顶行是正类还是负类呢?假设混淆矩阵输出如下:

confusion_matrix(y_test, preds)
 [ [30  5]
    [2 42] ]

在混淆矩阵中会是什么样子?在scikit-learn中,实际实例是行还是列?

          prediction                        prediction
           0       1                          1       0
         -----   -----                      -----   -----
      0 | TN   |  FP        (OR)         1 |  TP  |  FP
actual   -----   -----             actual   -----   -----
      1 | FN   |  TP                     0 |  FN  |  TN
5个回答

44

Scikit-learn按升序排序标签,因此0是第一列/行,而1是第二列/行。

>>> from sklearn.metrics import confusion_matrix as cm
>>> y_test = [1, 0, 0]
>>> y_pred = [1, 0, 0]
>>> cm(y_test, y_pred)
array([[2, 0],
       [0, 1]])
>>> y_pred = [4, 0, 0]
>>> y_test = [4, 0, 0]
>>> cm(y_test, y_pred)
array([[2, 0],
       [0, 1]])
>>> y_test = [-2, 0, 0]
>>> y_pred = [-2, 0, 0]
>>> cm(y_test, y_pred)
array([[1, 0],
       [0, 2]])
>>> 

这段文字来自于文档

labels:数组,形状为[n_classes],可选 用于索引矩阵的标签列表。这可以用于重新排序或选择标签子集。如果未提供,则使用在y_true或y_pred中至少出现一次的标签以排序顺序

因此,您可以通过向confusion_matrix调用提供标签来改变此行为。

>>> y_test = [1, 0, 0]
>>> y_pred = [1, 0, 0]
>>> cm(y_test, y_pred)
array([[2, 0],
       [0, 1]])
>>> cm(y_test, y_pred, labels=[1, 0])
array([[1, 0],
       [0, 2]])

实际值/预测值的排列方式与您的图片中一样 - 预测在列中,实际值在行中。

>>> y_test = [5, 5, 5, 0, 0, 0]
>>> y_pred = [5, 0, 0, 0, 0, 0]
>>> cm(y_test, y_pred)
array([[3, 0],
       [2, 1]])
  • 真实值: 0,预测值: 0(数值为3,位置[0, 0])
  • 真实值: 5,预测值: 0(数值为2,位置[1, 0])
  • 真实值: 0,预测值: 5(数值为0,位置[0, 1])
  • 真实值: 5,预测值: 5(数值为1,位置[1, 1])

8

支持的回答:

在使用sklearn.metrics绘制混淆矩阵值时,请注意值的顺序为

[真负 假正] [假负 真正]

如果您错误地解释了这些值,例如将TN解释为TP,则您的准确性和AUC_ROC指标可能会基本匹配,但您的精度、召回率、敏感性和f1-score会受到影响,您将得到完全不同的指标。这将导致您对模型性能做出错误判断。

请务必清楚地确定模型中的1和0代表什么。这严重影响混淆矩阵的结果。

经验:

我曾经在预测欺诈(二元有监督分类)方面工作,其中欺诈由1表示,非欺诈由0表示。我的模型是在缩放、完美平衡的数据集上训练的,因此在实时测试期间,混淆矩阵的值似乎没有问题,当我的结果为[TP FP] [FN TN]的顺序时。

后来,当我需要在一个新的不平衡测试集上进行超时测试时,我意识到混淆矩阵的顺序是错误的,并且与sklearn文档页面中提到的顺序tn,fp,fn,tp不同。插入新的顺序让我认识到这个错误和它对我的模型性能判断所造成的巨大影响。


6

仿照wikipedia的例子,如果一个分类系统已经训练好了区分猫和非猫的能力,混淆矩阵将总结测试算法的结果以供进一步检查。假设有27只动物样本——8只猫和19只非猫,得到的混淆矩阵可能如下表所示:

enter image description here

使用sklearn

如果您想保持维基百科混淆矩阵的结构,首先查看预测值,然后是实际类别。

from sklearn.metrics import confusion_matrix
y_true = [0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,1,0,1,0,0,0,0]
y_pred = [0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0]
confusion_matrix(y_pred, y_true, labels=[1,0])

Out[1]: 
array([[ 5,  2],
       [ 3, 17]], dtype=int64)

另一种使用 pandas 交叉表的方法。
true = pd.Categorical(list(np.where(np.array(y_true) == 1, 'cat','non-cat')), categories = ['cat','non-cat'])
pred = pd.Categorical(list(np.where(np.array(y_pred) == 1, 'cat','non-cat')), categories = ['cat','non-cat'])

pd.crosstab(pred, true, 
            rownames=['pred'], 
            colnames=['Actual'], margins=False, margins_name="Total")

Out[2]: 
Actual   cat  non-cat
pred                 
cat        5        2
non-cat    3       17

2
天哪!sklearn 的 confusion_matrix 函数是 confusion_matrix(y_true, y_pred)。你把参数写反了!我也喜欢维基百科中的混淆矩阵结构,但 labels=[1,0] 只会给出一个(令人困惑的)转置。 - SYK

4

简短回答 在二元分类中,当使用参数labels时,模型期望标签从0开始递增(例如[0, 1])。

confusion_matrix([0, 1, 0, 1], [1, 1, 1, 0], labels=[0,1]).ravel()

类别标签01分别被认为是负面正面的。这是由于列表所暗示的顺序,而不是字母数字顺序。


验证: 考虑这样的不平衡类别标签:(使用不平衡类别使区分更容易)

>>> y_true = [0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0]
>>> y_pred = [0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0]
>>> table = confusion_matrix(y_true, y_pred, labels=[0,1]).ravel()

这将为您提供以下混淆矩阵表格:
>>> table
array([12,  1,  2,  1])

对应于:

              Actual
        |   1   |   0  |
     ___________________
pred  1 |  TP=1 | FP=1 |
      0 |  FN=2 | TN=12|

其中 FN=2 意味着有 2 个样本被模型预测为负类(即 0),但实际标签是正类(即 1),因此假阴性等于 2。

同样地,对于 TN=12,在 12 个样本中,模型正确预测了负类(0),因此真阴性等于 12。

这样一来,所有内容都能够相互匹配,假设 sklearn 将标签列表中的第一个标签(即 labels=[0,1])视为负类。因此,在这里,第一个标签 0 表示负类。


1
我认为我们在称呼“正/负”时所做的决定是一种选择,并且sklearn并不知道这一点。您可以按任何方式标记数据点(不仅限于0和1),因此您的陈述“sklearn使用0作为'正'”或反之亦然根本不成立。
如果您未明确使用“labels”参数来指定行和列标签的顺序,则sklearn将按字母数字顺序对其进行排序。因此,您可以以任何想要的方式输出混淆矩阵,并且您可以决定在最简单的二进制情况下称呼“正/负”的方式。sklearn不会为您做出这些决定。

对于混淆矩阵来说是正确的,但要注意有些指标会为你做出决策,至少f1_score、precision_score和recall_score都有一个参数pos_label,默认值为1。而混淆矩阵和对称指标则没有这个参数。 - petsol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接