【问题标题】:log_loss in sklearn: Multioutput target data is not supported with label binarizationsklearn 中的 log_loss:标签二值化不支持多输出目标数据
【发布时间】:2018-07-08 08:44:29
【问题描述】:

以下代码

from sklearn import metrics
import numpy as np
y_true = np.array([[0.2,0.8,0],[0.9,0.05,0.05]])
y_predict = np.array([[0.5,0.5,0.0],[0.5,0.4,0.1]])
metrics.log_loss(y_true, y_predict)

产生以下错误:

   ---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-32-24beeb19448b> in <module>()
----> 1 metrics.log_loss(y_true, y_predict)

~\AppData\Local\conda\conda\envs\tensorflow\lib\site-packages\sklearn\metrics\classification.py in log_loss(y_true, y_pred, eps, normalize, sample_weight, labels)
   1646         lb.fit(labels)
   1647     else:
-> 1648         lb.fit(y_true)
   1649 
   1650     if len(lb.classes_) == 1:

~\AppData\Local\conda\conda\envs\tensorflow\lib\site-packages\sklearn\preprocessing\label.py in fit(self, y)
    276         self.y_type_ = type_of_target(y)
    277         if 'multioutput' in self.y_type_:
--> 278             raise ValueError("Multioutput target data is not supported with "
    279                              "label binarization")
    280         if _num_samples(y) == 0:

ValueError: Multioutput target data is not supported with label binarization

我很好奇为什么。我正在尝试重新阅读日志丢失的定义,但找不到任何会使计算不正确的内容。

【问题讨论】:

  • 在 scikit 中,log_loss 仅针对分类任务定义,如下所述:- scikit-learn.org/stable/modules/…
  • @VivekKumar,谢谢Vivek,你的意思是说二元分类任务?我说的问题仍然是分类,而不是二元。
  • 我已经添加了我对您问题的解释作为答案。请仔细阅读并告诉您是否需要。

标签: python scikit-learn cross-entropy


【解决方案1】:

源码表明metrics.log_loss不支持y_true中的概率。它仅支持形状为(n_samples, n_classes) 的二进制指示符,例如[[0,0,1],[1,0,0]] 或形状为(n_samples,) 的类标签,例如[2, 0]。在后一种情况下,在计算 log loss 之前,类标签将被 one-hot 编码为看起来像指标矩阵。

在这个区块中:

lb = LabelBinarizer()

if labels is not None:
    lb.fit(labels)
else:
    lb.fit(y_true)

您正在访问lb.fit(y_true),如果y_true 不是全部1 和/或0,这将失败。例如:

>>> import numpy as np
>>> from sklearn import preprocessing

>>> lb = preprocessing.LabelBinarizer()

>>> lb.fit(np.array([[0,1,0],[1,0,0]]))

LabelBinarizer(neg_label=0, pos_label=1, sparse_output=False)

>>> lb.fit(np.array([[0.2,0.8,0],[0.9,0.05,0.05]]))

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/imran/.pyenv/versions/anaconda3-4.4.0/lib/python3.6/site-packages/sklearn/preprocessing/label.py", line 278, in fit
    raise ValueError("Multioutput target data is not supported with "
ValueError: Multioutput target data is not supported with label binarization

我会定义你自己的自定义日志损失函数:

def logloss(y_true, y_pred, eps=1e-15):
    y_pred = np.clip(y_pred, eps, 1 - eps)
    return -(y_true * np.log(y_pred)).sum(axis=1).mean()

这是您数据的输出:

>>> logloss(y_true, y_predict)
0.738961717153653

【讨论】:

  • 没有。你错了。它不需要y_true 是二进制的。 y_true 可以是多类类型。源码表明它将多类y转换为二进制标签指示符。
  • y_true 可以有多个1,但不能有不是01 的值。
  • 很多时候您可能希望针对并非全部为01 的真实标签计算日志损失。例如,用于预测固有随机过程或部分类别成员的潜在概率,例如:这条狗是 75% 的猎犬和 25% 的哈士奇。
  • 我认为您提供的示例中的标签和类概率之间仍然存在一些混淆。标签可以是 0、1、2,但这些将是 one-hot 编码,因此这与支持非二进制值的 log-loss 无关。
  • 同样,在我的示例中,它们不是单热编码的。我并不是在向你争辩说我的答案比你的更正确。我只是指出你在回答中所说的不真实。就是这样。
【解决方案2】:

不,我不是在谈论二进制分类。

您在上面显示的y_truey_predict 不会被视为分类目标,除非另有说明。

首先,因为它们是概率,所以它可以采用任何连续值,因此在 scikit 中被检测为回归。

其次,y_pred 或 y_true 中的每个元素都是一个概率列表。这被检测为多输出。因此出现“多输出目标”的错误。

您需要为log_loss 提供实际标签,而不是为 y_true(基本事实)提供概率。顺便说一句,为什么你有这种可能性?预测数据可以存在概率,但为什么实际数据存在?

为此,您需要首先将y_true 的概率转换为标签,将最高概率视为获胜者类别。

这可以由numpy.argmax 使用以下代码完成:

import numpy as np
y_true = np.argmax(y_true, axis=1)

print(y_true)
Output:-  [0, 1]
# We will not do this the above for y_predict, because probabilities are allowed in it.

# We will use labels param to declare that we have actually 3 classes, 
# as evident from your probabilities.
metrics.log_loss(y_true, y_predict, labels=[0,1,2])

Output:-  0.6931471805599458

正如与@Imran 讨论的那样,这是一个示例,其中y_true 的值不是0 或1。

下面的例子简单地检查是否允许其他值:

y_true = np.array([0, 1, 2])
y_pred = np.array([[0.5,0.5,0.0],[0.5,0.4,0.1], [0.4,0.1,0.5]])
metrics.log_loss(y_true, y_pred)

Output:- 1.3040076684760489   (No error)

【讨论】:

  • 很好地使用了argmax,但在计算日志损失时,当然可能需要y_true 中的小数值,例如预测固有随机过程的潜在概率或部分类成员资格。目前尚不清楚@user1700890 对他的具体情况有什么要求,但我的回答应该解决其他任何发现它的人的普遍问题。
  • @Imran 有人可能想要“y_true 中的小数值”,但 log_loss 不支持这一点,并且在您的回答中您已经展示了一个不错的选择。我只是列出了 log_loss 在 scikit 中实现的正确用法。
  • @VivekKumar。你是对的。它严格针对 1 和 0 结果。这是交叉熵的一个有点狭窄的实现
猜你喜欢
  • 2017-09-08
  • 2021-03-22
  • 2018-07-08
  • 2018-06-11
  • 2018-09-11
  • 1970-01-01
  • 2021-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多