(作者:陈玓玏)
写在前面:这篇博客我自认为写得不太好,有些问题可能我自己也没有弄得多清楚,对文章有疑问的朋友可以留言讨论,不胜感激。
1、基本的查找分割点的贪婪算法
这样的算法称为精确贪婪算法,在计算分割点的过程中,它会去查找进入当前分支的每一个样本的每一个特征值,计算它们的增益,sklearn和单机版xgboost都支持这种算法。不过这种算法要求在一开始的时候先把所有样本按照特征值排好序,并计算好它们的一阶导数和二阶导数,这样才能快速地计算增益,选定分割的候选节点。
2、效率极高的分位点算法
以上算法在其他基于决策树的算法中是常用的,但是这样做的结果就是运算量极大,即使在xgboost中通过率先排序及计算梯度向量,在实施过程中的计算量仍旧非常大,尤其是样本量足够大的时候,因此xgboost中使用的是基于Weighted Quantile Sketch分位点算法。
xgboost所使用的分位点算法,其核心思想是根据特征的分布取其分位点,这些分位点将作为分割点将整个特征区间划分为多个段,所有特征值将进入对应分段,由分位点代替其真实特征值,其本质就是连续特征的分段离散,随后获取梯度向量,找出最佳分割点。
2.1 算法分类
实际计算分位点时也有两种算法:
1)全局算法:在树结构构建的初始阶段,计算出所有的候选分割点,在随后的建树过程中,无论构建哪一层,都使用同样的候选分割点,这种方法全局只需要计算一次,步骤更少,但是需要计算出的候选节点更多才能保证精度。
2)局部算法:每一次分裂都重新计算候选分割点,计算步骤更多,但是总的需要计算的候选节点更少,适用于更深的树的构建。
Weighted Quantile Sketch算法的基础是GK算法,GK算法可以看这一篇:https://blog.csdn.net/matrix_zzl/article/details/78641264 ,原始的论文:http://infolab.stanford.edu/~datar/courses/cs361a/papers/quantiles.pdf。
GK算法和xgboost中所使用的算法的一个重要区别在于:
- GK算法中的rank使用的就是根据特征值从小到大排序之后的序号,而Weighted Quantile Sketch算法中所使用的rank是排序后小于特征值某个值的样本的权重和,而xgboost中使用的是一个Weighted Quantile Sketch中归一化的权重和,使用的是特征值小于某个值的样本的二阶导数之和除以所有样本的二阶导数之和。
- 2.GK算法中每个summary(我理解的summary就是一个集合的意思)存储为一个三元组,绝对位置的三元组存储的内容分别是:集合内的样本值集合,集合内最小样本的序号,集合内最大样本的序号。相对位置的三元组存储内容分别为:集合内的样本值集合,当前集合最小样本序号-前一个集合最小样本序号(从第一次集合开始可以依次确定出每个集合的起始位置),集合内最大样本序号-集合内最小样本序号(表征当前集合的长度)。而对于xgboost而言,它的每个summary是由一个四元组表示的:集合内的样本值集合,集合内的所有特征值<某个值的样本对应权重和,集合内的所有特征值<=某个值的样本对应权重和,集合内的所有特征值=某个值的样本对应权重和。
2.2 统一定义
Weighted Quantile Sketch算法中,有以下固定的定义:
表示输入的数据集,
表示所有样本的某个特征值,
表示样本对应的权重。
即需要存入元组的第二项的上限,表示所有特征值小于y(这里的y不要理解成label)的样本的权重和。
即需要存入元组的第三项的上限值,表示所有特征值小于等于y的样本的权重和。
即需要存入元组的第四项的上限值,表示所有特征值等于y的样本的权重和。
另外,对于整个dateset来说,其权重为所有样本的权重和,公式如下:
summary的四元组内容如下:
是集合
对应的分位数summary,
是
中的样本特征值的集合,即{
},
是此summary中的最小值,
是最大值,summary中的每一个点都可以计算得到
(但加了波浪线的rank是什么运算,没有弄明白。。。有看懂的可以留言补充,感谢~),因为此处的集合
包含的是所有数据,这些操作自然也是在整个区间计算的了。
除了每个summary对应的四元组内容,算法还定义了每个summary中的点需要满足的约束:
不过当集合中的点是整个输入区间的最大值或最小值时,约束条件中的等号成立。
这几个变量还满足另外一个约束条件:
对于新插入的数据点
,其rank和
的计算逻辑如下:
1)如果
,则
2)如果
,则
3)如果
在集合范围内,处于某两个特征值之间,则
2.3 merge和prune操作
有了以上的基础,我们就可以来讨论下面的内容了。
我们当前所讨论的summary是没有进行切分的,如果直接这么使用,精度几乎为0,这就涉及到算法中最重要的两个操作:merge和prune。
1)merge
两个summary做merge操作,其实就是把两个summary中的数据放到一起,并且更新它们的rank值和
值。令需要merge的两个summary是
,它们merge后的结果是
,因此merge的结果如下:
2)prune
光是merge的话,其实一直执行merge最后的精度一定又会变为0,所以我们必须要进行prune操作。prune操作是基于一个新的函数
,这个函数定义了找到prune操作分位点的方法,因为对于一个给定精度为
的summary
而言,我们总是能找到一个点
满足以下两个不等式:
我的理解是,对于给定的
作为一个标尺,总能在summary内找到一个距离Dataset内最小的数的权重距离最接近
的样本点作为
。具体如何来确定样本点,需要分四种情况,论文中的prune算法中讲得很清楚了,下面贴出来:
有了寻找分割点的算法基础之后,我们就可以根据内存预算来找分割点了,比如我们内存的预算是
,我们需要找到
个分割点,也就是
构成的新的summary为
这里需要注意的是,
并不发生改变,还是包含所有训练数据的dateset,变的是summary,summary中的
样本点更新了。
中的每个样本点由以下公式确定:
是从1到b+1的,这样就能找出b+1个分位点了。更新之后的误差为
。
2.4 xgboost中使用weighted quantile sketch算法
有了这个基础之后我们就可以来讨论xgboost中模糊查找分割点的具体情况了。
模糊算法中,每个样本的权重取的是
,这个可以通过将目标函数转换成以下形式而得:
目标函数转化成此形式之后,可以视为平方损失函数和正则项构成的目标函数,
视为样本的label值,而
就是每个样本的权重。
所以对于以下dataset
其rank表示为:
我们需要找到的分割点必须满足:
参考文献: