机器学习 - 基于 Scikit-learn 多类别和多标签分类算法

多类别分类如果采用GBDT,boost等分类器,逻辑要求较冗繁。在实际应用中建议使用已有算法库直接处理。省时间省力!

针对多分类和多标签问题,虽然深度学习具有较好的表现,但采用传统机器学习方法可以作为对问题深入理解的尝试.

sklearn.multiclass 提供了很多机器学习算法,处理 multiclassmultilabel分类问题,主要是将问题转化为二值分类(binary classification) 问题. 同时也支持 multitarget回归问题.

  • Multiclass 分类: 多类别分类问题,类别classes数大于 2,如,对水果fruit数据集分类,类别有 oranges, apples, pears. Multiclass 分类问题,假设每个样本仅对应一个标签 label,如一张 fruit 图片可能是 apple 或 pear,而不能同时是 apple 和 pear.
  • Mulitlabel 分类: 多标签分类问题,每个样本对应着一组标签 labels. 可以看作是,对一个样本数据点的属性预测,属性间不是互斥关系(mutually exclusive),如文档document中的相关主题topics. 一篇文章可以是 religion, politics, finance, education 中的任意一个,也可以同时是几种,也可以是都不是.
  • Multioutput 回归: 多输出回归问题,每个样本对应一组目标值target values. 可以看作是,对每个样本数据点预测几个属性,如某个地点的风向和地震震级预测.
  • Multioutput-multiclass 分类和 Multi-task 分类: 单个估计器estimator 需要处理几个联合分类任务. 可以看作是,Multi-label 分类问题和 Multi-class 分类问题的泛化. 输出是 2d numpy array 或稀疏矩阵 sparse matrix. 标签 labels 集对于每个输出可以是不同的,例如,一个样本的类别标签可能来自 fruit 标签集(oranges, apples, pears);而其颜色color 标签可能来自 color 标签集(red, green, blue, yellow).

分类器集

1. Multilabel 分类

多标签分类中,二值分类的联合集可以表示为 label binary indicatior 数组形式:每个样本是一个 {0,1}{0,1}\{0, 1\} 二值向量形式.

例如:np.array([[1, 0, 0], [0, 1, 1], [0, 0, 0]]表示第一个样本的 label = 0,第二个样本的 label=2,3,第三个样本没有 label.

标签 label 转换工具 - 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]])

2. One-Vs-Rest

one-vs-rest,也被叫作 one-vs-all,一对多,由 OneVsRestClassifier 实现.

对每一个类别class 拟合一个分类器. 对于每一个分类器,该类别 class 也拟合其它 classes.

特点:

  • 其计算效率较高,只需 N_classes 个分类器.
  • 可解释性好 由于每个类别 class 仅由一个分类器classifier表示,只需利用该分类器即可学习该类的相关信息.

2.1 Multiclass learning

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

2.2 Multilabel learning

OneVsRestClassifier 也支持 multilabel 分类问题.

如:Multilabel classification

机器学习 - 基于 Scikit-learn 多类别和多标签分类算法机器学习 - 基于 Scikit-learn 多类别和多标签分类算法转存失败重新上传取消机器学习 - 基于 Scikit-learn 多类别和多标签分类算法

3. One-Vs-One

OneVsOneClassifier 对每一对pair类别 classes 创建一个分类器classifier. 预测时,最多投票votes 被作为预测类别 class.

特点:

  • 需要 N_classes * (N_classes - 1) / 2 个分类器,其复杂度为 O(N2classes)O(Nclasses2)O(N_{classes}^2), 相比较于 one-vs-rest,效率较慢.
  • 对于某些核算法(kernel algorithms) 比较有优势.

3.1 Multiclass learning

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

4. Error-Correcting Output-Codes

纠错输出编码.

与 one-vs-rest 和 one-vs-one 是完全不同的策略.

纠错输出编码中,每一个类别class 都是 Euclidean 空间表示,每一维是 0 或 1. 将每一个类别class 表示为二值0或1编码的形式.

表示了每一类编码的矩阵为 codebook. 编码 code 的长度即为Euclidean空间的维度.

每一类class 都是由唯一的编码code 来表示的.

好的 codebook 设计应该是能取得最有的分类精度.

这里仅是采用随机生成的 codebook - [The error coding method and PICTs] 论文所提出.

在 fitting 时,二值分类器是 对 codebook 内的每个字节bit 进行拟合.

在 prediction 时,分类器用于得到样本的类别class 空间内的点,然后根据该点与数据类别点的最近距离,选择最近的预测类别.

OutputCodeClassifiercode_size 参数可以自定义分类器数量. 其值小于等于 N_classes.

Solving multiclass learning problems via error-correcting output codes. The error coding method and PICTs.

4.1 Multiclass learning

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

5. Multioutput regression

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

6. Multioutput classification

对每一个目标值 target 拟合一个分类器.

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

7. Classifier Chain

链式分类器(Classifier Chain),ClassifierChain, 是将很多二值分类器组合为一个 multi-label 模型,能够挖掘各 targets 之间的关联性.

对于 N 类的多标签分类问题,N 个二值分类器分别指定一个0 到 N-1 间的整数,表示了在链式分类器中的模型次序order. 依次在训练数据集上训练模型.

在预测时,每个模型的预测结果作为特征,依次传递到下一个模型.

这里,模型的顺序是很重要的.