前段时间与手下同学一起研究并实现了某回归问题,主要尝试了应用模型集成学习去提升模型效果。
在此总结一下集成学习原理及Python实现。
1.集成学习
模型融合是集成学习的一个类别。
集成学习可分为两类,一种是把强分类器进行强强联合,使得融合后的模型效果更强,称为模型融合。另一种是将弱分类器通过学习算法集成起来变为很强的分类器,称为机器学习元算法。
这里我们把用来进行融合的学习器称为个体学习器。
模型融合的代表有:投票法(Voting,针对分类问题)、线性混合(Linear Blending,针对回归问题)、Stacking。
而机器学习元算法又可以根据个体学习器之间是否存在依赖关系分为两类,称为Bagging和Boosting。
1.1 机器学习元算法
- Bagging: 个体学习器不存在依赖关系,可同时对样本随机采样并行化生成个体学习器。有放回的方式进行抽样,用抽样的样本建立子模型,对子模型进行训练,这个过程重复多次,最后进行融合。代表作为随机森林(Random Forest)
- Boosting: 个体学习器存在依赖关系,基于前面模型的训练结果误差生成新的模型,必须串行化生成。每一次训练的时候都更加关心分类错误的样例,给这些分类错误的样例增加更大的权重,下一次迭代的目标就是能够更容易辨别出上一轮分类错误的样例。最终将这些弱分类器进行加权相加。代表的算法有:Adaboost、GBDT、XGBoost
- 其中:GBDT串行地构造多棵决策树来进行数据的预测,它是在损失函数所在的函数空间中做梯度下降,即把待求的决策树模型当作参数,每轮迭代都去拟合损失函数在当前模型下的负梯度,从而使得参数朝着最小化损失函数的方向更新。
- Xgboost是梯度提升树的一种高效系统实现,是对GBDT进一步的改进,包括对代价函数进行了二阶泰勒展开,在代价函数里加入了正则项,借鉴了随机森林的列采样方法,支持并行计算等。
1.2 模型融合
模型融合又分为投票法、平均法和stacking法。
1.2.1 投票法(Voting):
多个基础模型,采取投票制的方法,投票多者确定为最终的分类。适用于
1.2.2 平均法(Averaging):
- 简单平均:
- 加权平均:
1.2.3 堆叠法(Stacking):
Stacking做法和Linear Blending类似,首先从数据集中训练出初级学习器,然后”生成“一个新的数据集用于训练次级学习器。为了防止过拟合,采用K折交叉验证法求解。
Stacking模型本质上是一种分层的结构,这里简单起见,只分析二级Stacking.假设我们有3个基模型M1、M2、M3。
1. 基模型M1,对训练集train训练,然后用于预测train和test的标签列,分别是P1,T1
对于M2和M3,重复相同的工作,这样也得到P2,T2,P3,T3。
2. 分别把P1,P2,P3以及T1,T2,T3合并,得到一个新的训练集和测试集train2,test2。
3. 再用第二层的模型M4训练train2,预测test2,得到最终的标签列。
毫无疑问过拟合是非常非常严重的,因此现在的问题变成了如何在解决过拟合的前提下得到P1、P2、P3,这就变成了熟悉的节奏——K折交叉验证。我们以2折交叉验证得到P1为例,假设训练集为4行3列:
将其划分为2部分
用traina训练模型M1,然后在trainb上进行预测得到preb3和pred4
在trainb上训练模型M1,然后在traina上进行预测得到pred1和pred2
然后把两个预测集进行拼接
2折交叉验证,M1相当于训练了2次,所以一种方法是每一次训练M1,可以直接对整个test进行预测,这样2折交叉验证后测试集相当于预测了2次,然后对这两列求平均得到T1。
1.2.4 线性混合(Linear Blending):
前面提到过加权平均法,每个个体学习器的权重不再相等,看起来就像是对每个个体学习器做一个线性组合,这也是线性混合法名字的由来。那么最优的权重是什么呢?一个直接的想法就是最好的αi使得error最小,即对应了优化问题:
这里有T个个体学习器,每个学习器用 表示,而αt就是对应的权重。
这里我们首先用训练数据训练出所有的h,然后再做线性回归求出αt 。
如何得到 呢?这里我们将个体学习器称为初级学习器,用于结合的学习器称为次级学习器。首先从数据集中训练出初级学习器,然后”生成“一个新的数据集用于训练次级学习器。注意为了防止过拟合,我们需要在训练集上做训练得到初级学习器ht,而在验证集上比较不同α的好坏。最终模型则在所有的数据上进行训练。
总结:Blending与Stacking大致相同,只是Blending的主要区别在于训练集不是通过K-Fold的CV策略来获得预测值从而生成第二阶段模型的特征,而是建立一个Holdout集,例如10%的训练数据,第二阶段的stacker模型就基于第一阶段模型对这10%训练数据的预测值进行拟合。说白了,就是把Stacking流程中的K-Fold CV 改成 HoldOut CV。
(holdout和交叉验证是两个常用的评估分类器预测准确率的技术,它们均是在给定数据集中随机取样划分数据。
holdout:将所给定的数据集随机划分成两个独立部分:一个作为训练数据集,而另一个作为测试数据集,通常训练数据集包含初始数据集中的三分之二的数据,而其余的三分之一则作为测试数据集的内容。利用训练集数据学习获得一个分类器,然后使用测试数据集对该分类器预测准确率进行评估,由于仅使用初始数据集中的一部分进行学习,因此对所得分类器预测准确性的估计应该是悲观的估计。随机取样是holdout方法的一种变化,在随机取样方法中,重复利用holdout方法进行预测准确率估计k次,最后对这k次所获得的预测准确率求平均,以便获得最终的预测准确率。
k-交叉验证:将初始数据集随机分为k个互不相交的子集,S1,S2,...,Sk,每个子集大小基本相同。学习和测试分别进行k次,在第i次循环中,子集Si作为测试集,其他子集则合并到一起构成一个大训练数据集并通过学习获得相应的分类器,也就是第一次循环,使用S2....Sk作为训练数据集,S1作为测试数据集;而在第二次循环时,使用S1,S3,...,Sk作为训练数据集,S2作为测试数据集;如此下去等等。而对整个初始数据所得分类器的准确率估计则可用k次循环中所获得的正确分类数目之和除以初始数据集的大小来获得。在分层交叉验证中,将所划分的子集层次化以确保每个子集中的各类别分布与初始数据集中的类别分布基本相同。)
2. heamy库实现stacking和blending
案例来自heamy库github
2.1 Stacking
import logging
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.metrics import mean_absolute_error
from sklearn.neighbors import KNeighborsRegressor
from xgboost import XGBClassifier
from heamy.dataset import Dataset
from heamy.estimator import Regressor, Classifier
from heamy.pipeline import ModelsPipeline
# 1st level# 1st l
model_rf = Regressor(dataset=dataset, estimator=RandomForestRegressor, parameters={'n_estimators': 151},name='rf')
model_lr = Regressor(dataset=dataset, estimator=LinearRegression, parameters={'normalize': True},name='lr')
model_knn = Regressor(dataset=dataset, estimator=KNeighborsRegressor, parameters={'n_neighbors': 15},name='knn')
pipeline = ModelsPipeline(model_rf,model_lr,model_knn)
stack_ds = pipeline.stack(k=5,seed=111)
# 2nd level
stack_rf = Regressor(dataset=stack_ds, estimator=RandomForestRegressor, parameters={'n_estimators': 15},name='rf')
stack_lr = Regressor(dataset=stack_ds, estimator=LinearRegression, parameters={'normalize': True},name='lr')
stack_pipeline = ModelsPipeline(stack_rf,stack_lr)
# 3rd level
weights = stack_pipeline.find_weights(mean_absolute_error)
print('---')
result = stack_pipeline.weight(weights).validate(mean_absolute_error,10)
2.1.2 blending
from heamy.dataset import Dataset
from heamy.estimator import Regressor, Classifier
from heamy.pipeline import ModelsPipeline
from sklearn import cross_validation
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
from sklearn.datasets import load_boston
data = load_boston()
X, y = data['data'], data['target']
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.1, random_state=111)
dataset = Dataset(X_train,y_train,X_test)
model_rf = Regressor(dataset=dataset, estimator=RandomForestRegressor, parameters={'n_estimators': 50},name='rf')
model_lr = Regressor(dataset=dataset, estimator=LinearRegression, parameters={'normalize': True},name='lr')
pipeline = ModelsPipeline(model_rf,model_lr)
stack_ds = pipeline.blend(proportion=0.2,seed=111)
stacker = Regressor(dataset=stack_ds, estimator=LinearRegression)
results = stacker.predict()
results10 = stacker.validate(k=10,scorer=mean_absolute_error)
参考资料:
1. https://zhuanlan.zhihu.com/p/61705517
2. https://www.cnblogs.com/yumoye/p/11024137.html
3. Xgboost document: https://xgboost.readthedocs.io/en/latest/
4. heamy官方github: https://github.com/rushter/heamy/blob/master/examples/walkthrough.ipynb