1024 祝大家快乐
xgboost这篇论文写得比较易懂,陈天奇大牛有科普的意思,推荐读原文,这里只是详细记录一下。

文章目录

  • ​​1. Introduction​​
  • ​​2. 提升树​​
  • ​​2.1 带正则项的目标函数​​
  • ​​2.2 梯度提升树​​
  • ​​2.3 Shrinkage and Column Subsampling​​
  • ​​3. Split Finding algorithms​​
  • ​​3.1 基础的精确贪心算法​​
  • ​​3.2 近似算法​​
  • ​​3.3 加权分位数算法​​
  • ​​3.4 Sparsity-aware Split Finding​​
  • ​​4. System Design​​
  • ​​4.1 Column Block for Parallel Learning​​

1. Introduction

比赛大杀器
本篇论文的贡献:

  • 高度弹性的端到端的提升树系统
  • 提出了一个有理论支撑的加权分位数算法
  • 介绍了一个新颖的并行树学习的稀疏感知算法
  • 提出了一种有效的缓存感知块结构,用于out-of-core树学习

2. 提升树

2.1 带正则项的目标函数

给定一个m个特征的n个样本集

XGBoost原文阅读_割点


将每棵树看做一个函数XGBoost原文阅读_损失函数_02,K颗树集成来计算输出结果

XGBoost原文阅读_XGBoost_03


XGBoost原文阅读_损失函数_04


XGBoost原文阅读_损失函数_05将样本从样本空间映射到叶子的节点空间,w为每个叶子节点的权重,T为树的叶子数

XGBoost原文阅读_权重_06


可以看出XGBoost原文阅读_损失函数_05,包含两部分,树的结构q和权重w,q将一个样本映射到叶子节点,w为叶子节点赋一个权重。那么可以从下图看出,一个样本的得分,是在每颗树下的叶子权重加和。为了学习每棵树,树的目标函数:

XGBoost原文阅读_权重_08


XGBoost原文阅读_权重_09定义了一个凸的损失函数,模型的预测精度由偏差和方差共同决定,损失函数代表了模型的偏差,想要方差小则需要更简单的模型, 所以目标函数最终由损失函数L与抑制模型复杂度的正则项Ω组成。后面的为含义为树的复杂度的正则项,描述了树的复杂度,可以看到包含了树的叶子数和叶子score的模的平方和,该正则项可以最终帮助避免过拟合。

2.2 梯度提升树

第t颗树生成计算的损失函数

XGBoost原文阅读_损失函数_10


这里可以把到t-1的所有树的加和看做变量XGBoost原文阅读_权重_11,把XGBoost原文阅读_权重_12看做自变量的修正,即XGBoost原文阅读_割点_13,二阶泰勒展开

XGBoost原文阅读_权重_14


其中XGBoost原文阅读_权重_15XGBoost原文阅读_XGBoost_16一阶导,XGBoost原文阅读_损失函数_17XGBoost原文阅读_XGBoost_16二阶导

XGBoost原文阅读_XGBoost_19


t之前的树已经确定了,把常数项移除后得到

XGBoost原文阅读_割点_20


定义叶子节点j的集合XGBoost原文阅读_XGBoost_21,把样本空间(n个)映射到叶子空间(T个),上面的等式(3)重写下

XGBoost原文阅读_损失函数_22


可以看出损失是w的二次函数,则最优w的值为

XGBoost原文阅读_XGBoost_23


带入损失函数

XGBoost原文阅读_权重_24


公式(6)用来评估树的结构q的质量,表示树的杂质(impurity)

(7)用作评估分割XGBoost原文阅读_XGBoost_25XGBoost原文阅读_权重_26XGBoost原文阅读_损失函数_27带来的收益,通过公式(6)中XGBoost原文阅读_割点_28计算获得

XGBoost原文阅读_XGBoost_29

2.3 Shrinkage and Column Subsampling

除了损失函数中的正则项,文中还提出了两种降低过拟合的方式–学习率和列采样

  • 学习率(xgboost中的eta)减少了每棵树的影响,为未来的树木留出空间来改进模型。
  • 列采样之前被用于随机森林,通过随机性降低过拟合,根据反馈,使用列子采样比传统的行子采样更有效的防止过拟合。

3. Split Finding algorithms

3.1 基础的精确贪心算法

如何找到最好的分割点?贪心算法是列举所有特征的所有可能值,找到最佳分割点。为了有效的完成寻找,算法必须先对数据根据特征排序。

XGBoost原文阅读_XGBoost_25是当前可分的节点,XGBoost原文阅读_XGBoost_31是所有样本的二阶导的和,XGBoost原文阅读_权重_32为所有样本的一阶导的和,对于每棵树,遍历所有的节点,根据分割后的XGBoost原文阅读_XGBoost_33XGBoost原文阅读_权重_34XGBoost原文阅读_损失函数_35XGBoost原文阅读_XGBoost_36找到增益最大的分割点。

XGBoost原文阅读_XGBoost_37

3.2 近似算法

精确的贪心算法显然不适合大规模的数据,因为它贪婪的列举了所有可能的分割点。

近似算法根据特征分布的百分位数提出候选分割点。首先将连续特征映射为候选点分割的桶,然后再遍历这些较少的分裂点来找到最佳分裂点。

分割点的候选集的构建有两种方式global和local,区别在于构建分割候选集的时间。global构建在构建树的开始构建候选集,后续不同的节点采用相同的分割候选集。local则是在每次分割后重新构建分割候选集。

可以看出,在某种程度下,近似算法的AUC都可以接近精确算法,local的方式比global需要更少的桶,因为它每次分割后重新定义候选分割集。

XGBoost原文阅读_权重_38


分割候选集的效果对比,eps是间隔参数

3.3 加权分位数算法

这里加权是加的h,也就是损失的二阶导。

定义第k个特征值和每一个训练样本的二阶导组成的集合

XGBoost原文阅读_割点_39

定义一个rank函数

XGBoost原文阅读_XGBoost_40


XGBoost原文阅读_XGBoost_41


表达的含义就是小于z的所有特征值的h相加,h表征分位数分的是loss,也就是根据loss大小做的分割,而不是样本特征的分布。

每一段间隔,产生一个候选分割点,大约有XGBoost原文阅读_XGBoost_42个候选分割点

XGBoost原文阅读_割点_43


为什么采用h作为权重呢?这个开始我也很疑惑

前面的公式(3)可以写作下式。这下就可以理解h表征loss这句话的含义了。

XGBoost原文阅读_权重_44


上述的样本有相同的权重,当样本有着不同权重时,作者在附录里也给出了解决方案和理论证明。

3.4 Sparsity-aware Split Finding

稀疏特征是比较普遍的现象,例如存在缺失值、比较多的零项、特征工程的产物(one-hot),让算法意识到数据中的稀疏模式是比较重要的。为了解决这种情况,当某个值是缺失的,会被分到一个默认方向
Xgboost 在处理带缺失值的特征时,先对非缺失的样本进行排序,对该特征缺失的样本先不处理,然后在遍历每个分裂点时,将这些缺失样本分别划入左子树和右子树来计算损失然后求最优。
如果训练样本中没有缺失值,而预测过程中出现了缺失值,那么样本会被默认分到右子树。
要理解下面的算法图,可以假设有按XGBoost原文阅读_XGBoost_45排序的XGBoost原文阅读_割点_46
ascent descent
1 3
2 2
3 1
null null
null null
这样就可以理解每个特征遍历时的两次线性搜索

  1. enumerate missing value goto right
  2. enumerate missing value goto left

4. System Design

4.1 Column Block for Parallel Learning

xgboost的并行是在特征粒度上的。决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要确定最佳分割点),为了减小排序成本,xgboost在训练之前,预先对数据进行了排序,然后保存为block结构(CSC),后面的迭代中重复地使用这个结构,大大减小计算量。这个block结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行。

为每个列收集统计数据可以并行化,给我们一个并行算法的分裂查找。 重要的是,列块结构还支持列子采样,因为在块中很容易选择列的子集。

XGBoost原文阅读_权重_47


时间复杂度分析

更新于 2020-12-16