1. 集成学习
集成学习(ensemble learning)通过构建并结合多个学习器来完成学习任务,有时也被称为多分类器系统(multi-classifier system)、基于委员会的学习(committee-based learning)等。构成集成学习的学习器称为个体学习器(individual learner)。集成学习可以有效减小个体学习器的方差(bagging),偏差(boosting),或者改进预测(stacking)。个体学习器可以是KNN、逻辑回归、SVM、朴素贝叶斯、决策树等多种基础机器学习算法。
2. 集成学习的种类
根据个体学习器是否同属一个种类,可以将集成学习分为同质和异质两种类型。 根据个体学习器之间的依赖关系又可以分为并行和串行。根据个体学习器之间的结合方式可以分为平均、投票、学习。不同的分类标准得到不同的分类结果,一个集成学习算法可属于多种类别,相互不冲突,不同的分类方式反应了看待问题的角度不同而已,并不相斥。
2.1 集成方式
异质指是所有的个体学习器不全是一个种类的。例如对分类问题,对训练集采用支持向量机个体学习器、逻辑回归个体学习器和朴素贝叶斯个体学习器来学习,再通过某种结合策略来确定最终的分类强学习器,异质集成中的个体学习器又称为组件学习器(component learner)。
同质表示各个基学习器都属于同一个种类,比如都是决策树学习器,或者同为神经网络学习器。 目前来说,同质个体学习器的应用最为广泛。一般的集成学习均指同质个体学习器。而同质个体学习器使用最多的模型是CART决策树和神经网络。同质集成中的个体学习器称为基学习器(base learner),相应的学习算法称为基学习算法(base learning algorithm)。
2.2 学习模式
按照个体学习器之间是否存在依赖关系可以分为两类。 第一种是个体学习器之间不存在强依赖关系,一系列个体学习器可以并行生成,代表算法有套袋法(Bagging)和随机森林(Random Forest)系列算法。 第二类是个体学习器之间存在强依赖关系,一般来说当前的个体学习器的输入要依赖于上一个个体学习器的输出,一系列个体学习器基本都需要串行生成,代表算法是提升学习Boosting系列算法。
3.3 结合策略
对于数值型输出算法(回归任务),最常见的结合策略是使用平均法,平均法又分为简单平均和加权平均。一般在个体学习器性能相差较大时使用加权平均,反之在个体学习器性能相差不大时,使用简单平均。
对于分类任务来说,常见的结合策略是使用投票法,根据输出值数量,投票法又可分为绝对多数投票法、相对多数投票法和加权投票法。根据输出值类型,可划分为软投票(概率值),硬投票(标记值)。
通过另一个学习器将所有个体学习器进行结合的方式叫学习法,这里把个体学习器称为初级学习器,用于结合的学习器称为次级学习器或元学习器。初级学习器的输出被当作次级学习器的样例输入特征,初始样本的标记仍被当作样例标记进行训练。代表算法是Stacking(这里笔者不做过多介绍,在神经网络算法再介绍)
4. 常见的集成学习
常见的集成学习方法如上所示,本文通过sklearn封装的方法进行演示,其需要的引入的模块和数据准备代码如下所示:
import pandas as pd
from sklearn.linear_model import LogisticRegression, LinearRegression
from sklearn.svm import SVC, SVR
from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import VotingRegressor
from sklearn.model_selection import train_test_split
from sklearn import datasets
import numpy as np
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import RandomForestClassifier
def dataInit(type="moons"):
if type == "moons":
X, y = datasets.make_moons(n_samples=500, noise=0.3, random_state=42)
elif type == "boston":
data_url = "http://lib.stat.cmu.edu/datasets/boston"
boston = pd.read_csv(data_url, sep="\s+", skiprows=22, header=None)
data = np.hstack([boston.values[::2, :], boston.values[1::2, :2]])
target = boston.values[1::2, 2]
X, y = data[:, (2, 5)], target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
return X_train, X_test, y_train, y_test, X, y
4.1 投票集成法
根据不同的模型计算的结果进行投票,得到最终结果,sklearn封装了投票集成的方法,可使用此集成方法处理回归和分类问题,使用逻辑回归、支撑向量机、决策树进行分类问题的集成学习,具体代码如下所示:
def votingClf():
# 1 Voting Classifier 解决分类问题
X_train, X_test, y_train, y_test, X, y = dataInit(type="moons")
voting_clf = VotingClassifier(estimators=[
('log_clf', LogisticRegression()),
('svm_clf', SVC()),
('dt_clf', DecisionTreeClassifier(random_state=666))],
voting='hard') # 当参数为soft时,即为带概率的加权投票
voting_clf.fit(X_train, y_train)
hardVotingScore = voting_clf.score(X_test, y_test)
print("hard Voting Classifier score = {}.".format(hardVotingScore))
使用线性回归、支撑向量机、决策树进行回归问题的集成学习,代码如下:
def votingReg():
# 1 Voting Regressor 解决回归问题
X_train, X_test, y_train, y_test, X, y = dataInit(type="boston")
voting_reg = VotingRegressor(estimators=[
('lin_reg', LinearRegression()),
('svr_reg', SVR()),
('tree_reg', DecisionTreeRegressor(random_state=666))])
voting_reg.fit(X_train, y_train)
votingRegScore = voting_reg.score(X_test, y_test)
print("Voting Regressor score = {}.".format(votingRegScore))
4.2 bagging 套袋法
Bagging(Bootstrap Aggregating)方法又叫做自举汇聚法,即:在原始数据集上采样有放回的抽样的方式,重新选择出S个新数据集来分别训练S个分类器的集成技术。也就是说这些模型的训练数据中允许存在重复数据,Bagging方式是有放回的抽样。
Bagging方法训练出来的模型在预测新样本分类的时候,会使用多数投票或者求均值的方式来统计最终的分类结果,Bagging方法中的基学习器可以是基本的算法模型,eg: Linear、 Ridge、 Lasso、logistic、Softmax、ID3、c4.5、CART、SWM、KNN等,随机森林就是基于Bagging的方法。
以下代码是使用决策树作为基学习器,通过baging的方式集成训练处理分类问题:
# 使用 Bagging 集成学习
def bagingClf():
X_train, X_test, y_train, y_test, X, y = dataInit(type="moons")
bagging_clf = BaggingClassifier(DecisionTreeClassifier(),
n_estimators=500, # 进行500次取样
max_samples=200, # 每次取样200个样本
bootstrap=True, # 对样本进行放回取样
oob_score=True, # 使用out of bag数据作为测试集
n_jobs=-1, # 最大并行计算
max_features=2, # 每次取样的特征数量
bootstrap_features=True) # 是否开启对特征进行放回采样
bagging_clf.fit(X, y)
bagging_clf_score = bagging_clf.oob_score_
print("Bagging Classifier out of bag score = {}.".format(bagging_clf_score))
同时也可以通过baging的方式集成决策树进行回归问题处理:
def bagingReg():
X_train, X_test, y_train, y_test, X, y = dataInit(type="moons")
bagging_reg = BaggingRegressor(DecisionTreeRegressor(),
n_estimators=500, # 进行500次取样
max_samples=200, # 每次取样200个样本
bootstrap=True, # 对样本进行放回取样
oob_score=True, # 使用out of bag数据作为测试集
n_jobs=-1, # 最大并行计算
max_features=2, # 每次取样的特征数量
bootstrap_features=True) # 是否开启对特征进行放回采样
bagging_reg.fit(X, y)
bagging_reg_score = bagging_reg.oob_score_
print("Bagging Regressor out of bag score = {}.".format(bagging_reg_score))
Random Forest 随机森林
随机森林属于gagging算法的一种,其基本原理如下:
第一步,从原始数据中以有放回的方式随机取样得到n个训练数据集。
第二步 从每个训练数据集中随机选择K个特征(K小于原始数据总共的特征)。
第三步,反复根据这K个特征建立起来m棵决策树。
第四步,应用每个决策树来预测结果,并且保存所有预测的结果。
第五步,对分类模型进行投票,计算每个预测结果的得票数,选择得票数最高的模型作为最终决策。
以下是基于sklearn封装的方法进行随机森林代处理分类问题的码实现:
# 随机森林
def RandomForestClf():
X_train, X_test, y_train, y_test, X, y = dataInit(type="moons")
# 随机森林: 使用多个决策树进行集成学习,决策树在节点划分上,在随机的特征子集上寻找最优划分特征
rf_clf = RandomForestClassifier(n_estimators=500, oob_score=True, random_state=666, n_jobs=-1)
rf_clf.fit(X, y)
test_score = rf_clf.oob_score_
print("Random Forest Classifier test_score = {}.".format(test_score))
# 极其随机森林 Extra-Trees:决策树在节点划分上,使用随机的特征和随机的阈值,提供额外的随机性,抑制过拟合,但增大了bias偏差
et_clf = ExtraTreesClassifier(n_estimators=500, bootstrap=True, oob_score=True, random_state=666, n_jobs=-1)
et_clf.fit(X, y)
test_score = et_clf.oob_score_
print("Extra Trees Classifier test_score = {}.".format(test_score))
以下是基于sklearn封装的方法进行随机森林代处理回归问题的码实现:
def RandomForestReg():
X_train, X_test, y_train, y_test, X, y = dataInit(type="boston")
# 随机森林: 使用多个决策树进行集成学习,决策树在节点划分上,在随机的特征子集上寻找最优划分特征
rf_reg = RandomForestRegressor(n_estimators=500, oob_score=True, random_state=666, n_jobs=-1)
rf_reg.fit(X, y)
test_score = rf_reg.oob_score_
print("Random Forest Regressor test_score = {}.".format(test_score))
# 极其随机森林 Extra-Trees:决策树在节点划分上,使用随机的特征和随机的阈值,提供额外的随机性,抑制过拟合,但增大了bias偏差
et_reg = ExtraTreesRegressor(n_estimators=500, bootstrap=True, oob_score=True, random_state=666, n_jobs=-1)
et_reg.fit(X, y)
test_score = et_reg.oob_score_
print("Extra Trees Regressor test_score = {}.".format(test_score))
4.3 Boosting 提升学习
Adaboost是一种迭代算法,算法会为每个样本赋予一个权重,每次用训练好的学习器标注/预测各个样本,如果某个样本点被预测的越正确,则将其权重降低。否则提高样本的权重。权重越高的样本在下一个迭代训练中所占的比重就越大,也就是说越难区分的样本在训练过程中会变得越重要。整个迭代过程会一直持续到错误率足够小或者达到一定的迭代次数为止。
Adaboost算法将基分类器的线性组合作为强分类器,同时给分类误差率较小的基分类器以大的权值,给分类误差率较大的基分类器以小的权值,另外需要注意的是这里的权重和权值是两个不同的概念,这里权重针对的是样本,在各个基分类器上,分类的错误样本越多,权重越高,权值针对的是基模型误分率越小的基模型,权重越大。
代码如下:
def AdaboostModle():
# AdaBoosting 分类:每一个模型对前一个模型犯错误的样本加大权重进行训练
X_train, X_test, y_train, y_test, X, y = dataInit(type="moons")
ada_clf = AdaBoostClassifier(
DecisionTreeClassifier(max_depth=2), n_estimators=500)
ada_clf.fit(X_train, y_train)
score = ada_clf.score(X_test, y_test)
print("AdaBoost Classifier score = {}.".format(score))
# AdaBoosting 回归:每一个模型对前一个模型犯错误的样本加大权重进行训练
X_train, X_test, y_train, y_test, X, y = dataInit(type="boston")
ada_reg = AdaBoostRegressor(
DecisionTreeRegressor(max_depth=30), n_estimators=250)
ada_reg.fit(X_train, y_train)
score = ada_reg.score(X_test, y_test)
print("AdaBoost Regressor score = {}.".format(score))
GBDT梯度提升决策树和AdaBoost算法一样同属于Boosting算法,不同之处在于,AdaBoost算法是利用前一轮弱学习器误差来更新样本权重值,然后一轮一轮迭代。GBDT也是迭代,但是GBDT要求弱学习器必须是CART模型,而且GBDT在模型预测的时候,要求模型预测样本损失尽可能小。GBDT中的每一棵树学的是之前所有树的平方和残差,拟合得到一个当前的残差回归树。
代码如下:
def GBDTModle():
# Gradient Boosting 分类:每一个模型对前一个模型犯错的样本进行训练
gb_clf = GradientBoostingClassifier(max_depth=2, n_estimators=30)
gb_clf.fit(X_train, y_train)
score = gb_clf.score(X_test, y_test)
print("Gradient Boosting Classifier score = {}.".format(score))
# Gradient Boosting 回归:每一个模型对前一个模型犯错的样本进行训练
gb_reg = GradientBoostingRegressor(max_depth=2, n_estimators=300)
gb_reg.fit(X_train, y_train)
score = gb_reg.score(X_test, y_test)
print("Gradient Boosting Regressor score = {}.".format(score))
5 常见算法区别
5.1 Bagging 与 Boosting 的区别
区别 | Bagging | Boosting |
样本选择 | Bagging算法是有放回的随机采样 | Boosting算法是每一轮训练集不变,只是训练集中的每个样例在分类器中的权重发生变化,而权重根据上一轮的分类结果进行调整 |
样例权重 | Bagging使用随机抽样,样例的权重相等 | Boosting根据错误率不断的调整样例的权重值,错误率越大则权重越大 |
预测函数 | Bagging所有预测模型的权重相等 | Boosting算法对于误差小的分类器具有更大的权重 |
并行计算 | Bagging算法可以并行生成各个基模型 | Boosting理论上只能顺序生产 因为后一个模型需要前一个模型的结果 |
作用 | Bagging是减少模型的variance(方差), Bagging里每个分类模型都是强分类器,因为降低的是方差,方差过高需要降低是过拟合; | Boosting是减少模型的Bias(偏度), Boosting里每个分类模型都是弱分类器, 因为降低的是偏度,偏度过高是欠拟合。 |
5.2 随机森林 和 GBDT梯度提升决策树 的区别
随机森林属于bagging算法,它使用抽取不同的样本构建不同的子树,将多棵决策树的结果进行投票后得到最终的结果,对不同的树的训练结果也没有做进一步的优化提升,也就是说第m棵树的构建和前m-1棵树的结果是没有关系的,完全独立,可进行并行计算。
梯度提升决策树GBDT用到的是boosting算法,在迭代的每一步构建弱学习器弥补原有模型的不足。GBDT中的GradientBoost就是通过每次迭代的时候构建一个沿梯度下降最快的方向的学习器DecisionTree。使用之前子树构建结果后形成的残差作为输入数据构建下个子树,然后最终预测的时候按照子树构建的顺序进行预测,并将预测结果相加。
6 总结
本文讲解了集成学习的原理,分类以及常见的集成学习模型。并基于sklearn使用常见集成学习方法处理回归和分类问题,在文章的最后,对易于混淆的集成算法进行了区分对比。