集成模型简单的总结,后续有时间再继续完善
集成模型主要目的就是为了降低模型的不确定性,通常来说集成模型可以分成两大类:
- Bagging:这类方法的代表是随机森林
- Boosting:这类方法的代表是GBDT和XGBoost
注意深度学习中用到的Dropout,其也可以理解为集成模型。随着每个mini-batch随机丢弃一些神经元,其最终会得到不同的网络结构,最终将其集成起来。
Bagging vs Boosting
相同点:两者都可以理解为base learning,且weak(指单个模型效果不太好)
不同点:bagging模型weak的原因是overfitting,而boosting模型weak的原因是underfitting。
实际两者基本的构筑都是基于决策树。
Bagging
Bagging主要是通过平均带来方差的减少(variance reduction)。假设有N个模型,每个模型再预测时的方差为σ2 。则通过N个模型一起预测时的方差是(平均):Nσ2 。
其代表方法随机森林区别于决策树的地方在于:构建树之前需要随机采样。这里包含了样本与特征2个方面。样本随机通常采用Bootstrap方法。
Random Forests = Bagging w. trees + random feature subsets
直观上理解就是, 采用 bootsrap 方法, 训练 多个决策树, 最后对所有的结果进行投票。
Boosting
Boosting算法本质是通过学习一个个弱分类器,在之前分类器的基础上不断迭代,最终集成提升为强分类器。boosting方法大致可以分为两种:
- Adaptive boosting: 通过分类误差率来调整样本的权重,经过迭代不断更新样本权重(提高错误样本权重,降低正确样本权重)(同时适用于基分类器)。最后将多个分类器组合在一起。
- Gradient boosting : 基于残差来优化,不断更新迭代。最后将多个分类器组合在一起。
这里将主要讨论一下Gradient boosting方法。
CART回归树
GBDT使用的决策树基础是CART回归树,由于其每次迭代要拟合的是梯度值,属于连续值,所以不可以使用CART分类树。为了很好的评判拟合程序,选择使用平方误差(MSE)。
回归树的生成算法:
输入:训练数据集D:
输出:回归树 f(x).
在训练数据集所在的输入空间中,递归的将每个区域划分为两个子区域并决定每个子区域上的输出值,构建二叉决策树:
(1)选择最优切分变量j与切分点s,求解
j,smin⎣⎡c1minxi∈R1(j,s)∑(yi−c1)2+c2minxi∈R2(j,s)∑(yi−c2)2⎦⎤
遍历变量j,对固定的切分变量j扫描切分点s,选择使得上式达到最小值的对(j,s)。c1,c2表示生成的左右两棵子树的均值。
(2)用选定的对(j,s)划分区域并决定相应的输出值:
R1(j,s)=x∣∣∣x(j)≤s,R2(j,s)=x∣∣∣x(j)>s
cm^=N1x1∈Rm(j,s)∑yi,x∈Rm,m=1,2
(3)继续对两个子区域调用步骤(1)和(2),直至满足停止条件(特定迭代次数或值满足某些条件)。
(4)将输入空间划分为M个区域 $R_1,R_2,...R_M $ ,生成决策树:
f(x)=m=1∑Mc^mI(x∈Rm)
提升树
提升树的精髓就是利用残差作为新的样本,不断去迭代决策树,最终使用投票等方法得出最终结果。这是一种基础的思想,后续算法都是再次基础上改进得来。
加法模型与前向分布算法,以决策树作为基函数
提升树算法:
输入:训练数据集D={(x1,y1),(x2,y2),…,(xN,yN)}
输出:提升树fM(x)
(1) 初始化f0(x)=0
(2) For m=1,2,……M
(a) 针对每个样本(xi,yi),计算残差
rm,i=yi−fm−1(xi),i=1,2,⋯,N
(b) 利用 {(xi,rm,i)}i=1,2,…,N 训练出一个决策树(回归树),得到T(x;Θm)
(c) 更新fm(x)=fm−1(x)+T(x;Θm)
(3) 完成以上迭代,即可得到提升树
fM(x)=m=1∑MT(x;Θm)
GBDT
GBDT(Gradient Boosting Decision Tree),梯度提升树。结合上面两种思想构建而成。
GBDT是基于 Boosting的思想,串行地构造多棵决策树来进行数据的预测,对损失函数做梯度下降,每轮迭代都去拟合损失函数在当前模型下的负梯度,把待求的決策树模型当作参数,从而使得参数朝着最小化损失函数的方向更新。
精髓:利用最速下降的近似方法,具体指利用损失函数的负梯度拟合一个回归树。
GBDT算法
输入:训练数据集D={(x1,y1),(x2,y2),…,(xN,yN)};损失函数L(y,f(x)).
输出:梯度提升树f^(x)
(1) 初始化 f0(x)=argminc∑i=1NL(yi,c)
(2) For m=1,2,……M
(a) 针对每个样本(xi,yi),计算残差
rm,i=−[∂f(xi)∂L(yi,f(xi))]f(x)=fm−1(x)),i=1,2,…,N
(b) 利用{(xi,rm,i)}i=1,2,…,N 训练出第m棵回归树Tm,其叶节点划分的区域为Rm,j,j=1,2,…,J
(c) 对于回归树的每一个叶节点,计算器输出值
cm,j=argcminxi∈Rm,j∑L(yi,fm−1(xi)+c),j=1,2,…,J
(d) 更新fm(x)=fm−1(x)+∑j=1Jcm,jI(x∈Rm,j)
(3) 得到最终的梯度提升回归树
f^(x)=fM(x)=m=1∑Mj=1∑Jcm,jI(x∈Rm,j)
实际使用时需要定义一个学习率α。且如果损失函数选用的是平方损失函数(MSE),其负梯度就是提升树中的直接相减的残差y−f(xi),但这仅仅是特殊情况。
XGBoost
XGBoost(eXtreme Gradient Boosting) 极端梯度提升,既可运用于分类,也可运用于回归。
XGBoost是对GBDT的进一步改进。传统GBDT在优化时只用到一阶导数信息, Xgboost则对损失函数进行了二阶泰勒展开,同时用到了一阶和二阶导数。
XGBOOST在损失函数里加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数、每个叶子节点上输出的 score的L2模的平方和。从 Bias-variance tradeoff角度来讲,正则项降低了模型的 variance,使学习出来的模型更加简单,防止过拟合,这也是 Xgboost优于传统GBDT的一个特性。
相比于前面的不断迭代树求最优函数的推导,XGBoost可以反向去理解,先构造出一个最优的函数,进而最后再去反推树的形状。
- 如何构造目标函数
类似于上面介绍的方法,最终预测值都是采用累加的方法
假设已经训练好了K棵树,则对于第i个样本的(最终)预测值为:
y^i=ϕ(Xi)=k=1∑Kfk(Xi),fk∈F
目标函数定义为两个部分,损失函数和控制每棵树复杂度的正则项:
L(ϕ)=i∑l(y^i,yi)+k∑Ω(fk)
对于回归问题,Loss可以选择MSE,对于分类问题,可以选择CrossEntropy,根据实际情况来选择
根据前k−1棵树去构建第k棵树,则可以表示为:
k^i(t)=k^i(t−1)+fk(xi)
那么目标函数变化为:
L(ϕ)=i∑nl(yi,y^i(k))+k=1∑KΩ(fk)=i∑nl(yi,y^i(k−1)+fk(Xi))+k=1∑K−1Ω(fK)+Ω(fK)
前K-1棵树的复杂度无意义,则第K棵树目标函数表示为:
L(K)=i∑nl(yi,y^i(k−1)+fk(Xi))+Ω(fK)
目的就是最小化这个式子
- 目标函数的近似
这里用到二阶的泰勒公式
f(x+Δx)≈f(x)+f′(x)Δx+21f′′(x)Δx2
将fk(Xi)看作Δx(为何可以这样?因为每棵树迭代相加提升的数值很小,可以这样去理解)。则第K棵树目标函数转化为:
L(K)≃i=1∑n[l(yi,y^i(K−1))+gifK(Xi)+21hifK2(Xi)]+Ω(fK)
其中gi=∂y^(K−1)(yi,y^(K−1)),hi=∂y^(K−1)2(yi,y^(K−1))
- 将树的结构引入目标函数
树的复杂度定义如下:
Ω(fK)=γT+21λj=1∑Twj2
其中T衡量节点的个数,∑j=1Twj2衡量了节点的值。定义fK(x)=Wq(x)
L(K)≃i=1∑n[gifK(Xi)+21hifK2(Xi)]+Ω(fK)=i=1∑n[giwq(xi)+21hiwq(xi)2]+γT+λ21j=1∑Twj2=j=1∑T⎣⎡⎝⎛i∈Ij∑gi⎠⎞wj+21⎝⎛i∈Ij∑hi+λ⎠⎞wj2⎦⎤+γT
Tips:第二至三步:将所有节点1到n的循环改写成单独叶节点$I_J$1到T的循环(优点:去除下标,包含二次项)
令Gj=∑i∈Ijgi,Hj=∑i∈Ijgi,代入上式:
L(K)=j=1∑T[Gjwj+21(Hj+λ)wj2]+γT
根据一元二次方程,每个叶子结点的scorewj的解为:
wj∗=−Hj+λGj
L(K)=−21j=1∑THj+λGj2+γT
- 优化方法(使用贪心算法)
接下来的目标就是学习寻找树的形状,一一例举进行比较不现实。由于已经推导出第K棵树最优结果L(K),因此可以使用贪心算法,相较于上一步Lold(K),不断寻找最优Lnew(K),目标是使得两者间差距最大。
因此对于一个叶子节点进行分裂,分裂先后得到的增益函数可以表示为:
Gain=21[HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2]−γ
第一项为左节点的score,第二项为右节点的score,第三项为上一步骤的score(如果不做分裂),第四项是多出来分支的附加项。式子等同于:
Lsplit =21[∑i∈ILhi+λ(∑i∈ILgi)2+∑i∈IRhi+λ(∑i∈IRgi)2−∑i∈Ihi+λ(∑i∈Igi)2]−γ
论文中构造树的算法步骤如图:
但是一个个位移寻找过慢,算法优化后采用一块块进行位移计算。对于每个特征,只考察候选切分点(分位点),减少计算复杂度。根据候选切分点把当前结点的样本放入对应的桶中,对每个桶的G,H进行累加。最后在候选切分点集合上贪心查找,论文描述如下:
具体如何选取切分点,这里使用h,二阶梯度加权,细节部分参考论文,就不细写了。
XGBoost同样有很多优化,例如Shrinkage,列抽样,稀疏值处理等等,也不细展开了,具体详见论文。
不过在使用XGBoost这个库时,对于回归问题,假设迭代K轮,总共生成K棵树。然而对于分类问题,迭代K轮,C分类问题,总共生成CK棵树。原因是分类最后使用softmax函数,针对每一个类别都会生成一棵树,即单次迭代就会生成C棵树,后将对应类别的值相加再求softmax,才能得到类似分类的结果。
还有个LightGBM,其使用了一堆方法对XGBoost进行优化 ,速度快,且内存占用较低,想了解的自己看论文去吧。
这里仅仅是对自己学习的简单整理,还有很多地方不完善,后续根据情况再继续补补吧。
参考
李航《统计学习方法》
GBDT算法原理以及实例理解
XGBoost论文解读
AdaBoost、GBDT、RF、XGboost、LightGBM的对比分析
XGBoost原始论文:XGBoost: A Scalable Tree Boosting System
LightGBM原始论文:LightGBM: A Highly Efficient Gradient Boosting Decision Tree