UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 in labels with no predicted samples

我得到了一个奇怪的错误:

classification.py:1113: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 in labels with no predicted samples.
'precision', 'predicted', average, warn_for)`

但我第一次运行时它也会打印出 f 值:

metrics.f1_score(y_test, y_pred, average='weighted')

我第二次运行时,它提供的分数没有错误。为什么呢?

>>> y_pred = test.predict(X_test)
>>> y_test
array([ 1, 10, 35,  9,  7, 29, 26,  3,  8, 23, 39, 11, 20,  2,  5, 23, 28,
30, 32, 18,  5, 34,  4, 25, 12, 24, 13, 21, 38, 19, 33, 33, 16, 20,
18, 27, 39, 20, 37, 17, 31, 29, 36,  7,  6, 24, 37, 22, 30,  0, 22,
11, 35, 30, 31, 14, 32, 21, 34, 38,  5, 11, 10,  6,  1, 14, 12, 36,
25,  8, 30,  3, 12,  7,  4, 10, 15, 12, 34, 25, 26, 29, 14, 37, 23,
12, 19, 19,  3,  2, 31, 30, 11,  2, 24, 19, 27, 22, 13,  6, 18, 20,
6, 34, 33,  2, 37, 17, 30, 24,  2, 36,  9, 36, 19, 33, 35,  0,  4,
1])
>>> y_pred
array([ 1, 10, 35,  7,  7, 29, 26,  3,  8, 23, 39, 11, 20,  4,  5, 23, 28,
30, 32, 18,  5, 39,  4, 25,  0, 24, 13, 21, 38, 19, 33, 33, 16, 20,
18, 27, 39, 20, 37, 17, 31, 29, 36,  7,  6, 24, 37, 22, 30,  0, 22,
11, 35, 30, 31, 14, 32, 21, 34, 38,  5, 11, 10,  6,  1, 14, 30, 36,
25,  8, 30,  3, 12,  7,  4, 10, 15, 12,  4, 22, 26, 29, 14, 37, 23,
12, 19, 19,  3, 25, 31, 30, 11, 25, 24, 19, 27, 22, 13,  6, 18, 20,
6, 39, 33,  9, 37, 17, 30, 24,  9, 36, 39, 36, 19, 33, 35,  0,  4,
1])
>>> metrics.f1_score(y_test, y_pred, average='weighted')
C:\Users\Michael\Miniconda3\envs\snowflakes\lib\site-packages\sklearn\metrics\classification.py:1113: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 in labels with no predicted samples.
'precision', 'predicted', average, warn_for)
0.87282051282051276
>>> metrics.f1_score(y_test, y_pred, average='weighted')
0.87282051282051276
>>> metrics.f1_score(y_test, y_pred, average='weighted')
0.87282051282051276

Also, why is there a trailing 'precision', 'predicted', average, warn_for) error message? There is no open parenthesis so why does it end with a closing parenthesis? I am running sklearn 0.18.1 using Python 3.6.0 in a conda environment on Windows 10.

我也看了 给你,我不知道它是否是同一个错误。这个 SO post也没有解决方案。

233962 次浏览

As mentioned in the comments, some labels in y_test don't appear in y_pred. Specifically in this case, label '2' is never predicted:

>>> set(y_test) - set(y_pred)
{2}

这意味着这个标签不需要计算 F 分数,因此这种情况下的 F 分数被认为是0.0。因为您要求得到平均分,所以必须考虑到计算中包含0分,这就是 scikit-learn 向您显示这个警告的原因。

这让我想到你没有看到第二次错误。如前所述,这是一个 warning,它的处理方式与 python 中的错误不同。大多数环境中的默认行为是只显示一次特定的警告。这种行为是可以改变的:

import warnings
warnings.filterwarnings('always')  # "error", "ignore", "always", "default", "module" or "once"

如果在导入其他模块之前设置此值,则每次运行代码时都会看到警告。

除了设置 warnings.filterwarnings('ignore')之外,没有办法避免在第一次看到这个警告。你 可以所做的,就是决定你对那些没有被预测到的标签的分数不感兴趣,然后明确地指定你 are感兴趣的标签(那些至少被预测过一次的标签) :

>>> metrics.f1_score(y_test, y_pred, average='weighted', labels=np.unique(y_pred))
0.91076923076923078

警告就会消失。

正如错误消息所述,用于获取 F 分数的方法来自 sklearn 的“分类”部分——因此讨论的是“标签”。

你有回归问题吗? Sklearn 在“特征选择”组下提供了一个“ F 分数”的回归方法: http://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.f_regression.html

In case you do have a classification problem, @Shovalt's answer seems correct to me.

公认的答案已经很好地解释了为什么会发生这种警告。如果只想控制警告,可以使用 precision_recall_fscore_support。它提供了一个(半官方的)参数 warn_for,可用于静音警告。

(_, _, f1, _) = metrics.precision_recall_fscore_support(y_test, y_pred,
average='weighted',
warn_for=tuple())

正如在一些注释中已经提到的,使用时要小心。

the same problem also happened to me when i training my classification model. 引起这个问题的原因正如警告消息所说的“在没有预测样本的标签中”,当计算 f1分数时,它将导致零除。 当我阅读 F1 _ score文档时,我发现了另一种解决方案,有一个注释如下:

当真阳性 + 假阳性 = = 0时,精度未定义; 当真阳性 + 假阴性 = = 0时,召回未定义。在这种情况下,默认情况下,度量值将设置为0,f-score 也是如此,并且将引发 UnDefinition edMetricPolice。此行为可以用 zero _ Division 修改

zero_division的默认值是 "warn",您可以将其设置为 01以避免 UndefinedMetricWarning。 哦,等等,当我使用 zero_division时还有一个问题,我的 sklearn 报告说使用 scikit-learn 0.21.3时没有这样的关键字参数。只需要通过运行 pip install scikit-learn -U来更新你的 sklearn 到最新版本

我注意到这个错误发生在两种情况下,

  1. 如果您使用 train _ test _ split ()来分割数据,那么您必须确保您重置了数据的索引(特别是在使用熊猫系列对象时) : y _ train,y _ test 索引应该重置。问题在于,当您试图使用 skLearn.metrics 中的一个得分时,比如精度 _ 得分,这将尝试匹配您从 train _ test _ split ()中获得的 y _ test 的混合索引。

因此,要么使用 np.array(y_test) for y_true in scoresy_test.reset_index(drop=True)

  1. 然后,如果您预测的“真正正面”是0,那么您仍然可以有这个错误,这是用于精度,召回和 f1 _ 得分。您可以使用混淆 _ 矩阵将其可视化。如果分类是多标签的,并且你设置了 param: average = ‘ weight’/micro/巨集,那么只要矩阵中的对角线不是0,你就会得到一个答案

希望这个能帮上忙。

I ended up here with the same error but after reading @Shovalt's answer, I realized I was quite low in my test/train split. I had a large data set to start with but had split it down and one group was quite small. By making the sample size bigger, this warning went away and I got my f1 score. 从这里

from sklearn.model_selection import train_test_split


X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=0)

这个

from sklearn.model_selection import train_test_split


X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

正如 Shovalt所建议的那样,我检查了多标签情况下真值集和预测集之间的差异,但这并没有帮助我解决我的问题。

因此,我搜索了 精度 _ 召回 _ fscore _ 支持源代码(由 f1 _ score 调用)来检查它是如何工作的。

触发警告的代码如下:

precision = _prf_divide(
tp_sum, pred_sum, "precision", "predicted", average, warn_for, zero_division
)
recall = _prf_divide(
tp_sum, true_sum, "recall", "true", average, warn_for, zero_division
)
  • tpsum对应于 TP (真正的积极因素)
  • pred_sum对应于 TP + FP (假阳性)
  • true_sum对应于 TP + FN (假阴性)
  • _prf_divide的第一个参数是除法分子
  • second parameter of _prf_divide is denominator of division

一旦 pred _ sum 或 true _ sum 等于0,它就会触发警告,因为不允许除以0。

为了得到这些不同的值,使用 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$。结果是一个三维数组。你可以看到它是一个2x2的矩阵列表,其中每个矩阵代表每个标签的真正负面(TN)、假正面(FP)、假负面(FP)和真正正面(TP) ,结构如下:

multilabel_confusion_matrix output

在我看来,问题应该来自模型无法预测一些标签,由于不良的训练或缺乏样本。