Scikit-learn,获取每个类的准确度分数

Posted

技术标签:

【中文标题】Scikit-learn,获取每个类的准确度分数【英文标题】:Scikit-learn, get accuracy scores for each class 【发布时间】:2017-02-07 18:48:45 【问题描述】:

是否有内置方法可以分别获取每个班级的准确度分数?我知道在 sklearn 中,我们可以使用metric.accuracy_score 获得整体准确性。有没有办法获得各个班级的准确度分数细分?类似于metrics.classification_report

from sklearn.metrics import classification_report
from sklearn.metrics import accuracy_score

y_true = [0, 1, 2, 2, 2]
y_pred = [0, 0, 2, 2, 1]
target_names = ['class 0', 'class 1', 'class 2']

classification_report 不给出准确度分数:

print(classification_report(y_true, y_pred, target_names=target_names, digits=4))

Out[9]:         precision    recall  f1-score   support

class 0     0.5000    1.0000    0.6667         1
class 1     0.0000    0.0000    0.0000         1
class 2     1.0000    0.6667    0.8000         3

avg / total     0.7000    0.6000    0.6133         5

准确度分数仅给出整体准确度:

accuracy_score(y_true, y_pred)
Out[10]: 0.59999999999999998

【问题讨论】:

【参考方案1】:
from sklearn.metrics import confusion_matrix
y_true = [2, 0, 2, 2, 0, 1]
y_pred = [0, 0, 2, 2, 0, 2]
matrix = confusion_matrix(y_true, y_pred)
matrix.diagonal()/matrix.sum(axis=1)

【讨论】:

详细说明,假设列(因此这个答案的“axis = 1”)代表实际类,而行代表预测类,第 i 类的准确度是混淆矩阵的第 ii 个元素第 i 列的总和。数学就是这样计算的。 这个link 很好地解释了混淆矩阵。 我相信这段代码可能不正确。 sklearn.metrics.confusion_matrix 将该行作为实际的类。所以我们应该改用axis=0 这不就相当于precisio吗?如果你axis=0,你会得到召回吗?【参考方案2】:

你可以使用sklearn的confusion matrix来获取准确率

from sklearn.metrics import confusion_matrix
import numpy as np

y_true = [0, 1, 2, 2, 2]
y_pred = [0, 0, 2, 2, 1]
target_names = ['class 0', 'class 1', 'class 2']

#Get the confusion matrix
cm = confusion_matrix(y_true, y_pred)
#array([[1, 0, 0],
#   [1, 0, 0],
#   [0, 1, 2]])

#Now the normalize the diagonal entries
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
#array([[1.        , 0.        , 0.        ],
#      [1.        , 0.        , 0.        ],
#      [0.        , 0.33333333, 0.66666667]])

#The diagonal entries are the accuracies of each class
cm.diagonal()
#array([1.        , 0.        , 0.66666667])

参考文献

plot Confusion matrix sklearn

【讨论】:

计算的不是准确率,而是召回率。 不,在文档中确实如此,它声明 scikit-learn.org/stable/modules/generated/… [1] 混淆矩阵的***条目(***和其他参考资料可能对轴使用不同的约定) 提示:对于 sklearn>=0.22 使用 confusion_matrix(..., normalize="true").diagonal() 直接计算每个类的准确率。 @strohne 好像混淆矩阵还不够混淆,不要让它变得更糟:) 上面正确计算了每类准确率,即每类正确分类样本的比率。召回率是正类的每类准确率,不应与整体准确率(所有类的正确预测的比率)混淆。整体准确率可以计算为confusion_matrix(..., normalize="all").diagonal().sum() 对于多类分类,每类准确率与每类召回率相同。【参考方案3】:

您可以自己编码:准确率无非是分类良好的样本(真阳性和真阴性)与您拥有的样本总数之间的比率。

然后,对于给定的班级,您无需考虑所有样本,而只考虑您班级的样本。

然后你可以试试这个: 我们先定义一个方便的函数。

def indices(l, val):
   retval = []
   last = 0
   while val in l[last:]:
           i = l[last:].index(val)
           retval.append(last + i)
           last += i + 1   
   return retval

上面的函数会返回列表l中某个值val

的索引
def class_accuracy(y_pred, y_true, class):
    index = indices(l, class)
    y_pred, y_true = ypred[index], y_true[index]
    tp = [1 for k in range(len(y_pred)) if y_true[k]==y_pred[k]]
    tp = np.sum(tp)
    return tp/float(len(y_pred))

最后一个函数将返回您寻找的类内准确度。

【讨论】:

我不知道 numpy 中是否有一个现有函数可以返回列表中与您的参数匹配的值的索引。有人有想法吗?非常感谢! 第二个函数使用未定义的“l”。再次分配 y_true 和 y_pred 时还有一种类型。 (但我赞成它,因为它是这里唯一正确的答案)【参考方案4】:

我正在添加我的答案,因为我没有在网上找到这个确切问题的任何答案,并且因为我认为我之前建议的其他计算方法是不正确的。

记住准确度定义为:

accuracy = (true_positives + true_negatives) / all_samples

或者说成文字;它是正确分类的示例(正面或负面)的数量与测试集中示例总数之间的比率。

需要注意的重要一点是,对于 TN 和 FN,“否定”与类别无关,意思是“未预测为有问题的特定类别”。例如,考虑以下情况:

y_true = ['cat', 'dog', 'bird', 'bird]
y_pred = ['cat', 'dog', 'cat', 'dog']

这里,第二个“猫”预测和第二个“狗”预测都是假阴性,因为它们不是“鸟”。

你的问题:

据我所知,目前还没有包提供可以满足您要求的方法,但根据准确度的定义,我们可以使用 sklearn 的混淆矩阵方法自行计算。

from sklearn.metrics import confusion_matrix
import numpy as np

# Get the confusion matrix
cm = confusion_matrix(y_true, y_pred)

# We will store the results in a dictionary for easy access later
per_class_accuracies = 

# Calculate the accuracy for each one of our classes
for idx, cls in enumerate(classes):
    # True negatives are all the samples that are not our current GT class (not the current row) 
    # and were not predicted as the current class (not the current column)
    true_negatives = np.sum(np.delete(np.delete(cm, idx, axis=0), idx, axis=1))
    
    # True positives are all the samples of our current GT class that were predicted as such
    true_positives = cm[idx, idx]
    
    # The accuracy for the current class is ratio between correct predictions to all predictions
    per_class_accuracies[cls] = (true_positives + true_negatives) / np.sum(cm)

最初的问题是不久前发布的,但这可能会帮助像我这样通过 Google 来到这里的任何人。

【讨论】:

【参考方案5】:

你的问题毫无意义。准确度是一个全球性的衡量标准,没有分类准确度之类的东西。根据具体情况,通过真实案例(行)进行标准化的建议会产生所谓的真阳性率、敏感性或召回率。同样,如果您通过预测(列)进行归一化,则称为精度或正预测值。

【讨论】:

是的,我不认为有一种称为“每类”准确性的度量。因为在数学上它没有意义。准确率定义为(TP + TN) / total_population,问题是如何计算“特定类的总人口”【参考方案6】:

这个问题具有误导性。每个类别的准确度分数等于总体准确度分数。考虑混淆矩阵:

from sklearn.metrics import confusion_matrix
import numpy as np

y_true = [0, 1, 2, 2, 2]
y_pred = [0, 0, 2, 2, 1]

#Get the confusion matrix
cm = confusion_matrix(y_true, y_pred)
print(cm)

这给了你:

 [[1 0 0]
  [1 0 0]
  [0 1 2]]

准确率计算为正确分类的样本占所有样本的比例:

accuracy = (TP + TN) / (P + N)

关于混淆矩阵,分子(TP + TN)是对角线的和。分母是所有单元格的总和。每个班级都一样。

【讨论】:

【参考方案7】:

在我看来,准确性是具有不同维度的通用术语,例如精度、召回率、f1 分数(甚至是特异性、灵敏度)等,提供不同角度的准确度度量。因此,函数“classification_report”为每个类输出一系列准确度度量。例如,精度提供了准确检索到的实例(即真阳性)与特定类中可用的实例总数(真阳性和假阴性)的比例。

【讨论】:

嗨,Md Abdul Bari,欢迎来到 Stack Overflow!我完全同意你的回复。尽管它没有回答 CentAu 提出的问题,但不能强调有许多具有不同含义的准确度指标。 我强烈反对。准确性是非常标准化的术语。当然,您可以在不同的上下文中粗略地谈论准确性,但对于分类,它具有非常具体、定义明确的含义。【参考方案8】:

这里是解决方案兄弟:

def classwise_accuracy():
   a = pd.crosstab(y_test,predict_over)
   print(a.max(axis=1)/a.sum(axis=1))
classwise_accuracy()

【讨论】:

以上是关于Scikit-learn,获取每个类的准确度分数的主要内容,如果未能解决你的问题,请参考以下文章

为啥 scikit-learn SVM 分类器交叉验证这么慢?

在 scikit-learn 中获得二元概率分类器的最大准确度

如何获得每个 rfecv 分数的特征索引?

在 scikit-learn 中获取每个亲和传播集群的***术语

如何使用 Python (scikit-learn) 计算 FactorAnalysis 分数?

如何在 scikit-learn 中计算正确的交叉验证分数?