Skip to content

1.12. 多类和多标签算法(Multiclass and multilabel algorithms)

警告:

scikit-learn中所有分类器都可以直接进行多分类。除非您想使用不同的多类策略,否则无需使用sklearn.multiclass模块。

sklearn.multiclass模块实现了元估计器(meta-estimators),该估计器是通过将multiclassmultilabel分类问题分解为二分类问题来解决的 。multioutput 还支持回归。

  • 多分类:具有两个以上类别的分类任务。每个样本只能被标记为一个类别。

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

type_of_target(y)的有效多分类的表现形式为 :

  • 1d数组或包含两个以上离散值的列向量。3个样本对应y向量的示例为::
>>> import numpy as np
>>> y = np.array(['apple', 'pear', 'apple'])
>>> print(y)
['apple' 'pear' 'apple']
  • 每行只有一个元素的形状为(n_samples, n_classes)的稀疏二进制矩阵,其中每一列代表一个类别。下面是3个样本的稀疏二进制矩阵y的示例,其中的列依次代表橙色,苹果和梨:
>>> from scipy import sparse
>>> row_ind = np.array([0, 1, 2])
>>> col_ind = np.array([1, 2, 1])
>>> y_sparse = sparse.csr_matrix((np.ones(3), (row_ind, col_ind)))
>>> print(y_sparse)
  (0, 1)        1.0
  (1, 2)        1.0
  (2, 1)        1.0
  • 多标签分类:分类任务使用来自n_classes类别的标签x来标记每个样本 ,其中x的取值可以为0到 n_classes。这可以认为是相互排斥的样本属性。正式而言,对于每个样本,每个类都会输出二进制数字。正类用1表示,负类用0或-1表示。因此,它与运行n_classes 的二分类任务(例如使用sklearn.multioutput.MultiOutputClassifier)相同。这种方法可以独立地处理每个标签,而多标签分类器可以同时处理多个类,从而考虑了它们之间的相关性。

例如,预测与文本文档或视频相关的主题。该文档或视频可以是关于“宗教”,“政治”,“财务”或“教育”这几个主题类别中的一个,或者是一些,又或者是全部类别。

多标签 y的有效表示形式是形状为(n_samples, n_classes)的密集(或稀疏) 二进制矩阵。该矩阵的每列代表一个类。1在各行中分别表示样本已经被标记正类(标记为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]]

稀疏矩阵y的示例:

>>> y_sparse = sparse.csr_matrix(y)
>>> print(y_sparse)
  (0, 0)    1
  (0, 3)    1
  (1, 2)    1
  (1, 3)    1
  • 多输出回归:预测每个样本的多个数值属性。每个属性都是一个数值变量,每个样本要预测的属性数量大于或等于2。某些支持多输出回归的估计器的运行速度比仅运行n_output 个估计器要更快。

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

多标签y 的有效表示形式是形状为(n_samples, n_classes)的浮点密集矩阵 。一维多类变量按列串联 。3个样本对应的y的示例为:

>>> y = np.array([[31.4, 94], [40.5, 109], [25.0, 30]])
>>> print(y)
[[ 31.4  94. ]
 [ 40.5 109. ]
 [ 25.   30. ]]
  • 多输出多分类 任务(也称为多任务分类):它使用一组非二进制属性标记每个样本。属性的数量和每个属性的类的数量都大于2。因此,一个估计器可以处理多个联合分类任务。这既是仅考虑二进制属性的多标签分类任务的一般化,又是仅考虑一个属性的多分类任务的一般化。

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

多标签 y的有效表示形式是形状为(n_samples, n_classes)的浮点密集矩阵 。一维多类变量按列串联 。3个样本对应的y的示例为:

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

请注意,特殊情况下,任何处理多输出多分类(也称为多任务分类)任务的分类器都支持多标签分类任务。多任务分类似于具有不同模型的多输出分类任务。有关更多信息,请参见相关的估计器文档。

所有scikit-learn分类器都能够进行多分类,但是由sklearn.multiclass提供的元估计器(meta-estimators)允许更改它们,以处理超过两个类以上的分类任务,因为这可能会影响分类器的性能(无论是泛化误差还是所需的计算资源)。

摘要

目标数量 目标基数(Target cardinality) 有效 type_of_target
多类别分类 1个 > 2 “多类”
多标签分类 > 1 2(0或1) “多标签指示器”(multilabel-indicator)
多输出回归 > 1 连续 “连续多输出”
多输出多分类 > 1 > 2 “多类多输出”

以下是scikit-learn支持的分类策略汇总。如果您正在使用其中之一,则不需要此类中的元估计器(meta-estimators),除非您需要自定义多分类行为(multiclass behavior):

警告:

当前,在sklearn.metrics中没有测度(metric)来支持多输出多类分类任务。

1.12.1. 多标签分类问题的形式

在多标签学习中,二分类任务的联合集是用标签二进制指标数组表示:每个样本是形状为(n_samples,n_classes)的二进制值的二维数组中的一行:一个样本(即非零元素)对应于标签的子集。诸如数组np.array([[1, 0, 0], [0, 1, 1], [0, 0, 0]])表示第一个样本的标签是0,第二个样本的标签是1和2,而在第三个样本没有标签。

把多标签数据变为标签列表可能更加直观。MultiLabelBinarizer 转变器(transformer)可用于标签的集合和指示(indicator)格式之间的转换。

>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> y = [[2, 3, 4], [2], [0, 1, 3], [0, 1, 2, 3, 4], [0, 1, 2]]
>>> MultiLabelBinarizer().fit_transform(y)
array([[0, 0, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [1, 1, 0, 1, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0]])

1.12.2. 一对多(One-Vs-The-Rest)

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

1.12.2.1. 多分类学习

以下是使用一对多(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, 2])

1.12.2.2. 多标签学习

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

https://scikit-learn.org/stable/_images/sphx_glr_plot_multilabel_0011.png

案例:

1.12.3. 一对一(One-Vs-One)

OneVsOneClassifier为每一个类拟合一个分类器。在预测时,将选择得分最多的类。如果出现平局(在两个类别中具有相同得分),它将通过汇总基础二分类器计算的分类置信度来选择具有最高分类置信度(classification confidence)的类别。

由于该方法需要拟合n_classes * (n_classes - 1) / 2个分类器,因此该方法的复杂度为O(n_classes ^ 2),通常来说运行速度比一对多(one-vs-the-rest)的方法慢。但是,这种方法对于无法随着训练样本n_samples增加而地扩展的算法来说(例如内核算法)可能是有利的 。这是因为每个单独的学习问题仅涉及数据的一小部分,而相对于一对多(one-vs-the-rest)来说,要使用n_classes次完整的数据集。决策函数(decision function)是一对一分类的单调变换的结果。

1.12.3.1. 多分类学习

以下是使用一对一(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])

参考资料:

  • “Pattern Recognition and Machine Learning. Springer”, Christopher M. Bishop, page 183, (First Edition)

1.12.4. 纠错输出代码(Error-Correcting Output-Codes)

基于输出代码的策略与一对多和一对一完全不同。如果使用该策略的话,每个类都在一个欧几里得空间中表示,每个维只能为0或1。另一种表达方式是,每个类都由一个二进制代码(0和1的数组)表示。记录每个类的位置/代码的矩阵称为代码簿(code book)。代码大小是上述空间的维数。直观地,每个类都应该尽可能地由唯一个的代码表示,并且需要设计出一个好的代码簿来优化分类的准确性。在此实现中,我们仅使用[3]中提倡的随机生成的代码簿,尽管在将来可能会添加更复杂的方法来生成代码簿。

在代码簿中每一个二分类器都需要被拟合。在预测时,分类器用于在类空间中投影新点,并选择最接近这些点的类。

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

比起一对多,如果是0到1之间的数字的话,它需要更少的分类器。从理论上讲,log2(n_classes) / n_classes足以代表每个类。但是,实际上,由于log2(n_classes)n_class小得多,因此用log2(n_classes) / n_classes个分类器的话可能不会导致有很好的准确率。

如果是大于1的数字的话,它将需要更多的分类器。在这种情况下,某些分类器理论上可以纠正其他分类器所犯的错误,因此命名为“纠错”。然而,实际上,这可能不会发生,因为分类器错误通常会是相互关联的。纠错输出代码与bagging具有相似的效果。

1.12.4.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.

  • [3] “The error coding method and PICTs”, James G., Hastie T., Journal of Computational and Graphical statistics 7, 1998.

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

1.12.5. 多输出回归

支持在任何回归器 MultiOutputRegressor中添加多输出回归策略。此策略包括为每个目标拟合一个回归器。由于每个目标仅由一个回归变量表示,因此可以通过检查其相应的回归变量来获取有关目标的知识(knowledge)。由于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.6. 多输出分类

支持在任何分类器 MultiOutputClassifier中添加多输出分类策略。该策略包括为每个目标拟合一个分类器。这可以实现多个目标变量分类。此类的目的是扩展估计器,使估计器能够在单个X的预测矩阵上训练并估计一系列目标函数(f1,f2,f3 ...,fn),以预测一系列响应(y1,y2,y3 …,yn)。

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

>>> 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=-1)
>>> 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]])

1.12.7. 分类器链(Classifier Chain)

分类器链(请参阅参考资料ClassifierChain)是一种将多个二分类器结合到单个多标签模型中的方法,该模型能够利用目标之间的相关性。

对于具有N个类别的多标签分类问题,为N个二进制分类器分配0到N-1之间的整数。这些整数定义了链中模型的顺序。然后,每个分类器将在训练数据以及为模型分配了较小数字的真实标签中进行训练。

进行预测时,不使用真实标签。取而代之的是,将每个模型的预测结果作为特征传递到链上的后续模型。

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

参考文献:

Jesse Read, Bernhard Pfahringer, Geoff Holmes, Eibe Frank,

“Classifier Chains for Multi-label Classification”, 2009.

1.12.8. 回归链

回归链(请参阅RegressorChain)类似于ClassifierChain,它是将多个回归结合到单个多目标模型中的一种方法,该模型能够利用目标之间的相关性。

©2007-2019,scikit-learn开发人员(BSD许可证)。 显示此页面源码