【问题标题】:Scikit-learn, get accuracy scores for each classScikit-learn,获取每个类的准确度分数
【发布时间】: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

【问题讨论】:

    标签: python machine-learning scikit-learn


    【解决方案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])
    

    参考文献

    【讨论】:

    • 计算的不是准确率,而是召回率。
    • 不,在文档中确实如此,它声明 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()
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-11-24
          • 2017-05-18
          • 2015-10-07
          • 2014-04-14
          • 2015-10-12
          • 2019-11-18
          • 2016-06-18
          • 1970-01-01
          相关资源
          最近更新 更多