如何计算精确度,召回,准确度和 f1得分的多类情况与 scikit 学习?

我在研究一个情绪分析问题,数据是这样的:

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"

我怎样才能正确处理我的不平衡的数据,以正确的方式计算分类器的指标?

273476 次浏览

首先,仅仅使用计数分析来判断数据是否不平衡有点困难。例如: 1在1000积极观察只是一个噪音,错误或科学的突破?谁知道呢。
因此,最好是利用你所有的可用知识和选择它的地位与所有的智慧。

好吧,如果真的很不平衡呢?
再说一次,看看你的数据。有时候你可以发现一两个观察结果乘以百倍。有时创建这种假的一类观察是有用的。
如果所有的数据是干净的下一步是使用类权重的预测模型。

那么多类度量呢?
根据我的经验,你的指标没有一个是经常使用的。
首先: 使用概率总是比使用可靠的预测更好(因为如果它们都给你同样的类,你怎么能够将0.9和0.6的预测模型分开呢?)
第二: 比较您的预测模型并根据一个好的度量标准建立新的预测模型要容易得多。
根据我的经验,我可以推荐 失去原木或者 MSE(或者仅仅是均方差)。

如何修复 sklearn 警告?
只需要(像杨洁注意到的那样)用其中之一覆盖 average参数即可 值: 'micro'(计算全局指标) ,'macro'(计算每个标签的指标)或 'weighted'(与宏相同,但使用自动加权)。

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

所有的警告都是在调用默认 average'binary'的度量函数之后发出的,这对于多类预测来说是不合适的。
祝你机器学习好运,玩得开心!

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

我建议(在 scikit-learn 的范围内)尝试另一种非常强大的分类工具: 梯度提升随机森林(我的最爱)、 邻居等等。

之后,你可以计算算术或几何平均之间的预测和大多数时候,你会得到更好的结果。

final_prediction = (KNNprediction * RFprediction) ** 0.5

提问

回答“对于不平衡数据的多类分类应该使用什么度量”的问题: 宏观 F1度量。 宏精度和宏回忆也可以使用,但是它们不像二进制分类那样容易解释,它们已经被合并到 F 度量中,并且过多的度量使方法比较、参数调整等复杂化。

微平均对类不平衡很敏感: 例如,如果您的方法对最常见的标签有效,而对其他标签则完全混乱,那么微平均指标将显示良好的结果。

加权平均不太适合于不平衡的数据,因为它是通过标签计数来加权的。此外,它很难解释,也不受欢迎: 例如,我强烈建议浏览以下非常详细的 调查中没有提到这种平均数:

索科洛娃,玛丽娜和盖伊拉帕尔梅 分类任务的绩效评估”,《信息处理》 及管理45.4(2009) : 427-437。

专门针对应用程序的问题

然而,回到你的任务,我会研究两个主题:

  1. 指标通常用于您的特定任务-它让(a) 把你的方法和别人比较一下,看看你是否做了什么 错误的,(b)不要自己探索这一点,并重复使用某人 其他人的发现;
  2. 方法的不同错误的代价 例如,应用程序的用例可能依赖于4星和5星 只评论-在这种情况下,好的度量标准应该只计算这2个 标签。

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

  1. 精度 ,用于

Yu April 和 Daryl Chang“多阶段情绪预测使用 Yelp Business”

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

彭,波,李,“看星星: 剥削阶级 情绪分类与评级的关系 第四十三届香港中华总商会周年会议记录 计算语言学计算机语言学协会 二零零五年。

(链接)

  1. MSE (或者不太常见的平均绝对误差 -MAE < a href = “ http://scikit-Learn.org/stat/module/generated/skLearn.metrics.mean _ Absol_ error.html”> MAE )-例如,

李,孟太,和 R。格拉夫。“多级情绪分析与 食肆评论》(CSN 224(2010)的期末专题。

(链接)-他们探索精确性和 MSE,认为后者更好

Pappas,Nikolaos,Rue Marconi,和 Andrei Popescu-Belis 星星: 基于方面的加权多示例学习 《情绪分析》2014年经验研究会议论文集 自然语言处理中的方法,编号: EPFL-CONF-200899.2014。

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

不同错误的成本。 如果你更关心避免严重的错误,例如给一星到五星的评价或类似的东西,看看 MSE; 如果差异很重要,但不那么重要,试试 MAE,因为它不是平方差; 否则就继续保持精准。

关于方法,而不是度量

尝试回归方法,例如 俄对外情报局,因为它们通常优于 SVC 或 OVA SVM 等多类分类器。

我认为人们对于哪些重量用于哪些方面存在很多困惑。我不确定我是否确切知道是什么困扰着你,所以我将涉及不同的话题,请耐心等待;)。

级别重量

来自 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分数的 全局数字? 你可以:

  1. 取每个类的 f1分数的平均值: 这是上面的 avg / total结果,也称为 宏观平均值。
  2. 使用真正正面/假负面的全局计数来计算 f1分数,等等(你把每个类的真正正面/假负面的数量相加)。也就是 微观平均值。
  3. 计算 f1分数的加权平均数。在 scikit-learn 中使用 'weighted'将根据类的支持来权衡 f1分数: 类拥有的元素越多,该类在计算中的 f1分数就越重要。

这是 scikit-learn 中的3个选项,警告就是说你是 必须选一个。因此,您必须为 score 方法指定一个 average参数。

你选择哪一个取决于你想如何衡量分类器的性能: 例如,宏平均不考虑班级不平衡,一班的 f1分数将与五班的 f1分数一样重要。然而,如果你使用加权平均,你会得到更多的重要性为第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"))

希望这个能帮上忙。

这里有很多非常详细的答案,但我认为你没有回答正确的问题。根据我对这个问题的理解,有两个问题值得关注:

  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)的得分低,那么你就知道不平衡的数据实际上是个问题,你可以相应地采取行动,正如这个线程中的其他一些答案所描述的那样。 但是,如果您想要预测的数据中存在相同的类分布,那么不平衡的训练数据就是数据的良好代表,因此,不平衡是一件好事。