目标函数:
累加训练
目标函数t时刻的整体复杂度可以拆分成,那么t-1时刻前面的所有的复杂度都已经固定了,就用constant表示。
我们发现目标函数(相对GBDT)里面是带正则项的,t-1时刻的正则项全部在const里面
2.对loss进行泰勒二阶展开的近似。
对loss损失函数(括号里的内容进行二阶泰勒展开)
GBDT用的是牛顿法(一阶导)
XGBoost用的是梯度下降(二阶导)
XGBoost用更快速度找到最优解,迭代次数更少
3.再次化简目标函数
因为我们让目标函数尽可能小对常数项没有关系,那么我们就可以把常数项都去掉。前面l(yi,yi_hat(t-1))也是常数项也可以去掉。
新的目标函数
GBDT是拟合上一条样本的负梯度
XGBoost是去拟合上一条样本的gi、hi,所以我们在训练的时候,要去准备下一条样本的gi、hi,准备好了后,变量就是ft(xi),那么目标函数就是再求ft(xi)是何值时,整体的损失最小。
综合以上XGBoost对比GDBT有两点好处:
(1)考虑了正则项Ω。
(2)求二阶导,使得梯度下降的更快。
4.重新定义树
q:代表落在哪个叶子节点,返回那个叶子节点的索引号,T:T个叶子节点
W:是一个向量里面存放所有叶子分数,给出一个索引号,从W向量里查询分数。
W(qx):根据q(x)叶子节点的索引号,取出来W向量里面相应的分值
经过重新定义后,一棵树对应的分值就是,在目标函数中就可以把
替换成
5.重新定义复杂度
γ:系数
T:叶子节点个数
:系数
W:就是上面定义的叶子节点的分值
叶子节点越少,复杂度就越小。
叶子节点分值越少,正则项数值就越少。
6.在重新定义树和复杂度后,带入原目标函数,得到新的目标函数
7.再次化简 目标函数
因为
我们假设
带入目标函数
所以
最终目标函数变成
确定好目标函数后,obj分值越小,代表树的结构越好,我们就可以通过obj分值知道我们要选择第一棵树,还是第二颗树的结构
我们就可以把obj当成每棵树分裂的评价指标
例如:tree1比tree2多分了一次,如果多分了这次后计算得到的obj比tree高了,就说明树的结构还不如不分。
8.XGBoost收益计算
分裂前计算一下obj,用分裂前的obj减去分裂后的两个叶子结点的obj得到下面的公式。
计算obj收益,根据obj收益选择最佳特征特征值。
9.时间复杂度
O(n d K log n)
d个特征,每个特征有K个分裂点。
优化:
基于这个分裂节点再进行分裂后,下一个分裂节点可以不用再进行分裂。因为X都是一样的,每次分裂排序不会变,那么我们整体学习一棵树的时间复杂度就会优化。
在集成学习中最耗时间的部分是每个特征选择最佳分割点,XGBoost在训练前将数据进行了排序,并存储在Block中,以后每次迭代直接用Block中存储的结构,这样大大节省了计算时间。
特征寻找最佳分割点需要计算增益,XGBoost对这个过程使用了多线程。
XGBoost前剪枝
树节点往下分裂,如果计算得到收益是负的,就不会往下分了。
但是这样做有个问题,这次收益是负的,但是如果继续分裂说不定下次收益就是正的,而且加起来收益会很大。。
为了解决这个问题:后剪枝
让树充分生长,通过传入超参,在叶子涨到一定程度后,剪掉最后面的负收益的叶子节点。
有了XGBoost,就不太用GBDT了,因为XGBoost就是GBDT的优化。