【问题标题】:What is the difference between OneVsRestClassifier and MultiOutputClassifier in scikit learn?scikit learn中的OneVsRestClassifier和MultiOutputClassifier有什么区别?
【发布时间】:2017-08-06 18:20:54
【问题描述】:

有人可以解释一下(可能有例子)scikit-learn 中OneVsRestClassifierMultiOutputClassifier 之间的区别是什么?

我已阅读文档并了解我们使用:

  • OneVsRestClassifier - 当我们想要进行多类或多标签分类时,它的策略是为每个类拟合一个分类器。对于每个分类器,该类与所有其他类进行拟合。 (这很清楚,这意味着多类/多标签分类问题被分解为多个二元分类问题。
  • MultiOutputClassifier - 当我们想要进行多目标分类时(这是什么?),它的策略包括为每个目标拟合一个分类器(什么是目标是什么意思?)

我已经使用 OneVsRestClassifier 进行多标签分类,我可以理解它是如何工作的,但后来我发现 MultiOutputClassifier 并且无法理解它与 OneVsRestClassifier 的工作方式有何不同。

【问题讨论】:

    标签: python scikit-learn classification multilabel-classification multiclass-classification


    【解决方案1】:

    这是@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]。例如:第一个样本属于 label1 中的 2 类,label2 中的 1 类,label3 中的 0 类。 将其视为标签不互斥,而每个标签中的类互斥。

    Sklearn OVR 将在何时工作,

    y_true = np.arr([[0, 1, 1],
                     [0, 0, 1],
                     [1, 1, 0]])
    

    其中 label1 labe2, label3 每个只有 2 个类。因此,样本要么属于该标签,要么不属于该标签。例如:第一个样本属于 label1 和 label2。

    很抱歉,我找不到此类用例的真实示例。

    【讨论】:

    • 一个玩具的例子,也许是,您正在尝试将乐高积木分类为形状 - 矩形、正方形等,并且对于每种形状,您想知道积木有多种不同的颜色;例如:粉色、红色、绿色等。
    【解决方案2】:

    多类分类

    为了更好地说明差异,让我们假设您的目标是将 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 是不同类的数量。这些二元分类器中的每一个都会决定项目是否属于特定类别。在这种情况下,您不能将类标签编码为从0n_classes - 1 的整数,您需要创建一个二维指示矩阵。考虑样本n 属于k 类。然后,指标矩阵的[n, k] 条目为1n 行中的其余元素为0。重要的是要注意,如果类不是互斥的,则可以连续有多个1。这种方法被命名为多标签分类,可以通过MultiLabelBinarizer轻松实现:

    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 中实现,因此您需要编写自己的代码。 This thread 描述了一些巧妙的方法来做到这一点,但就本文而言,以下单行就足够了:

    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')
    

    【讨论】:

    • 这个答案虽然内容丰富,但并没有真正解决 OP 的问题:“sklearn 的 OneVsRestClassifier 和 MultiOutputClassifier 类之间的区别是什么。”
    • 这可以呈现编辑,但 OneVsRestClassifier 回答多标签分类(如果 Y 是矩阵)或多类分类(如果 y 是一维数组),而 MultiOutputClassifier 专门回答多输出分类。此外,据我所知,多输出分类仅适用于不同的多类分类。
    • 对此有任何答案吗?接受的答案只是描述了概念,但实际上并没有明确解决 OP 的问题“sklearn 的 OneVsRestClassifier 和 MultiOutputClassifier 类有什么区别
    猜你喜欢
    • 2016-08-01
    • 2015-03-10
    • 2018-03-18
    • 2018-07-02
    • 2020-07-13
    • 2015-04-21
    • 2021-07-03
    • 1970-01-01
    • 2016-12-08
    相关资源
    最近更新 更多