如何标准化混淆矩阵?

问题描述 投票:0回答:9

我使用 scikit-learn 中的

confusion_matrix()
计算了分类器的混淆矩阵。混淆矩阵的对角线元素表示预测标签等于真实标签的点的数量,而非对角线元素是被分类器错误标记的点。

我想标准化我的混淆矩阵,使其仅包含 0 到 1 之间的数字。我想从矩阵中读取正确分类样本的百分比。

我发现了几种如何标准化矩阵(行和列标准化)的方法,但我对数学了解不多,并且不确定这是否是正确的方法。

python machine-learning scikit-learn normalization confusion-matrix
9个回答
45
投票

假设

>>> y_true = [0, 0, 1, 1, 2, 0, 1]
>>> y_pred = [0, 1, 0, 1, 2, 2, 1]
>>> C = confusion_matrix(y_true, y_pred)
>>> C
array([[1, 1, 1],
       [1, 2, 0],
       [0, 0, 1]])

然后,要了解每个类别有多少样本已收到正确的标签,您需要

>>> C / C.astype(np.float).sum(axis=1)
array([[ 0.33333333,  0.33333333,  1.        ],
       [ 0.33333333,  0.66666667,  0.        ],
       [ 0.        ,  0.        ,  1.        ]])

对角线包含所需的值。计算这些的另一种方法是意识到您正在计算的是每个类别的召回率:

>>> from sklearn.metrics import precision_recall_fscore_support
>>> _, recall, _, _ = precision_recall_fscore_support(y_true, y_pred)
>>> recall
array([ 0.33333333,  0.66666667,  1.        ])

类似地,如果除以

axis=0
的总和,您将得到精度(具有真实标签
k
的类
k
预测的分数):

>>> C / C.astype(np.float).sum(axis=0)
array([[ 0.5       ,  0.33333333,  0.5       ],
       [ 0.5       ,  0.66666667,  0.        ],
       [ 0.        ,  0.        ,  0.5       ]])
>>> prec, _, _, _ = precision_recall_fscore_support(y_true, y_pred)
>>> prec
array([ 0.5       ,  0.66666667,  0.5       ])

45
投票

使用 Seaborn,您可以轻松打印带有健康图的标准化且漂亮的混淆矩阵:

enter image description here

from sklearn.metrics import confusion_matrix
import seaborn as sns

cm = confusion_matrix(y_test, y_pred)
# Normalise
cmn = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
fig, ax = plt.subplots(figsize=(10,10))
sns.heatmap(cmn, annot=True, fmt='.2f', xticklabels=target_names, yticklabels=target_names)
plt.ylabel('Actual')
plt.xlabel('Predicted')
plt.show(block=False)

28
投票

如今,scikit-learn 的混淆矩阵带有

normalize
参数;来自文档

标准化:{'true', 'pred', 'all'},默认=无

在真实(行)、预测(列)条件或所有总体上标准化混淆矩阵。如果没有,则混淆矩阵 不会正常化。

因此,如果您希望所有样本的值标准化,您应该使用

confusion_matrix(y_true, y_pred, normalize='all')

26
投票

来自 sklearn 文档 (绘图示例)

cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]

其中 cm 是 sklearn 提供的混淆矩阵。


15
投票

我假设

M[i,j]
代表
Element of real class i was classified as j
。如果相反,你将需要颠倒我所说的一切。我还将使用以下矩阵作为具体示例:

1 2 3
4 5 6
7 8 9

您基本上可以做两件事:

查找每个类别是如何分类的

您可以问的第一件事是真实类别

i
的元素的百分比是多少,这里被分类为每个类别。为此,我们取一行固定
i
并将每个元素除以该行中元素的总和。在我们的示例中,类别 2 中的对象被分类为类别 1 4 次,被正确分类为类别 2 5 次,以及被分类为类别 3 6 次。要找到百分比,我们只需将所有内容除以总和 4 + 5 + 6 = 15

4/15 of the class 2 objects are classified as class 1
5/15 of the class 2 objects are classified as class 2
6/15 of the class 2 objects are classified as class 3

找出哪些类负责每个分类

您可以做的第二件事是查看分类器的每个结果,并询问其中有多少结果来自每个真实的类别。它与其他情况类似,但使用列而不是行。在我们的示例中,当原始类别为 1 时,我们的分类器返回“1”1 次;当原始类别为 2 时,返回 4 次;当原始类别为 3 时,分类器返回 7 次。为了找到百分比,我们除以总和 1 + 4 + 7 = 12

1/12 of the objects classified as class 1 were from class 1
4/12 of the objects classified as class 1 were from class 2
7/12 of the objects classified as class 1 were from class 3

--

当然,我给出的两种方法一次仅适用于单行列,我不确定以这种形式实际修改您的混淆矩阵是否是一个好主意。然而,这应该给出您正在寻找的百分比。


10
投票

sklearn 的

confusion_matrix()
输出的矩阵是 这样

C_{i, j} 等于第 i 组中已知的观测值数量 但预计会在j组

因此,要获得每个类别的百分比(在二元分类中通常称为特异性和敏感性),您需要按行进行归一化:将一行中的每个元素替换为其自身除以该行元素的总和。

请注意,sklearn 有一个可用的汇总函数,可以根据混淆矩阵计算指标:classification_report。它输出精确度和召回率,而不是特异性和敏感性,但这些通常被认为通常提供更多信息(特别是对于不平衡的多类分类)。


5
投票

我认为最简单的方法是这样做:

c = sklearn.metrics.confusion_matrix(y, y_pred)
normed_c = (c.T / c.astype(np.float).sum(axis=1)).T

3
投票

scikit-learn 本身提供了一个用于绘制图表的库。它基于 matplotlib,应该已经安装才能继续。

pip install scikit-plot

现在,只需将 normalize 参数设置为 true:

import scikitplot as skplt 
skplt.metrics.plot_confusion_matrix(Y_TRUE, Y_PRED, normalize=True)

0
投票

对于您有TOTALS的情况。像这样的东西:

             0        1         2     Total
0      5434084      567      3460   5438111
1       458896  4717484    115297   5291677
2       189553     8305  13962602  14160460
Total  6082533  4726356  14081359  24890248

我的解决方案是:

cm = (cm.astype('float').T / cm.drop('Total', axis=1).sum(axis=1)).T

© www.soinside.com 2019 - 2024. All rights reserved.