1.12. 多类和多输出算法#

本用户指南的这一部分涵盖了与多学习问题相关的功能,包括 多类多标签多输出 分类和回归。

本节中的模块实现了 元估计器 ,它们在其构造函数中需要提供一个基础估计器。元估计器通过将多学习问题转化为一组更简单的问题,然后为每个问题拟合一个估计器,从而扩展了基础估计器的功能以支持多学习问题。

本节涵盖了两个模块:sklearn.multiclasssklearn.multioutput 。下图展示了每个模块负责的问题类型,以及每个模块提供的相应元估计器。

../_images/multi_org_chart.png

下表提供了问题类型之间差异的快速参考。更详细的解释可以在本指南的后续部分找到。

目标数量

目标基数

有效 type_of_target

多类分类

1

>2

‘multiclass’

多标签 分类

>1

2 (0 或 1)

‘多标签指示器’

多类-多输出 分类

>1

>2

‘多类-多输出’

多输出 回归

>1

连续

‘连续-多输出’

以下是 scikit-learn 估计器中内置多学习支持的总结,按策略分组。如果您使用的是这些估计器之一,则不需要本节提供的元估计器。然而,元估计器可以提供超出内置功能的额外策略:

1.12.1. 多类分类#

Warning

所有scikit-learn中的分类器都支持开箱即用的多类分类。除非您想尝试不同的多类策略,否则不需要使用:mod:sklearn.multiclass 模块。

多类分类 是一个包含两个以上类别的分类任务。每个样本只能被标记为一个类别。

例如,使用从一组水果图像中提取的特征进行分类,其中每个图像可能是橙子、苹果或梨。每个图像是一个样本,并被标记为这3个可能类别中的一个。多类分类假设每个样本被分配到一个且仅一个标签——例如,一个样本不能同时是梨和苹果。

虽然所有scikit-learn分类器都支持多类分类,但:mod:sklearn.multiclass 提供的元估计器允许改变它们处理两个以上类别的方式,因为这可能会影响分类器的性能(无论是泛化误差还是所需的计算资源)。

1.12.1.1. 目标格式#

type_of_target ( y )的有效:term:multiclass 表示形式包括:

  • 包含两个以上离散值的一维或列向量。一个包含4个样本的向量 y 的例子:

    >>> import numpy as np
    >>> y = np.array(['apple', 'pear', 'apple', 'orange'])
    >>> print(y)
    ['apple' 'pear' 'apple' 'orange']
    
  • 形状为 (n_samples, n_classes) 的密集或稀疏:term:binary 矩阵,每行代表一个样本,每列代表一个类别。一个包含4个样本的密集和稀疏:term:binary 矩阵 y 的例子,其中列按顺序分别是苹果、橙子和梨:

    >>> import numpy as np
    >>> from sklearn.preprocessing import LabelBinarizer
    
    >>> y = np.array(['apple', 'pear', 'apple', 'orange'])
    >>> y_dense = LabelBinarizer().fit_transform(y)
    >>> print(y_dense)
    [[1 0 0]
     [0 0 1]
     [1 0 0]
     [0 1 0]]
    >>> from scipy import sparse
    >>> y_sparse = sparse.csr_matrix(y_dense)
    >>> print(y_sparse)
      (0, 0)    1
      (1, 2)    1
      (2, 0)    1
      (3, 1)    1
    

有关 LabelBinarizer 的更多信息,请参阅 转换预测目标( y )

1.12.1.2. OneVsRestClassifier#

一对多 策略,也称为 一对一,在 OneVsRestClassifier 中实现。该策略包括为每个类别拟合一个分类器。对于每个分类器,该类别与所有其他类别进行拟合。除了其计算效率(仅需要 n_classes 个分类器)之外,这种方法的一个优点是其可解释性。由于每个类别由一个且仅一个分类器表示,因此可以通过检查其相应的分类器来获得关于该类别的知识。这是最常用的策略,是一个公平的默认选择。

以下是使用 OvR 进行多类学习的示例:

>>> from sklearn import datasets
>>> from sklearn.multiclass import OneVsRestClassifier
>>> from sklearn.svm import LinearSVC
>>> X, y = datasets.load_iris(return_X_y=True)
>>> OneVsRestClassifier(LinearSVC(random_state=0)).fit(X, y).predict(X)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

OneVsRestClassifier 也支持多标签分类。要使用此功能,请向分类器提供一个指示矩阵,其中单元格 [i, j] 表示样本 i 中标签 j 的存在。

../_images/sphx_glr_plot_multilabel_001.png

示例

1.12.1.3. OneVsOneClassifier#

OneVsOneClassifier 为每一对类别构建一个分类器。在预测时,选择获得最多票数的类别。如果在两个类别之间出现平局(即票数相等),则选择通过汇总成对分类置信水平计算的最高综合分类置信度的类别。

由于需要拟合 n_classes * (n_classes - 1) / 2 个分类器,这种方法通常比 one-vs-the-rest 慢,因为其复杂度为 O(n_classes^2)。然而,对于如核算法等不适用于 n_samples 的算法,这种方法可能具有优势。这是因为每个单独的学习问题仅涉及数据的一个小子集,而 one-vs-the-rest 则使用完整数据集 n_classes 次。决策函数是 one-versus-one 分类的单调变换结果。

以下是使用 OvO 进行多类别学习的示例:

>>> from sklearn import datasets
>>> from sklearn.multiclass import OneVsOneClassifier
>>> from sklearn.svm import LinearSVC
>>> X, y = datasets.load_iris(return_X_y=True)
>>> OneVsOneClassifier(LinearSVC(random_state=0)).fit(X, y).predict(X)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

参考文献

  • “模式识别与机器学习. Springer”, Christopher M. Bishop, 第183页, (第一版)

1.12.1.4. OutputCodeClassifier#

基于纠错输出码的策略与一对一和一对多策略有很大不同。在这些策略中,每个类别在欧几里得空间中表示,其中每个维度只能是0或1。换句话说,每个类别由一个二进制码(0和1的数组)表示。记录每个类别的定位/代码的矩阵称为代码本。代码大小是上述空间的维度。直观地说,每个类别应该由尽可能唯一的代码表示,并且应该设计一个好的代码本来优化分类准确性。在这个实现中,我们简单地使用随机生成的代码本,如[3]_中所倡导的那样,尽管将来可能会添加更精细的方法。

在拟合时,代码本中的每一位对应一个二进制分类器。在预测时,分类器用于将新点投影到类别空间中,并选择最接近点的类别。

OutputCodeClassifier 中, code_size 属性允许用户控制将使用的分类器数量。它是总类别数的百分比。

介于0和1之间的数字将需要比一对多更少的分类器。理论上, log2(n_classes) / n_classes 足以 每个类别都明确表示。然而,在实践中,这可能不会导致良好的准确性,因为 log2(n_classes) 远小于 n_classes

大于1的数值将需要比一对多更多的分类器。在这种情况下,理论上一些分类器将纠正其他分类器所犯的错误,因此得名“纠错”。然而,在实践中,这可能不会发生,因为分类器的错误通常是相关的。纠错输出码的效果类似于装袋。

下面是一个使用输出码进行多类学习的示例:

>>> from sklearn import datasets
>>> from sklearn.multiclass import OutputCodeClassifier
>>> from sklearn.svm import LinearSVC
>>> X, y = datasets.load_iris(return_X_y=True)
>>> clf = OutputCodeClassifier(LinearSVC(random_state=0), code_size=2, random_state=0)
>>> clf.fit(X, y).predict(X)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1,
       1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

参考文献

  • “Solving multiclass learning problems via error-correcting output codes”, Dietterich T., Bakiri G., Journal of Artificial Intelligence Research 2, 1995.

  • “The Elements of Statistical Learning”, Hastie T., Tibshirani R., Friedman J., page 606 (second-edition), 2008.

1.12.2. 多标签分类#

多标签分类**(与**多输出**密切相关) **分类) 是一项分类任务,为每个样本标记 m 个标签,这些标签来自 n_classes 个可能的类别,其中 m 可以是 0 到 n_classes 之间的任意值(包括 0 和 n_classes )。这可以被视为预测样本的非互斥属性。形式上,为每个样本的每个类别分配一个二进制输出。正类用 1 表示,负类用 0 或 -1 表示。因此,这类似于运行 n_classes 个二分类任务,例如使用 MultiOutputClassifier 。这种方法将每个标签独立处理,而多标签分类器 可能 同时处理多个类别,考虑它们之间的相关行为。

例如,预测与文本文档或视频相关的话题。该文档或视频可能涉及 ‘宗教’、’政治’、’财经’ 或 ‘教育’ 中的一个或多个话题类别,甚至所有话题类别。

1.12.2.1. 目标格式#

多标签``y `的有效表示形式是一个密集或稀疏的 :term: 二进制`矩阵,形状为 (n_samples, n_classes) 。每一列代表一个类别。每一行中的 1 表示样本被标记为正类的类别。以下是一个包含 3 个样本的密集矩阵 y 的示例:

>>> y = np.array([[1, 0, 0, 1], [0, 0, 1, 1], [0, 0, 0, 0]])
>>> print(y)
[[1 0 0 1]
 [0 0 1 1]
 [0 0 0 0]]

密集二进制矩阵也可以使用 MultiLabelBinarizer 创建。更多信息,请参阅 预处理目标

以下是相同 y 的稀疏矩阵形式示例:

>>> y_sparse = sparse.csr_matrix(y)
>>> print(y_sparse)
  (0, 0)      1
  (0, 3)      1
  (1, 2)      1
  (1, 3)      1

1.12.2.2. MultiOutputClassifier#

多标签分类支持可以通过 MultiOutputClassifier 添加到任何分类器中。这种策略包括 为每个目标拟合一个分类器。这允许多目标变量分类。此类旨在扩展估计器,使其能够估计一系列目标函数(f1, f2, f3…, fn),这些函数在一个X预测矩阵上进行训练,以预测一系列响应(y1, y2, y3…, yn)。

您可以在关于 多类-多输出分类 的部分中找到 MultiOutputClassifier 的使用示例,因为它是对多标签分类的泛化,从二元输出变为多类输出。

1.12.2.3. ClassifierChain#

分类器链(参见 ClassifierChain )是一种将多个二元分类器组合成一个多标签模型的方法,该模型能够利用目标之间的相关性。

对于具有N个类的多标签分类问题,N个二元分类器被分配一个介于0和N-1之间的整数。这些整数定义了链中模型的顺序。然后,每个分类器在可用的训练数据以及模型被分配较低编号的类的真实标签上进行拟合。

在预测时,真实标签将不可用。相反,每个模型的预测结果会传递给链中的后续模型,作为特征使用。

显然,链的顺序很重要。链中的第一个模型对其他标签一无所知,而链中的最后一个模型具有指示所有其他标签存在的特征。通常情况下,我们不知道链中模型的最佳顺序,因此通常会拟合许多随机顺序的链,并将它们的预测结果平均在一起。

参考文献

  • Jesse Read, Bernhard Pfahringer, Geoff Holmes, Eibe Frank, “Classifier Chains for Multi-label Classification”, 2009.

1.12.3. 多类-多输出分类#

多类-多输出分类 (也称为 多任务分类)是一种分类任务,它为每个样本标记一组 非二元 属性。属性的数量和每个属性的类别数都大于 2。因此,单个估计器处理多个联合分类任务。这是多 标签 分类任务的泛化,后者仅考虑二元属性,同时也是多 分类任务的泛化,后者仅考虑一个属性。

例如,对一组水果图像的“水果类型”和“颜色”属性进行分类。属性“水果类型”的可能类别有:“苹果”、“梨”和“橙子”。属性“颜色”的可能类别有:“绿色”、“红色”、“黄色”和“橙色”。每个样本是一张水果的图像,为两个属性输出标签,每个标签是相应属性的可能类别之一。

请注意,所有处理多类-多输出(也称为多任务分类)任务的分类器都支持多标签分类任务作为特例。多任务分类类似于具有不同模型公式的多输出分类任务。有关更多信息,请参阅相关估计器的文档。

以下是多类-多输出分类的示例:

>>> from sklearn.datasets import make_classification
>>> from sklearn.multioutput import MultiOutputClassifier
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.utils import shuffle
>>> import numpy as np
>>> X, y1 = make_classification(n_samples=10, n_features=100,
...                             n_informative=30, n_classes=3,
...                             random_state=1)
>>> y2 = shuffle(y1, random_state=1)
>>> y3 = shuffle(y1, random_state=2)
>>> Y = np.vstack((y1, y2, y3)).T
>>> n_samples, n_features = X.shape # 10,100
>>> n_outputs = Y.shape[1] # 3
>>> n_classes = 3
>>> forest = RandomForestClassifier(random_state=1)
>>> multi_target_forest = MultiOutputClassifier(forest, n_jobs=2)
>>> multi_target_forest.fit(X, Y).predict(X)
array([[2, 2, 0],
       [1, 2, 1],
       [2, 1, 0],
       [0, 0, 2],
       [0, 2, 1],
       [0, 0, 2],
       [1, 1, 0],
       [1, 1, 1],
       [0, 0, 2],
       [2, 0, 0]])

Warning

目前,sklearn.metrics 中没有指标支持多类-多输出分类任务。

1.12.3.1. 目标格式#

multioutput``y`的有效表示是一个形状为 ``(n_samples, n_classes)` 的类标签密集矩阵。这是 1D multiclass 变量的列式连接。以下是 3 个样本的 y 示例:

>>> y = np.array([['apple', 'green'], ['orange', 'orange'], ['pear', 'green']])
>>> print(y)
[['apple' 'green']
 ['orange' 'orange']
 ['pear' 'green']]

1.12.4. 多输出回归#

多输出回归 预测每个样本的多个数值属性。每个属性是一个数值变量,并且每个样本要预测的属性数量大于或等于 2。一些支持多输出回归的估计器比仅仅运行 n_output 个估计器更快。

例如,使用在某个位置获得的数据预测风速和风向(以度为单位)。每个样本将是在一个位置获得的数据,并且每个样本的输出将是风速和方向。

以下回归器原生支持多输出回归:

1.12.4.1. 目标格式#

多输出``y`的有效表示是一个形状为 ``(n_samples, n_output)` 的密集浮点矩阵。这是 连续 变量的按列连接。以下是 3 个样本的 y 示例:

>>> y = np.array([[31.4, 94], [40.5, 109], [25.0, 30]])
>>> print(y)
[[ 31.4  94. ]
 [ 40.5 109. ]
 [ 25.   30. ]]

1.12.4.2. MultiOutputRegressor#

多输出回归支持可以通过 MultiOutputRegressor 添加到任何回归器中。这种策略包括为每个目标拟合一个回归器。由于每个目标由一个回归器精确表示,因此可以通过检查其相应的回归器来获得关于目标的知识。由于 MultiOutputRegressor 为每个目标拟合一个回归器,因此它不能利用目标之间的相关性。

以下是一个多输出回归的示例:

>>> from sklearn.datasets import make_regression
>>> from sklearn.multioutput import MultiOutputRegressor
>>> from sklearn.ensemble import GradientBoostingRegressor
>>> X, y = make_regression(n_samples=10, n_targets=3, random_state=1)
>>> MultiOutputRegressor(GradientBoostingRegressor(random_state=0)).fit(X, y).predict(X)
array([[-154.75474165, -147.03498585,  -50.03812219],
       [   7.12165031,    5.12914884,  -81.46081961],
       [-187.8948621 , -100.44373091,   13.88978285],
       [-141.62745778,   95.02891072, -191.48204257],
       [  97.03260883,  165.34867495,  139.52003279],
       [ 123.92529176,   21.25719016,   -7.84253   ],
       [-122.25193977,  -85.16443186, -107.12274212],
       [ -30.170388  ,  -94.80956739,   12.16979946],
       [ 140.72667194,  176.50941682,  -17.50447799],
       [ 149.37967282,  -81.15699552,   -5.72850319]])

1.12.4.3. RegressorChain#

回归链(见 RegressorChain )类似于 ClassifierChain ,作为一种将多个回归组合成一个能够利用目标之间相关性的多目标模型的方法。