【问题标题】:How to compute precision, recall, accuracy and f1-score for the multiclass case with scikit learn?如何使用 scikit learn 计算多类案例的精度、召回率、准确率和 f1 分数?
【发布时间】:2015-10-03 23:06:54
【问题描述】:

我正在处理一个情绪分析问题,数据如下所示:

label instances
    5    1190
    4     838
    3     239
    1     204
    2     127

所以我的数据是不平衡的,因为 1190 instances 被标记为 5。对于分类我使用 scikit 的SVC。问题是我不知道如何以正确的方式平衡我的数据,以便准确计算多类案例的精度、召回率、准确率和 f1 分数。所以我尝试了以下方法:

第一:

    wclf = SVC(kernel='linear', C= 1, class_weight={1: 10})
    wclf.fit(X, y)
    weighted_prediction = wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, weighted_prediction)
print 'F1 score:', f1_score(y_test, weighted_prediction,average='weighted')
print 'Recall:', recall_score(y_test, weighted_prediction,
                              average='weighted')
print 'Precision:', precision_score(y_test, weighted_prediction,
                                    average='weighted')
print '\n clasification report:\n', classification_report(y_test, weighted_prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, weighted_prediction)

第二:

auto_wclf = SVC(kernel='linear', C= 1, class_weight='auto')
auto_wclf.fit(X, y)
auto_weighted_prediction = auto_wclf.predict(X_test)

print 'Accuracy:', accuracy_score(y_test, auto_weighted_prediction)

print 'F1 score:', f1_score(y_test, auto_weighted_prediction,
                            average='weighted')

print 'Recall:', recall_score(y_test, auto_weighted_prediction,
                              average='weighted')

print 'Precision:', precision_score(y_test, auto_weighted_prediction,
                                    average='weighted')

print '\n clasification report:\n', classification_report(y_test,auto_weighted_prediction)

print '\n confussion matrix:\n',confusion_matrix(y_test, auto_weighted_prediction)

第三:

clf = SVC(kernel='linear', C= 1)
clf.fit(X, y)
prediction = clf.predict(X_test)


from sklearn.metrics import precision_score, \
    recall_score, confusion_matrix, classification_report, \
    accuracy_score, f1_score

print 'Accuracy:', accuracy_score(y_test, prediction)
print 'F1 score:', f1_score(y_test, prediction)
print 'Recall:', recall_score(y_test, prediction)
print 'Precision:', precision_score(y_test, prediction)
print '\n clasification report:\n', classification_report(y_test,prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, prediction)


F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1082: DeprecationWarning: The default `weighted` averaging is deprecated, and from version 0.18, use of precision, recall or F-score with multiclass or multilabel data or pos_label=None will result in an exception. Please set an explicit value for `average`, one of (None, 'micro', 'macro', 'weighted', 'samples'). In cross validation use, for instance, scoring="f1_weighted" instead of scoring="f1".
  sample_weight=sample_weight)
 0.930416613529

但是,我收到这样的警告:

/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:1172:
DeprecationWarning: The default `weighted` averaging is deprecated,
and from version 0.18, use of precision, recall or F-score with 
multiclass or multilabel data or pos_label=None will result in an 
exception. Please set an explicit value for `average`, one of (None, 
'micro', 'macro', 'weighted', 'samples'). In cross validation use, for 
instance, scoring="f1_weighted" instead of scoring="f1"

如何正确处理我的不平衡数据,以便以正确的方式计算分类器的指标?

【问题讨论】:

  • 那么为什么不在第三种情况下添加average参数呢?
  • @yangjie 我不知道。我只是检查文档,但我不明白如何正确使用不平衡数据的指标。你能提供一些更广泛的解释和一个例子吗?谢谢!

标签: python machine-learning nlp artificial-intelligence scikit-learn


【解决方案1】:

我认为对于哪些权重用于什么目的存在很多混淆。我不确定我是否确切地知道是什么困扰着你,所以我将讨论不同的主题,请耐心等待;)。

类权重

class_weight 参数的权重用于训练分类器。 它们不会用于计算您正在使用的任何指标:对于不同的类权重,数字会因为分类器不同而不同。

基本上,在每个 scikit-learn 分类器中,类权重用于告诉您的模型一个类的重要性。这意味着在训练过程中,分类器会付出额外的努力来正确分类具有高权重的类。
他们如何做到这一点是特定于算法的。如果您想详细了解 SVC 的工作原理,并且该文档对您没有意义,请随时提及。

指标

一旦有了分类器,您就想知道它的性能如何。 在这里您可以使用您提到的指标:accuracyrecall_scoref1_score...

通常当类别分布不平衡时,准确率被认为是一个糟糕的选择,因为它为仅预测最频繁类别的模型提供高分。

我不会详细说明所有这些指标,但请注意,除了accuracy,它们自然地应用于类级别:正如您在分类报告的print 中看到的,它们是为每个类定义的.它们依赖于诸如 true positivesfalse negative 之类的概念,这些概念需要定义哪个类是类。

             precision    recall  f1-score   support

          0       0.65      1.00      0.79        17
          1       0.57      0.75      0.65        16
          2       0.33      0.06      0.10        17
avg / total       0.52      0.60      0.51        50

警告

F1 score:/usr/local/lib/python2.7/site-packages/sklearn/metrics/classification.py:676: DeprecationWarning: The 
default `weighted` averaging is deprecated, and from version 0.18, 
use of precision, recall or F-score with multiclass or multilabel data  
or pos_label=None will result in an exception. Please set an explicit 
value for `average`, one of (None, 'micro', 'macro', 'weighted', 
'samples'). In cross validation use, for instance, 
scoring="f1_weighted" instead of scoring="f1".

您收到此警告是因为您使用的是 f1 分数、召回率和精度,而没有定义它们的计算方式! 这个问题可以换个说法:从上面的分类报告中,你如何为 f1-score 输出 一个 全局数字? 你可以:

  1. 取每个类的 f1-score 的平均值:这就是上面的avg / total 结果。它也称为平均。
  2. 使用真阳性/假阴性等的全局计数计算 f1 分数(您将每个类别的真阳性/假阴性数相加)。又名平均。
  3. 计算 f1 分数的加权平均值。在 scikit-learn 中使用 'weighted' 将通过类的支持来衡量 f1-score:类的元素越多,该类在计算中的 f1-score 越重要。

这些是 scikit-learn 中的 3 个选项,警告是说你必须选择一个。所以你必须为 score 方法指定一个average 参数。

您选择哪一个取决于您希望如何衡量分类器的性能:例如,宏观平均不考虑类别不平衡,类别 1 的 f1-score 将与 f1- 一样重要第 5 类的分数。但是,如果您使用加权平均,则对第 5 类的重要性会更高。

这些指标中的整个参数规范目前在 scikit-learn 中还不是很清楚,根据文档,它会在 0.18 版中变得更好。他们正在删除一些不明显的标准行为,并发出警告,以便开发人员注意到它。

计算分数

我要提到的最后一件事(如果您知道,可以跳过它)是,只有在分类器从未见过的数据上计算分数时,分数才有意义。 这一点非常重要,因为您在用于拟合分类器的数据上获得的任何分数都是完全不相关的。

这是一种使用StratifiedShuffleSplit 的方法,它为您提供数据的随机拆分(在改组后),以保留标签分布。

from sklearn.datasets import make_classification
from sklearn.cross_validation import StratifiedShuffleSplit
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, classification_report, confusion_matrix

# We use a utility to generate artificial classification data.
X, y = make_classification(n_samples=100, n_informative=10, n_classes=3)
sss = StratifiedShuffleSplit(y, n_iter=1, test_size=0.5, random_state=0)
for train_idx, test_idx in sss:
    X_train, X_test, y_train, y_test = X[train_idx], X[test_idx], y[train_idx], y[test_idx]
    svc.fit(X_train, y_train)
    y_pred = svc.predict(X_test)
    print(f1_score(y_test, y_pred, average="macro"))
    print(precision_score(y_test, y_pred, average="macro"))
    print(recall_score(y_test, y_pred, average="macro"))    

希望这会有所帮助。

【讨论】:

  • 对于多类,如何指定类权重?例如,class_weight={1:10} 对于具有 3 个类的数据意味着什么?
  • 有没有办法获得标签准确度分数?
  • 你能更清楚地解释一下 micro 的工作原理吗?你也没有提到任何关于二进制的内容
  • 对我来说,分层洗牌会造成问题,所以我切换回训练测试拆分,因为它显示 ValueError: The least populated class in y has only 1 member, which is too few. The minimum number of labels for any class cannot be less than 2.。它在训练测试拆分中运行良好,但任何人都可以帮助我为什么我收到 SSS 的这个错误?谢谢。
  • 您好我测试了您的代码,但我收到此错误消息 C:\Users\\Anaconda3\lib\site-packages\sklearn\metrics\classification.py:976: DeprecationWarning: From version 0.18, binary使用平均精度/召回率/F-score 时,不会对输入进行特殊处理。请使用 average='binary' 仅报告积极的班级表现。 “积极的课堂表现。”,弃用警告)
【解决方案2】:

这里有很多非常详细的答案,但我认为您没有回答正确的问题。据我了解这个问题,有两个问题:

  1. 如何为多类问题评分?
  2. 如何处理不平衡的数据?

1.

您可以使用 scikit-learn 中的大多数评分函数来处理多类问题和单类问题。例如:

from sklearn.metrics import precision_recall_fscore_support as score

predicted = [1,2,3,4,5,1,2,1,1,4,5] 
y_test = [1,2,3,4,5,1,2,1,1,4,1]

precision, recall, fscore, support = score(y_test, predicted)

print('precision: {}'.format(precision))
print('recall: {}'.format(recall))
print('fscore: {}'.format(fscore))
print('support: {}'.format(support))

通过这种方式,您最终会为每个类获得有形且可解释的数字。

| Label | Precision | Recall | FScore | Support |
|-------|-----------|--------|--------|---------|
| 1     | 94%       | 83%    | 0.88   | 204     |
| 2     | 71%       | 50%    | 0.54   | 127     |
| ...   | ...       | ...    | ...    | ...     |
| 4     | 80%       | 98%    | 0.89   | 838     |
| 5     | 93%       | 81%    | 0.91   | 1190    |

那么……

2.

...您可以判断不平衡的数据是否是一个问题。如果代表较少的类(第 1 类和第 2 类)的得分低于具有更多训练样本的类(第 4 类和第 5 类),那么您知道不平衡数据实际上是一个问题,您可以采取相应的行动,如在此线程的其他一些答案中进行了描述。 但是,如果您要预测的数据中存在相同的类分布,那么您的不平衡训练数据可以很好地代表数据,因此,不平衡是一件好事。

【讨论】:

  • 很棒的帖子,说得好。谢谢
  • 嘿只是一个后续问题:您是如何使用precision_recall_fscore_support 打印标签的?标签是按订单打印的吗?
  • @BigD 是的,请参阅最底部的scikit-learn.org/stable/modules/generated/…。设置 average=None 并定义标签,然后您就可以为每个指定的标签获得您正在寻找的指标。
  • 有没有办法获得标签准确度分数?
  • @trollster 我不确定你的意思?我在答案标签准确度分数中显示的不是吗?
【解决方案3】:

提出的问题

回答“对于不平衡数据的多类分类应该使用什么度量标准”这个问题:Macro-F1-measure。 也可以使用 Macro Precision 和 Macro Recall,但它们不像二元分类那样容易解释,它们已经被纳入 F-measure,过多的指标使方法比较、参数调整等变得复杂。

微平均对类别不平衡很敏感:例如,如果您的方法对最常见的标签效果很好并且完全搞砸了其他标签,那么微平均指标显示出良好的结果。

加权平均不太适合不平衡的数据,因为它按标签计数加权。此外,它太难以解释和不受欢迎:例如,在下面非常详细的survey 中没有提到这种平均,我强烈建议您仔细阅读:

索科洛娃、玛丽娜和盖伊·拉帕尔梅。 “系统分析 分类任务的性能度量。” 信息处理 与管理 45.4 (2009): 427-437。

应用特定问题

但是,回到你的任务,我会研究 2 个主题:

  1. 通常用于您的特定任务的指标 - 它允许 (a) 将您的方法与他人进行比较并了解您是否做了某事 错误,并且(b)不要自己探索并重用某人 其他人的调查结果;
  2. 您的方法的不同错误的成本 - 对于 例如,您的应用程序的用例可能依赖于 4 星和 5 星 仅评论 - 在这种情况下,好的指标应该只计算这 2 个 标签。

常用指标。 在查阅文献后我可以推断,有两个主要的评估指标:

  1. Accuracy,用于,例如在

于、April 和 Daryl Chang。 “使用多类情绪预测 Yelp 业务。”

(link) - 请注意,作者使用几乎相同的评分分布,参见图 5。

Pang、Bo 和 Lillian Lee。 《看星星:剥削阶级》 情绪分类与评级的关系 尺度。”第 43 届协会年会论文集 计算语言学。计算语言学协会, 2005.

(link)

  1. MSE(或者,较少见的平均绝对误差 - MAE) - 参见,例如,

Lee、Moontae 和 R. Grafe。 “多类情绪分析 餐厅评论。”来自 CS N 224 (2010) 的最终项目。

(link) - 他们探索准确性和 MSE,认为后者更好

Pappas、Nikolaos、Rue Marconi 和 Andrei Popescu-Belis。 “解释 星星:基于方面的加权多实例学习 情绪分析。” 2014 年实证会议论文集 自然语言处理中的方法。编号 EPFL-CONF-200899。 2014.

(link) - 他们利用 scikit-learn 进行评估和基线方法,并声明他们的代码可用;但是,我找不到,所以如果你需要它,给作者写一封信,这个工作很新,似乎是用 Python 编写的。

不同错误的成本 如果您更关心避免严重错误,例如评估 1 星到 5 星的评论或类似的东西,看看 MSE; 如果差异很重要,但不是那么重要,请尝试 MAE,因为它不会平方差异; 否则请继续使用 Accuracy。

关于方法,而不是指标

尝试回归方法,例如SVR,因为它们通常优于 SVC 或 OVA SVM 等多类分类器。

【讨论】:

    【解决方案4】:

    首先,仅使用计数分析来判断您的数据是否不平衡有点困难。例如:千分之一的积极观察只是噪音、错误还是科学突破?你永远不知道。
    因此,最好利用所有可用的知识并明智地选择其状态。

    好的,如果真的不平衡怎么办?
    再一次 - 查看您的数据。有时你可以发现一两次观察乘以一百倍。有时创建这种虚假的一类观察结果很有用。
    如果所有数据都是干净的,下一步是在预测模型中使用类权重。

    那么多类指标呢?
    根据我的经验,通常不使用您的任何指标。有两个主要原因。
    第一:使用概率总是比使用可靠预测更好(因为如果它们都给你相同的类,你怎么能将具有 0.9 和 0.6 预测的模型分开?)
    其次:比较您的预测模型和构建新模型要容易得多,这取决于一个好的指标。
    根据我的经验,我可以推荐 loglossMSE(或者只是均方误差)。

    如何修复 sklearn 警告?
    只是简单地(正如 yangjie 注意到的)用其中之一覆盖 average 参数 值:'micro'(全局计算指标)、'macro'(计算每个标签的指标)或'weighted'(与宏相同,但具有自动权重)。

    f1_score(y_test, prediction, average='weighted')
    

    您的所有警告都是在使用默认 average'binary' 调用指标函数后发出的,这不适合多类预测。
    祝你好运,享受机器学习的乐趣!

    编辑:
    我发现另一个回答者建议切换到我不能同意的回归方法(例如 SVR)。据我所知,甚至没有多类回归之类的东西。是的,多标签回归有很大的不同,是的,在某些情况下可以在回归和分类之间切换(如果类以某种方式排序),但这种情况非常罕见。

    我建议(在 scikit-learn 范围内)尝试另一种非常强大的分类工具:gradient boostingrandom forest(我最喜欢的)、KNeighbors 等等。

    之后,您可以计算预测之间的算术或几何平均值,并且大多数情况下您会得到更好的结果。

    final_prediction = (KNNprediction * RFprediction) ** 0.5
    

    【讨论】:

    • > "在回归和分类之间切换(如果类以某种方式排序)但它非常罕见" 是这样的:5 > 4 > 3 > 2 > 1。我建议你看看在该任务的论文中 - 该任务有许多回归和分类方法(有时在同一个工作中)。
    • 那么它甚至不是一个多类分类而是一个简单的回归。
    • 是的,在内部,或者从 ML 的角度来看,它是一种回归,但在最后一步我们将回归结果转换为标签,所以它是一个多类分类——来自用户或应用程序,观点。
    猜你喜欢
    • 2017-06-21
    • 2012-01-07
    • 2022-12-17
    • 1970-01-01
    • 2019-11-23
    • 1970-01-01
    • 2023-03-29
    • 2015-12-05
    • 2019-09-06
    相关资源
    最近更新 更多