del*_*onX 23 python classification scikit-learn multilabel-classification multiclass-classification
有人可以解释(举例说明)scikit-learn中OneVsRestClassifier和MultiOutputClassifier之间的区别是什么?
我已阅读文档,我知道我们使用:
我已经使用OneVsRestClassifier进行多标签分类,我可以理解它是如何工作的,但后来我找到了MultiOutputClassifier,并且无法理解它与OneVsRestClassifier的工作方式有何不同.
Ton*_*has 27
为了更好地说明这些差异,我们假设您的目标是将SO问题分类为n_classes不同的互斥类.为了简化在这个例子起见,我们将只考虑四类,分别是'Python','Java','C++'和'Other language'.让我们假设您有一个仅由六个SO问题组成的数据集,这些问题的类标签存储在一个数组中y,如下所示:
import numpy as np
y = np.asarray(['Java', 'C++', 'Other language', 'Python', 'C++', 'Python'])
Run Code Online (Sandbox Code Playgroud)
上述情况通常称为多类分类(也称为多项分类).为了适应分类器并通过scikit-learn库验证模型,您需要将文本类标签转换为数字标签.要实现这一点,您可以使用LabelEncoder:
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y_numeric = le.fit_transform(y)
Run Code Online (Sandbox Code Playgroud)
这就是数据集标签的编码方式:
In [220]: y_numeric
Out[220]: array([1, 0, 2, 3, 0, 3], dtype=int64)
Run Code Online (Sandbox Code Playgroud)
这些数字表示以下数组的索引:
In [221]: le.classes_
Out[221]:
array(['C++', 'Java', 'Other language', 'Python'],
dtype='|S14')
Run Code Online (Sandbox Code Playgroud)
一个重要的特殊情况是只有两个类,即n_classes = 2.这通常称为二进制分类.
现在让我们假设您希望使用n_classes二进制分类池(n_classes即不同类的数量)执行此类多类分类.这些二元分类器中的每一个都决定项是否属于特定类.在这种情况下,你无法从编码级标记为整数0来n_classes - 1,你需要创建一个2维矩阵指标代替.考虑样本n是类k.然后,[n, k]指标矩阵的输入是,1并且行n中的其余元素是0.重要的是要注意,如果类不是互斥的,则可以连续多个1.这种方法被命名为multilabel分类,可以通过MultiLabelBinarizer轻松实现:
from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
y_indicator = mlb.fit_transform(y[:, None])
Run Code Online (Sandbox Code Playgroud)
指标看起来像这样:
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]])
Run Code Online (Sandbox Code Playgroud)
和列号,其中1的s实际上是这个数组的索引:
In [226]: mlb.classes_
Out[226]: array(['C++', 'Java', 'Other language', 'Python'], dtype=object)
Run Code Online (Sandbox Code Playgroud)
如果您想同时根据两个不同的标准对特定的SO问题进行分类,例如语言和应用,该怎么办?在这种情况下,您打算进行多输出分类.为了简便起见,我将只考虑三个应用程序类,即'Computer Vision','Speech Processing"和'Other application".数据集的标签数组应为2维:
y2 = np.asarray([['Java', 'Computer Vision'],
['C++', 'Speech Recognition'],
['Other language', 'Computer Vision'],
['Python', 'Other Application'],
['C++', 'Speech Recognition'],
['Python', 'Computer Vision']])
Run Code Online (Sandbox Code Playgroud)
同样,我们需要将文本类标签转换为数字标签.据我所知,这个功能尚未在scikit-learn中实现,因此您需要编写自己的代码.这个主题描述了一些聪明的方法来做到这一点,但为了这篇文章的目的,下面的单行应该足够:
y_multi = np.vstack((le.fit_transform(y2[:, i]) for i in range(y2.shape[1]))).T
Run Code Online (Sandbox Code Playgroud)
编码标签如下所示:
In [229]: y_multi
Out[229]:
array([[1, 0],
[0, 2],
[2, 0],
[3, 1],
[0, 2],
[3, 0]], dtype=int64)
Run Code Online (Sandbox Code Playgroud)
并且可以从以下数组推断每列中值的含义:
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')
Run Code Online (Sandbox Code Playgroud)
这是@tonechas 答案的扩展。在阅读本文之前先阅读该答案。仅当每个标签是二进制标签/类(也称为二进制多标签)时,OVR才支持多标签,即样本属于该标签或不属于该标签。当目标是多输出(也称为多类多标签)时,即每个样本可以属于标签内的任何一个类时,它将不起作用。对于后一种情况,您需要使用 sklearn Multioutput classifier。
换句话说,当你的目标变量看起来像这样时,sklearn OVR 不起作用,
y_true = np.arr([[2, 1, 0],
[0, 2, 1],
[1, 2, 4]])
Run Code Online (Sandbox Code Playgroud)
其中 label1 有 4 个类 [0, 1, 2, 3];label2 有 3 个类 [0, 1, 2];label3 有 5 个类别 [0, 1, 2, 3, 4]。例如:第一个样本属于 label1 中的类 2,label2 中属于类 1,label3 中属于类 0。将其视为标签不互斥,而每个标签内的类是互斥的。
Sklearn OVR 将在以下情况下工作:
y_true = np.arr([[0, 1, 1],
[0, 0, 1],
[1, 1, 0]])
Run Code Online (Sandbox Code Playgroud)
其中 label1 labe2、label3 各只有 2 个类。因此,样本要么属于该标签,要么不属于该标签。例如:第一个样本属于 label1 和 label2。
很抱歉,我找不到此类用例的真实示例。