仔细把陈天奇大神的论文又读了一遍,对xgBoost的原理又有了一些深入的了解吧。

XGBoost模型本身是Boosting方法,所以它的整体过程和传统的Boosting还是比较接近的,即串行化的建树过程。个人认为,XGBoost比较新奇点在于,在建树的过程中,结点分裂的时候使用的标准并不是传统的基于信息增益啊、信息增益比这类东西,而是根据损失函数自己定义了一个指标,并且在损失函数中也加入了正则项,防止了过拟合。另外的贡献就是模型加速,并行化这一方面,提出了近似算法,可以大规模的进行并行计算,极大的提高了效率。当然还有一些其他细节,接下来一一说来

自带正则项的损失函数

我们知道Boosting模型可以看作是一个加性模型,给定一个实例xi,它的对应的输出yi就可以写作:y^i=k=1Kfk(xi),k代表第k个树,f(x)=ωq(x),可以认为是给定一个实例,在当前的树模型下它被映射到q(xi)这个结点(q可以认为是树结构),这个结点的权重作为返回值。最终我们优化的目标就是

L(ϕ)(t)=tl(yi,y^i(t1))+kΩ(fk)whereΩ(f)=γT+12λω2
其中Ω就是结构损失,这里包含了对叶结点个数的惩罚(L1)和对叶结点权重的惩罚(L2),这种自带正则化项的损失函数,对防止过拟合起到了很大的作用。

由于模型为加性模型,那么可以得到:

Lt=i=1nl(yi,y^it1+ft(xi))+Ω(ft)

对上面的式子进行二阶泰勒展开,令gi=y^(t1)l(yi,y^(t1)),即f的一阶导数;令hi=y^(t1)2l(fi,y^(t1));
于是上式就可以近似为:
XGBoost那些事儿
更近一步的,l(yi,y^(t1))是已知的,就是基于前面步骤中产生的树的集合加权产生的结果,所以它是一个常数,我们可一忽略掉。于是上式就变成了这样:
XGBoost那些事儿
上面的式子我们可以认为是把样例从头到尾都计算了一遍,以样例为单位,而最终的结果其实是把样例划分到某个叶结点的形式,那么我们也可以按归属于哪个叶结点对上式重新进行组织,最终值是一样的,只不过是形式改变了。我们定义Ij={i|q(xi)=j},q(x)在前面提到过,代表树的结构,通过这样结构的决策树,把样例映射到叶结点j,所以Ij就代表属于叶结点j的样例集合。那么改写之后的表达式形式就变成了:
XGBoost那些事儿
为了求解得到最优的叶结点权值ωj,我们可以对上式进行求导,令导数为0,进行求解。于是得到了下面的式子:
XGBoost那些事儿
把最优的ωj代回原式,得到了对应的目标函数的值:
XGBoost那些事儿
这个值我们可以认为是一个评价指标,类似于传统的信息增益,基尼指数等。但是不可以把它直接遍历所有的树,这里采用贪心的方法,即一开始从一个根结点开始,逐渐地增加分枝,在分枝增加之前,我们预先计算一下IL,IR,然后再决定是否分裂。具体的公式就是:
XGBoost那些事儿
我们可以简单的理解,我要计算的其实是如果进行分枝,那么分枝之后的左结点的损失函数值加上右结点的损失函数值与不分枝的情况相比,会下降多少。只有当损失函数的值下降超过一定的值,我们才让它分裂。因此我们可以理解这个过程相当于是一个预剪枝的过程(那么计算这个值时是不是应该用包外数据呢?
从上面的推到过程中我们还发现一件事,在对目标函数值进行近似求解的时候,我们进行的操作是对它进行二阶泰勒展开,而且并不关心这个目标函数的形式。因此,XGBoost对求解问题其实是有很广泛的应用的,只需要满足一个条件:目标函数可以进行二阶泰勒展开,那么就可以用这个方法。

Shrinkage和Column Subsampling

shrinkage其实就是类似与GBDT里。因为XGBoost其实也是基于梯度的提升方法,说到底拟合的还是残差,在每一步加的时候,如果直接加可能会导致值的波动过大,所以对每棵树的结果乘上一个小的系数,就相当于是小步逼近,这样不会发生很明显的震荡,而且也不容易过拟合,有点类似于梯度下降的学习率,而且在优化上也可以类似学习率,比如可以让它不是固定的,开始的时候可以步子大一点,越往后越接近最优解,可以让步子放缓。
Column Subsampling就是随机森林里的那一套。增加属性扰动,一个原因是增加模型的多样性,从而提高泛化能力;再一个也可以提高计算速度。

对于缺失值的处理

XGBoost还做到的一点就是对于缺失值的处理。
我们回忆一下传统的决策树是怎么处理缺失值的:给每个样例增加一个权重属性,并计算一个非缺失值样本对全部样本的比例。在划分的时候,是按照不同的概率把含有缺失值的样本分配到所有的子结点中去。
而xgBoost却能自动的寻找分裂方向。
XGBoost那些事儿
上面的就是算法过程。简单的理解就是如果把这个样本分到左子结点,会得到一个损失函数下降值,如果分到右子结点,也会得到一个损失函数下降值,比较这两个方向哪个下降的最多,选择下降的最多的那个方向。这就是自动学习的过程。(有一个问题,如果针对某一结点的分裂属性有多个缺失值,那么他们划分到左右子结点的组合有2n个,爆炸似的计算量。是不是说所有的确实值我都划分到一个方向上去了呢????

加速方法

XGBoost用的加速方法或者说并行处理的方法
Boosting是串行建树的过程,也就是说在树层面上是没有办法做到并行的。能并行的过程只是在特征选择过程。
它所采用的方法是对特征取值先排序,然后遍历所有的划分点计算gi,hi,然后保存到一个block的结构里面。这个过程只需要一次,后面建树的过程就相当于是取数的过程了。
(上面说的是基于排序的,其实也可以采用直方图近似的方法。这两种方法xgBoost都有实现。)

  • 另外,从结点划分评判标准的式子来看,xgBoost是level-wise的,区别于lightGBM的path-wise.因为它每次分裂的时候一定是分到两个子结点的,也就是按层进行。
  • xgBoost的调参:总共有三类参数:
    • 1、通用参数:宏观函数控制。
    • 2、Booster参数:控制每一步的booster(tree/regression)。
    • 3、学习目标参数:控制训练目标的表现。
      具体的参数详解看这里

相关文章: