本文转载自
点击上方"枫叶AI",获取更多信息
1、集成学习概述
集成学习的原理正如盲人摸象这个古代寓言所揭示的道理类似:一群盲人第一次遇到大象,想要通过触觉来了解大象。每个人都摸到大象身体的不同部位。但只摸到不同部分,比如鼻子或一条腿。这些人描述的大象是这样的:“它像一条蛇”,“像一根柱子或一棵树”,等等。这些盲人就好比机器学习模型,每个人都是根据自己的假设,并从自己的角度来理解训练数据的多面性。每个人都得到真相的一部分,但不是全部真相。将他们的观点汇集在一起,你就可以得到对数据更加准确的描述。大象是多个部分的组合,每个盲人说的都不完全准确,但综合起来就成了一个相当准确的观点。
集成学习(ensemble learning)可以说是现在非常火爆的机器学习方法了。目前,集成方法在许多著名的机器学习比赛(如 Netflix、KDD 2009 和 Kaggle 比赛)中能够取得很好的名次。
集成学习本身不是一个单独的机器学习算法,而是通过构建并结合多个机器学习器来完成学习任务。也就是我们常说的“博采众长”。集成学习可以用于分类问题集成,回归问题集成,特征选取集成,异常点检测集成等等,可以说所有的机器学习领域都可以看到集成学习的身影。
集成学习的主要思想:对于一个比较复杂的任务,综合许多人的意见来进行决策往往比一家独大好,正所谓集思广益。其过程如下:
一般来说集成学习可以分为三大类:
①用于减少方差的bagging(方差描述的是预测值作为随机变量的离散程度)
②用于减少偏差的boosting(偏差描述的是预测值和真实值之间的差异,即提高拟合能力)
③用于提升预测效果的stacking
18.1.1 Bagging
Bagging是引导聚合的意思。减少一个估计方差的一种方式就是对多个估计进行平均。
Bagging使用装袋采样来获取数据子集训练基础学习器。通常分类任务使用投票的方式集成,而回归任务通过平均的方式集成。
给定一个大小为n的训练集 D,Bagging算法从中均匀、有放回地选出 m个大小为 n' 的子集Di,作为新的训练集。在这 m个训练集上使用分类、回归等算法,则可得到 m个模型,再通过取平均值、取多数票等方法综合产生预测结果,即可得到Bagging的结果。具体如下图:
对于Bagging需要注意的是,每次训练集可以取全部的特征进行训练,也可以随机选取部分特征训练,例如随机森林就是每次随机选取部分特征。
常用的集成算法模型是随机森林和随机树等。
在随机森林中,每个树模型都是装袋采样训练的。另外,特征也是随机选择的,最后对于训练好的树也是随机选择的。
这种处理的结果是随机森林的偏差增加的很少,而由于弱相关树模型的平均,方差也得以降低,最终得到一个方差小,偏差也小的模型。
18.1.2 boosting
Boosting指的是通过算法集合将弱学习器转换为强学习器。boosting的主要原则是训练一系列的弱学习器,所谓弱学习器是指仅比随机猜测好一点点的模型,例如较小的决策树,训练的方式是利用加权的数据。在训练的早期对于错分数据给予较大的权重。
对于训练好的弱分类器,如果是分类任务按照权重进行投票,而对于回归任务进行加权,然后再进行预测。boosting和bagging的区别在于是对加权后的数据利用弱分类器依次进行训练。
boosting是一族可将弱学习器提升为强学习器的算法,这族算法的工作机制类似:
(1)先从初始训练集训练出一个基学习器;
(2)再根据基学习器的表现对训练样本分布进行调整,使得先前基学习器做错的训练样本在后续受到更多关注;
(3)基于调整后的样本分布来训练下一个基学习器;
(4)重复进行上述步骤,直至基学习器数目达到事先指定的值T,最终将这T个基学习器进行加权结合。具体步骤如下图
如果上面这个图还不太直观,大家可参考以下简单示例:
1、假设我们有如下样本图:
2、第一次分类
第2次分类
在图2中被正确测的点有较小的权重(尺寸较小),而被预测错误的点(+)则有较大的权重(尺寸较大)
第3次分类
在图3中被正确测的点有较小的权重(尺寸较小),而被预测错误的点(-)则有较大的权重(尺寸较大)。
第4次综合以上分类
下面描述的算法是最常用的一种boosting算法,叫做AdaBoost,表示自适应boosting。
AdaBoost算法每一轮都要判断当前基学习器是否满足条件,一旦条件不满足,则当前学习器被抛弃,且学习过程停止。
AdaBoost算法中的个体学习器存在着强依赖关系,应用的是串行生成的序列化方法。每一个基生成器的目标,都是为了最小化损失函数。所以,可以说AdaBoost算法注重减小偏差。
由于属于boosting算法族,采用的是加性模型,对每个基学习器的输出结果加权处理,只会得到一个输出预测结果。所以标准的AdaBoost只适用于二分类任务。基于Boosting思想的除AdaBoost外,还有GBDT、XGBoost等。
18.1.3 Stacking
将训练好的所有基模型对训练基进行预测,第j个基模型对第i个训练样本的预测值(概率值或标签)将作为新的训练集中第i个样本的第j个特征值,最后基于新的训练集进行训练。同理,预测的过程也要先经过所有基模型的预测形成新的测试集,最后再对测试集进行预测。如下图所示。
上图可简化为:
其中Meta-Classifier在实际应用中通常使用单层logistic回归模型。
具体算法为:
18.1.3 .1Stacking中元分类层
为何要Meta-Classifier层?设置该层的目的是啥?其原理是什么?等等或许你还不很清楚,没关系。你看了下面这个说明或许就清楚多了。
让我们假设有三个学生名为LR,SVM,KNN,他们争论一个物理问题,他们对正确的答案可能有不同的看法:
他们认为没有办法相互说服他们的情况,他们通过平均估计他们做民主的事情,这个案例是14.他们使用了最简单的集合形式-AKA模型平均。
他们的老师,DL小姐 - 一位数学老师 - 见证了学生们所拥有的论点并决定提供帮助。她问“问题是什么?”,但是学生们拒绝告诉她(因为他们知道提供所有信息对他们不利,除了他们认为她可能会觉得愚蠢他们在争论这么微不足道的事情)。然而,他们确实告诉她这是一个与物理相关的论点。
在这种情况下,教师无法访问初始数据,因为她不知道问题是什么。然而,她确实非常了解学生 - 他们的优点和缺点,她决定她仍然可以帮助解决这个问题。使用历史信息,了解学生过去的表现,以及她知道SVM喜欢物理并且在这个课程中表现优异的事实(加上她的父亲在青年科学家的物理学院工作),她认为最多适当的答案会更像17。
在这种情况下,教师(DL)是元学习者。她使用其他模型(学生)输出的结果作为输入数据。然后,她将其与历史信息结合起来,了解学生过去的表现,以便更好地估计(并帮助解决冲突)。
然而......物理老师RF先生的意见略有不同。他一直在那里,但他一直等到这一刻才行动!RF先生最近一直在教授LR私人物理课程,以提高他的成绩(错过DL不知道的事情),他认为LR对最终估计的贡献应该更大。因此他声称正确的答案更像是16!
在这种情况下,RF先生也是一个元学习者,他用不同的逻辑处理历史数据 - 他可以访问比DL小姐更多的来源(或不同的历史信息)。
只有校长GBM做出决定,才能解决此争议!GBM不知道孩子们说了什么,但他很了解他的老师,他更热衷于信任他的物理老师(RF)。他总结答案更像是16.2。
在这种情况下,校长是元级学习者或元学习者的元学习者,并且通过处理他的老师的历史信息,他仍然可以提供比他们的结果的简单平均值更好的估计。
参考文档:
18.1.3.2Stacking的几种方法
1) 使用分类器产生的特征输出作为meta-classifier的输入
基本使用方法就是,使用前面分类器产生的特征输出作为最后总的meta-classifier的输入数据,以下为利用stacking的基本使用方法实例。
(1)生成数据
from sklearn import datasetsiris = datasets.load_iris()X, y = iris.data[:, 1:3], iris.target
(2)导入需要的库
from sklearn import model_selectionfrom sklearn.linear_model import LogisticRegressionfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.naive_bayes import GaussianNB from sklearn.ensemble import RandomForestClassifierfrom mlxtend.classifier import StackingClassifierimport numpy as np
(3)训练各种基模型
clf1 = KNeighborsClassifier(n_neighbors=1)clf2 = RandomForestClassifier(random_state=1)clf3 = GaussianNB()lr = LogisticRegression()sclf = StackingClassifier(classifiers=[clf1, clf2, clf3], meta_classifier=lr)print('3-fold cross validation:\n')for clf, label in zip([clf1, clf2, clf3, sclf], ['KNN', 'Random Forest', 'Naive Bayes', 'StackingClassifier']): scores = model_selection.cross_val_score(clf, X, y, cv=3, scoring='accuracy') print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
运行结果
3-fold cross validation:
Accuracy: 0.91 (+/- 0.01) [KNN]
Accuracy: 0.91 (+/- 0.06) [Random Forest]
Accuracy: 0.92 (+/- 0.03) [Naive Bayes]
Accuracy: 0.95 (+/- 0.03) [StackingClassifier]
(4)可视化结果
%matplotlib inlineimport matplotlib.pyplot as pltfrom mlxtend.plotting import plot_decision_regionsimport matplotlib.gridspec as gridspecimport itertoolsgs = gridspec.GridSpec(2, 2)fig = plt.figure(figsize=(10,8))for clf, lab, grd in zip([clf1, clf2, clf3, sclf], ['KNN', 'Random Forest', 'Naive Bayes', 'StackingClassifier'], itertools.product([0, 1], repeat=2)): clf.fit(X, y) ax = plt.subplot(gs[grd[0], grd[1]]) fig = plot_decision_regions(X=X, y=y, clf=clf) plt.title(lab)
运行结果
使用网格方法选择超参数
from sklearn.linear_model import LogisticRegressionfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.naive_bayes import GaussianNB from sklearn.ensemble import RandomForestClassifierfrom sklearn.model_selection import GridSearchCVfrom mlxtend.classifier import StackingClassifier# Initializing modelsclf1 = KNeighborsClassifier(n_neighbors=1)clf2 = RandomForestClassifier(random_state=1)clf3 = GaussianNB()lr = LogisticRegression()sclf = StackingClassifier(classifiers=[clf1, clf2, clf3], meta_classifier=lr)params = {'kneighborsclassifier__n_neighbors': [1, 5], 'randomforestclassifier__n_estimators': [10, 50], 'meta-logisticregression__C': [0.1, 10.0]}grid = GridSearchCV(estimator=sclf, param_grid=params, cv=5, refit=True)grid.fit(X, y)cv_keys = ('mean_test_score', 'std_test_score', 'params')for r, _ in enumerate(grid.cv_results_['mean_test_score']): print("%0.3f +/- %0.2f %r" % (grid.cv_results_[cv_keys[0]][r], grid.cv_results_[cv_keys[1]][r] / 2.0, grid.cv_results_[cv_keys[2]][r]))print('Best parameters: %s' % grid.best_params_)print('Accuracy: %.2f' % grid.best_score_)
运行结果
0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}
0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}
0.927 +/- 0.02 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}
0.913 +/- 0.03 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}
0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}
0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}
0.933 +/- 0.02 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}
0.940 +/- 0.02 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}
Best parameters: {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}
Accuracy: 0.94
2)使用类别概率值作为meta-classfier的输入
另一种使用第一层基本分类器产生的类别概率值作为meta-classfier的输入,这种情况下需要将StackingClassifier的参数设置为 use_probas=True。如果将参数设置为 average_probas=True,那么这些基分类器对每一个类别产生的概率值会被平均,否则会拼接。
例如有两个基分类器产生的概率输出为:
classifier 1: [0.2, 0.5, 0.3]
classifier 2: [0.3, 0.4, 0.4]
1) average = True :
产生的meta-feature 为:[0.25, 0.45, 0.35]
2) average = False:
产生的meta-feature为:[0.2, 0.5, 0.3, 0.3, 0.4, 0.4]
以下为具体实例
from sklearn import datasetsiris = datasets.load_iris()X, y = iris.data[:, 1:3], iris.targetfrom sklearn import model_selectionfrom sklearn.linear_model import LogisticRegressionfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.naive_bayes import GaussianNB from sklearn.ensemble import RandomForestClassifierfrom mlxtend.classifier import StackingClassifierimport numpy as npclf1 = KNeighborsClassifier(n_neighbors=1)clf2 = RandomForestClassifier(random_state=1)clf3 = GaussianNB()lr = LogisticRegression()sclf = StackingClassifier(classifiers=[clf1, clf2, clf3], use_probas=True, average_probas=False, meta_classifier=lr)print('3-fold cross validation:\n')for clf, label in zip([clf1, clf2, clf3, sclf], ['KNN', 'Random Forest', 'Naive Bayes', 'StackingClassifier']): scores = model_selection.cross_val_score(clf, X, y, cv=3, scoring='accuracy') print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
运行结果
3-fold cross validation:
Accuracy: 0.91 (+/- 0.01) [KNN]
Accuracy: 0.91 (+/- 0.06) [Random Forest]
Accuracy: 0.92 (+/- 0.03) [Naive Bayes]
Accuracy: 0.94 (+/- 0.03) [StackingClassifier]
显然,用stacking方法的精度(Accuracy: 0.94)明显好于单个模型的精度。
3)使用堆叠分类及网格搜索
使用堆叠分类及网格搜索(Stacked Classification and GridSearch)方法,要为scikit-learn网格搜索设置参数网格,我们只需在参数网格中提供估算器的名称 - 在meta-regressor的特殊情况下,我们附加'meta-'前缀即可,以下为代码实例。
from sklearn.linear_model import LogisticRegressionfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.naive_bayes import GaussianNB from sklearn.ensemble import RandomForestClassifierfrom sklearn.model_selection import GridSearchCVfrom mlxtend.classifier import StackingClassifier# Initializing modelsclf1 = KNeighborsClassifier(n_neighbors=1)clf2 = RandomForestClassifier(random_state=1)clf3 = GaussianNB()lr = LogisticRegression()sclf = StackingClassifier(classifiers=[clf1, clf2, clf3], meta_classifier=lr)params = {'kneighborsclassifier__n_neighbors': [1, 5], 'randomforestclassifier__n_estimators': [10, 50], 'meta-logisticregression__C': [0.1, 10.0]}grid = GridSearchCV(estimator=sclf, param_grid=params, cv=5, refit=True)grid.fit(X, y)cv_keys = ('mean_test_score', 'std_test_score', 'params')for r, _ in enumerate(grid.cv_results_['mean_test_score']): print("%0.3f +/- %0.2f %r" % (grid.cv_results_[cv_keys[0]][r], grid.cv_results_[cv_keys[1]][r] / 2.0, grid.cv_results_[cv_keys[2]][r]))print('Best parameters: %s' % grid.best_params_)print('Accuracy: %.2f' % grid.best_score_)
运行结果
0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}
0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}
0.967 +/- 0.01 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}
0.967 +/- 0.01 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}
0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}
0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}
0.967 +/- 0.01 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}
0.967 +/- 0.01 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}
Best parameters: {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}
Accuracy: 0.97
最一句是各参数最佳匹配模型的结果,显然,这个精度高于其他情况的精度。
如果我们计划多次使用回归算法,我们需要做的就是在参数网格中添加一个额外的数字后缀,如下所示:
from sklearn.model_selection import GridSearchCV# Initializing modelsclf1 = KNeighborsClassifier(n_neighbors=1)clf2 = RandomForestClassifier(random_state=1)clf3 = GaussianNB()lr = LogisticRegression()sclf = StackingClassifier(classifiers=[clf1, clf1, clf2, clf3], meta_classifier=lr)params = {'kneighborsclassifier-1__n_neighbors': [1, 5], 'kneighborsclassifier-2__n_neighbors': [1, 5], 'randomforestclassifier__n_estimators': [10, 50], 'meta-logisticregression__C': [0.1, 10.0]}grid = GridSearchCV(estimator=sclf, param_grid=params, cv=5, refit=True)grid.fit(X, y)cv_keys = ('mean_test_score', 'std_test_score', 'params')for r, _ in enumerate(grid.cv_results_['mean_test_score']): print("%0.3f +/- %0.2f %r" % (grid.cv_results_[cv_keys[0]][r], grid.cv_results_[cv_keys[1]][r] / 2.0, grid.cv_results_[cv_keys[2]][r]))print('Best parameters: %s' % grid.best_params_)print('Accuracy: %.2f' % grid.best_score_)
运行结果
0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}
0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}
0.967 +/- 0.01 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-....
0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}
0.967 +/- 0.01 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}
.......................................
0.967 +/- 0.01 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}
Best parameters: {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}
Accuracy: 0.97
StackingClassifier还可以对分类器参数进行网格搜索。但是,由于目前scikit-learn中GridSearchCV的实现,不可能同时搜索不同分类器和分类器参数。例如,虽然以下参数字典有效。
4)给不同及分类器不同特征
给不同及分类器不同特征是对训练基中的特征维度进行操作的,这次不是给每一个基分类器全部的特征,而是给不同的基分类器分不同的特征,即比如基分类器1训练前半部分特征,基分类器2训练后半部分特征(可以通过sklearn 的pipelines 实现)。最终通过StackingClassifier组合起来。以下为代码实例。
from sklearn.datasets import load_irisfrom mlxtend.classifier import StackingClassifierfrom mlxtend.feature_selection import ColumnSelectorfrom sklearn.pipeline import make_pipelinefrom sklearn.linear_model import LogisticRegressioniris = load_iris()X = iris.datay = iris.targetpipe1 = make_pipeline(ColumnSelector(cols=(0, 2)), LogisticRegression())pipe2 = make_pipeline(ColumnSelector(cols=(1, 2, 3)), LogisticRegression())sclf = StackingClassifier(classifiers=[pipe1, pipe2], meta_classifier=LogisticRegression())sclf.fit(X, y)
参考文档:
https://rasbt.github.io/mlxtend/user_guide/classifier/StackingClassifier/
2、投票分类器(VotingClassifier)
投票分类器的原理是结合了多个不同的机器学习分类器,使用多数票或者平均预测概率(软票),预测类标签。这类分类器对一组相同表现的模型十分有用,同时可以平衡各自的弱点。投票分类又可进一步分为多数投票分类(Majority Class Labels)、加权平均概率(soft vote,软投票)。
2.1多数投票分类(MajorityVote Class)
多数投票分类的分类原则为预测标签不同时,按最多种类为最终分类;如果预测标签相同时,则按顺序,选择排在第1的标签为最终分类。举例如下:
预测类型的标签为该组学习器中相同最多的种类:例如给出的分类如下
分类器1 -> 标签1
分类器2 -> 标签1
分类器3 -> 标签2
投票分类器(voting=‘hard’)则该预测结果为‘标签1’。
在各个都只有一个的情况下,则按照顺序来,如下:
分类器1 -> 标签2
分类器2 -> 标签1
最终分类结果为“标签2”
2.1.1 Iris数据集概述
首先,我们取得数据,下面这个链接中有数据的详细介绍,并可以下载数据集。https://archive.ics.uci.edu/ml/datasets/Iris
从数据的说明上,我们可以看到Iris有4个特征,3个类别。但是,我们为了数据的可视化,我们只保留2个特征(sepal length和petal length)。数据可视化代码如下:
%matplotlib inlineimport pandas as pdimport matplotlib.pylab as pltimport numpy as np# 加载Iris数据集作为DataFrame对象df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data', header=None) X = df.iloc[:, [0, 2]].values # 取出2个特征,并把它们用Numpy数组表示plt.scatter(X[:50, 0], X[:50, 1],color='red', marker='o', label='setosa') # 前50个样本的散点图plt.scatter(X[50:100, 0], X[50:100, 1],color='blue', marker='x', label='versicolor') # 中间50个样本的散点图plt.scatter(X[100:, 0], X[100:, 1],color='green', marker='+', label='Virginica') # 后50个样本的散点图plt.xlabel('petal length')plt.ylabel('sepal length')plt.legend(loc=2) # 把说明放在左上角,具体请参考官方文档plt.show()
示例代码如下:
运行结果如下:
Accuracy: 0.90 (+/- 0.05) [Logistic Regression]
Accuracy: 0.93 (+/- 0.05) [Random Forest]
Accuracy: 0.91 (+/- 0.04) [naive Bayes]
Accuracy: 0.95 (+/- 0.05) [Ensemble]
示例代码如下:
from sklearn import datasetsfrom sklearn import cross_validationfrom sklearn.linear_model import LogisticRegressionfrom sklearn.naive_bayes import GaussianNBfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.ensemble import VotingClassifieriris = datasets.load_iris()X, y = iris.data[:, 1:3], iris.targetclf1 = LogisticRegression(random_state=1)clf2 = RandomForestClassifier(random_state=1)clf3 = GaussianNB()eclf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)], voting='hard', weights=[2,1,2])for clf, label in zip([clf1, clf2, clf3, eclf], ['Logistic Regression', 'Random Forest', 'naive Bayes', 'Ensemble']): scores = cross_validation.cross_val_score(clf, X, y, cv=5, scoring='accuracy') print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std
运行结果如下:Accuracy: 0.90 (+/- 0.05) [Logistic Regression]Accuracy: 0.93 (+/- 0.05) [Random Forest]Accuracy: 0.91 (+/- 0.04) [naive Bayes]Accuracy: 0.95 (+/- 0.05) [Ensemble]
2.2多数投票分类(MajorityVote Class)
相对于多数投票(hard voting),软投票返回预测概率值的总和最大的标签。可通过参数weights指定每个分类器的权重;若权重提供了,在计算时则会按照权重计算,然后取平均;标签则为概率最高的标签。
举例说明,假设有3个分类器,3个类,每个分类器的权重为:w1=1,w2=1,w3=1。如下表:
下面例子为线性SVM,决策树,K邻近分类器:
from sklearn import datasets from sklearn.tree import DecisionTreeClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.svm import SVC from itertools import product from sklearn.ensemble import VotingClassifier #Loading some example data iris = datasets.load_iris() X = iris.data[:, [0,2]] y = iris.target #Training classifiers clf1 = DecisionTreeClassifier(max_depth=4) clf2 = KNeighborsClassifier(n_neighbors=7) clf3 = SVC(kernel='rbf', probability=True) eclf = VotingClassifier(estimators=[('dt', clf1), ('knn', clf2), ('svc', clf3)], voting='soft', weights=[2,1,2]) clf1 = clf1.fit(X,y) clf2 = clf2.fit(X,y) clf3 = clf3.fit(X,y) eclf = eclf.fit(X,y)##这些分类器分类结果x_min,x_max = X[:,0].min()-1,X[:,0].max()+1 y_min,y_max = X[:,1].min()-1,X[:,1].max()+1 xx,yy = np.meshgrid(np.arange(x_min,x_max,0.1), np.arange(y_min,y_max,0.1)) f, axarr = plt.subplots(2, 2, sharex='col', sharey='row', figsize=(10, 8)) for idx, clf, tt in zip(product([0, 1], [0, 1]), [clf1, clf2, clf3, eclf], ['Decision Tree (depth=4)', 'KNN (k=7)', 'Kernel SVM', 'Soft Voting']): Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) axarr[idx[0], idx[1]].contourf(xx, yy, Z, alpha=0.4) axarr[idx[0], idx[1]].scatter(X[:, 0], X[:, 1], c=y, alpha=0.8) axarr[idx[0], idx[1]].set_title(tt) plt.show()
3自适应分类器(Adaboost)
Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器)。其算法本身是通过改变数据分布来实现的,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次训练得到的分类器最后融合起来,作为最后的决策分类器。使用adaboost分类器可以排除一些不必要的训练数据特征,并放在关键的训练数据上面。
下面的例子展示了AdaBoost算法拟合100个弱学习器
from sklearn.model_selection import cross_val_score from sklearn.datasets import load_iris from sklearn.ensemble import AdaBoostClassifier iris = load_iris() clf = AdaBoostClassifier(n_estimators=100) scores = cross_val_score(clf, iris.data, iris.target)
输出结果为:0.95996732026143794
点个再看,鼓励下吧