翻译官方文档:http://scikit-learn.org/stable/modules/multiclass.html#id4
Multiclass and multilabel algorithms
*警告
scikit-learn中所有分类器做多类别分类是开箱即用的。除非你想实验不同的多分类策略,否则没有必要使用sklearn.multiclass模块。*
sklearn.multiclass模块通过将多类别和多标签分类问题分解为二分类问题并执行多个评估器来解决。支持多目标回归。
所有scikit-learn分类器都能进行多类别分类,但是sklearn.multiclass提供的多评估器允许改变控制多于两个类别的方式,这种方式影响分类器性能(通过一般化错误或请求计算资源)。
下面是scikit-learn支持的,根据策略分组的分类器列表;使用下面这些分类器时,除非你想自定义多分类行为,否则不需要使用本类中的多评估器(meta-estimators):
• 自带多类别:
• Multiclass as One-Vs-One:
• Multiclass as One-Vs-All:
• 支持多标签:
• Support multiclass-multioutput:
*警告
目前,sklearn.metrics中没有支持多输出-多类别分类任务的指标。*
Multilabel classification format
在多标签学习中,二分类任务连接集用二进制指示器数组标签表示:每个样本是一个二进制值表示的(样本数,类别数)形状的二维数组的一行:1表示非零元素,对应标签集。一个数组np.array([[1, 0, 0], [0, 1, 1], [0, 0, 0]])表示第一个样本有标签0,第二个样本有标签1和2,第三个样本没有标签。
将多标签数据作为标签集列表生成可能更直观。
MultiLabelBinarizer转换器可以用来在标签集列表和指示器格式间转换。
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]])
在OneVsRestClassifier中的实现策略,也叫one-vs-all。该策略为每个类训练一个分类器。对于每个分类器,适用于一个类区别于其他类。除了它的计算效率(只有n类别分类器需要),这个方法的另一个优势就是可解释性。因为每个类有且仅有一个分类器代表,就可能通过检查其相应的分类器来获得某个类别的信息。这是一个常用策略,通常作为默认选择。
1.12.2.1. 多类别学习
下面是一个使用OvR的多类别学习实例:
from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import LinearSVC
iris = datasets.load_iris()
X, y = iris.data, iris.target
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也支持多标签分类。使用这个特征,给分类器提供一个指示器矩阵,每个cell[i,j]代表样本i,标签j的取值。
Examples:
• Multilabel classification
OneVsOneClassifier为每一对儿类别创建一个分类器。在预测时,得票最多的类作为结果。当出现平局的情况(两个类得票相同),则计算二分类器的成对分类置信水平的和,取最高组合置信水平的类作为最终结果。
因为它需要训练n_classes * (n_classes - 1) / 2个分类器,复杂度为O(n_classes^2),这种方法通常比one-vs-the-rest慢。但是,这种方法可能对不能处理大规模数据的核函数算法有利。因为它每次学习只涉及数据的子集,而对于one-vs-the-rest,每次都要使用全部数据集。
1.12.3.1. 多类别学习
下面是使用OvO的多类别学习实例:
from sklearn import datasets
from sklearn.multiclass import OneVsOneClassifier
from sklearn.svm import LinearSVC
iris = datasets.load_iris()
X, y = iris.data, iris.target
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])
References:
• “Pattern Recognition and Machine Learning. Springer”, Christopher M. Bishop, page 183, (First Edition)
Error-Correcting Output-Codes
输出编码基于的策略与one-vs-the-rest and one-vs-one非常不同。后面两种策略中,每个类在欧式空间中表示,每一维只能是0或1。另一种编码方式是每个类由二进制编码(0、1数组)表示。保留每个类位置/编码轨迹的矩阵称为密码本。编码长度是上述空间的维度。直观上,每个类应该使用编码尽可能唯一的表示出来,一个好的密码本应该设计成能够优化分类精度。这里的实现,我们仅使用了在【3】中提倡的随机生成密码,本,将来可能会添加更精巧的方法。
在训练期间,二分类器在密码本中的每一位都被训练。在预测时,分类器用于在类空间中预测新点,与点最近的类被选中。
在OutputCodeClassifier中,code_size属性允许用户控制被使用的分类器的数量。它是一个全部类别数量的百分比。
0和1之间的一个数将需要比one-vs-the-rest更少的分类器。理论上,log2(n_classes) / n_classes就足够清楚的表示每个类。但是,实际情况中,它可能得不出好的准确率,因为log2(n_classes)比classes小太多了。
一个大于1的数需要比one-vs-the-rest更多的分类器。这种情况下,一些分类器将在理论上为其它分类器纠错,因此命名为“error-correcting”。但是实际上,分类器错误被纠正时是不可能发生的。纠错输出码与bagging有类似的作用。
1.12.4.1. 多类别学习
下面是一个使用 Output-Codes的多类别学习的实例:
from sklearn import datasets
from sklearn.multiclass import OutputCodeClassifier
from sklearn.svm import LinearSVC
iris = datasets.load_iris()
X, y = iris.data, iris.target
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])
References:
Multioutput regression
多输出回归可以用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]])
Multioutput classification
多输出分类可以通过使用MultiOutputClassifier附加给任意一个分类器。这个策略为每个目标训练一个分类器,允许多个目标变量分类。这个类的目标是扩展评估器,使其能够估计一系列目标函数(f1,f2,f3…,fn),这些函数使用一个X预测矩阵来预测一系列结果(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(n_estimators=100, 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]])
Classifier Chain
分类器链是一种将多个二分类器组合成一个能够运用目标之间的关系多标签分类模型的方法。
对于一个有N个类的多标签分类问题,N二分类器被定义为一个0到N-1之间的整数。这些整数定义模型在链中的顺序。每个分类器使用训练数据集加上较低序号模型给出的实际类标签进行训练。
预测时,不使用实际标签,而是将每个模型的预测作为特征传递给链中后来的模型。
很明显链的顺序非常重要。链中第一个模型没有关于其它标签的信息,而最后一个模型有其它所有标签的标志特征。通常情况下并不知道模型链的最优顺序,因此常用随机顺序链进行训练,然后去预测的平均值。
References:
Jesse Read, Bernhard Pfahringer, Geoff Holmes, Eibe Frank,
“Classifier Chains for Multi-label Classification”, 2009.