Python:如何规范混淆矩阵?

时间:2014-01-04 22:10:34

标签: python matrix normalization scikit-learn

我使用sklearn包中的confusion_matrix()方法为我的分类器计算了一个混淆矩阵。混淆矩阵的对角元素表示预测标签等于真实标签的点数,而非对角元素是分类器错误标记的元素。

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

我找到了几种方法来规范化矩阵(行和列标准化),但我对数学知之甚少,并且不确定这是否是正确的方法。有人可以帮忙吗?

8 个答案:

答案 0 :(得分:19)

假设

>>> 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       ])

答案 1 :(得分:7)

我假设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

-

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

答案 2 :(得分:7)

sklearn的confusion_matrix()输出的矩阵为such that

  

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

因此,要获得每个类的百分比(通常称为二进制分类中的特异性和灵敏度),您需要按行进行标准化:将行中的每个元素替换为该行的元素总和。

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

答案 3 :(得分:7)

来自sklearn文档(plot example)

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

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

答案 4 :(得分:4)

如今,scikit-learn 的混淆矩阵带有 normalize 参数;来自docs

<块引用>

规范化:{'true', 'pred', 'all'}, default=None

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

因此,如果您希望对所有样本进行标准化,则应使用

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

答案 5 :(得分:2)

使用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)

答案 6 :(得分:0)

scikit-learn本身提供了一个用于绘制图形的库。它基于matplotlib,应该已经安装好以继续进行操作。

pip install scikit-plot

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

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

答案 7 :(得分:0)

我认为最简单的方法是:

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