有人可以解释一下(也许有例子)scikit-learn中OneVsRestClassifier和MultiOutputClassifier有什么区别吗?
我已经阅读了文档,并且了解我们使用:
- OneVsRestClassifier- 当我们想要进行多类或多标签分类时,它的策略包括为每个类拟合一个分类器。对于每个分类器,该类与所有其他类拟合。(这很清楚,这意味着多类/多标签分类问题被分解为多个二元分类问题)。
- MultiOutputClassifier- 当我们想要进行多目标分类时(这是什么?),它的策略包括为每个目标拟合一个分类器(目标在那里意味着什么?)
我已经使用OneVsRestClassifier进行多标签分类,我可以理解它是如何工作的,但后来我发现了MultiOutputClassifier,无法理解它与OneVsRestClassifier的工作方式有何不同。
多类分类
为了更好地说明差异,让我们假设您的目标是将 SO 问题分类为n_classes
不同的、相互排斥的类。为了简单起见,在这个例子中,我们只考虑四个类,即'Python'
、'Java'
、'C++'
和'Other language'
。假设您有一个仅由六个 SO 问题组成的数据集,这些问题的类标签存储在数组中,y
如下所示:
import numpy as np
y = np.asarray(['Java', 'C++', 'Other language', 'Python', 'C++', 'Python'])
上述情况通常称为多类分类(也称为多项式分类)。为了拟合分类器并通过scikit-learn库验证模型,您需要将文本类标签转换为数字标签。要实现这一点,您可以使用 LabelEncoder:
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y_numeric = le.fit_transform(y)
数据集标签的编码方式如下:
In [220]: y_numeric
Out[220]: array([1, 0, 2, 3, 0, 3], dtype=int64)
其中这些数字表示以下数组的索引:
In [221]: le.classes_
Out[221]:
array(['C++', 'Java', 'Other language', 'Python'],
dtype='|S14')
一个重要的特殊情况是当只有两个类时,即n_classes = 2
.这通常称为二元分类。
多标签分类
现在让我们假设您希望使用n_classes
二元分类器池来执行这种多类分类,n_classes
不同类的数量。这些二元分类器中的每一个都决定项目是否属于特定类。在这种情况下,您不能将类标签编码为从0
到n_classes - 1
的整数,您需要创建一个二维指示矩阵。考虑样本n
属于类k
。然后,1
指标矩阵的[n, k]
条目,0
第n
行中的其余元素。重要的是要注意,如果类不是互斥的,则一行中可以有多个1
。这种方法称为多标签分类,可以通过多标签二旁白器轻松实现:
from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
y_indicator = mlb.fit_transform(y[:, None])
指标如下所示:
In [225]: y_indicator
Out[225]:
array([[0, 1, 0, 0],
[1, 0, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
[1, 0, 0, 0],
[0, 0, 0, 1]])
以及其中1
的列号实际上是此数组的索引:
In [226]: mlb.classes_
Out[226]: array(['C++', 'Java', 'Other language', 'Python'], dtype=object)
多输出分类
如果您想同时根据两个不同的标准(例如语言和应用程序)对特定的 SO 问题进行分类,该怎么办?在这种情况下,您打算执行多输出分类。为了简单起见,我将只考虑三个应用程序类,即'Computer Vision'
,'Speech Processing
'和'Other application
'。数据集的标签数组应该是二维的:
y2 = np.asarray([['Java', 'Computer Vision'],
['C++', 'Speech Recognition'],
['Other language', 'Computer Vision'],
['Python', 'Other Application'],
['C++', 'Speech Recognition'],
['Python', 'Computer Vision']])
同样,我们需要将文本类标签转换为数字标签。据我所知,这个功能还没有在scikit-learn中实现,所以你需要编写自己的代码。这个线程描述了一些聪明的方法,但出于这篇文章的目的,以下一行应该就足够了:
y_multi = np.vstack((le.fit_transform(y2[:, i]) for i in range(y2.shape[1]))).T
编码的标签如下所示:
In [229]: y_multi
Out[229]:
array([[1, 0],
[0, 2],
[2, 0],
[3, 1],
[0, 2],
[3, 0]], dtype=int64)
每列中值的含义可以从以下数组中推断出来:
In [230]: le.fit(y2[:, 0]).classes_
Out[230]:
array(['C++', 'Java', 'Other language', 'Python'],
dtype='|S18')
In [231]: le.fit(y2[:, 1]).classes_
Out[231]:
array(['Computer Vision', 'Other Application', 'Speech Recognition'],
dtype='|S18')
这是@tonechas答案的扩展。在阅读本文之前,请阅读该答案。仅当每个标签都是二进制标签/类(也称为二进制多标签)时,OVR 才支持多标签,即样本属于或不属于该标签。当目标是多输出(也称为多类多标签)时,即当每个样本可以属于标签中的任何一个类时,它将不起作用。对于后一种情况,您需要使用 sklearn 多输出分类器。
换句话说,当你的目标变量看起来像这样时,sklearn OVR 不起作用,
y_true = np.arr([[2, 1, 0],
[0, 2, 1],
[1, 2, 4]])
其中 label1 有 4 个类 [0, 1, 2, 3];label2 有 3 个类 [0, 1,2];label3 有 5 个类 [0, 1, 2, 3, 4]。例如:第一个样品属于标签1中的第2类,标签2中的第1类,标签3中的第0类。可以将其视为标签不是互斥的,而每个标签中的类是互斥的。
Sklearn OVR 将在以下情况下工作:
y_true = np.arr([[0, 1, 1],
[0, 0, 1],
[1, 1, 0]])
其中 label1 labe2,label3 各只有 2 个类。因此,样本要么属于该标签,要么不属于该标签。例如:第一个样本属于标签 1 和标签 2。
很抱歉,我找不到这种用例的真实示例。
对此有什么答案吗?接受的答案只是描述了概念 但实际上并没有明确解决OP的问题"什么是 sklearn的OneVsRestClassifier和MultiOutputClassifier类之间的区别
我认为问题的作者回答了自己
多输出分类器 - 当我们想要进行多目标分类时 (这是什么?它的策略包括拟合一个分类器 每个目标(目标在那里意味着什么?
目标为 Y(相关变量)
附言 多类或多标签 - 表示"多"名义特征- 被认为是独立变量的X...(分别在行中或以 feature_columns.count>1 为单位)
附言 我想在 sklearn 库内部为每个目标都有一个单独的训练(拟合) - 关于作者的引用