集成学习-提升(boosting)方法
1 提升方法
1.1 概率近似正确(PAC)学习框架
- 在概率近似正确(PAC)学习框架中,一个概念,如果存在一个多项式的学习算法能够学习它,并且正确率很高,那么就称这个概念是强可学习的;一个概念,如果存在一个多项式的学习算法能够学习它,但正确率仅比随机猜测好一点,则称这个概念是弱可学习的。
- 强可学习和弱可学习是等价的。
- 因此,若发现了弱学习器,可以将其提升为强学习器.
1.2 提升方法的问题
- 如何在每一轮训练中改变训练数据的权值或者概率分布?
- 如何将弱分类器组成一个强分类器?
2 AdaBoost 算法(最具代表性的提升算法)
2.1 主要思想
- 提高被前一轮弱分类器错误分类错误分类样本的权值,降低被正确分类的样本权值;
- 采取多数表决的方式组合弱分类器,加大分类误差小的弱分类器权值。
2.2 步骤
引用:https://zhuanlan.zhihu.com/p/591214033 提升树
3.1 定义
- 提升方法采用加法模型与前向分步算法,以决策树为基函数的提升方法称为提升树(boosting tree)。
- 当提升树算法为二分类算法时,就成了Adaboost算法的一种特例。
- 提升树都是回归树。
3.2 提升树算法
采用前向分布算法的提升树,第m步的模型为:
其中为当前待学习的回归树,其解为:
当损失函数为
平方误差损失
时,当前模型学习的目标就是你拟合残差
3.2 梯度提升决策树(GBDT)
提升树利用加法模型与前向分步算法实现优化过程,当损失函数是平方损失时,每一步优化是简单的,但对一般损失函数而言,问题就复杂了,因此,Freidman提出了梯度提升算法(Gradient Boosting),这是最速下降的近似方法,其关键是利用损失函数的负梯度在当前模型的值作为上述残差的近似值,拟合一个回归树。
GBDT
3.3 XGboost (Extreme Gradient Boosting)
3.3.1 改进点
XGboost本质上是GBDT思想的一种实现方式,它主要在以下几个方面做了改变:
- GBDT在训练时,只采用了损失函数的一阶导数信息,XGBoost对损失函数进行了二阶展开,理论上讲,收敛速度更快
- 加入了正则项,L1和L2分别用于限制叶子节点的数量和节点权重
- GBDT采用CART二叉树,分裂准则为平方误差,XGboost支持多种分类器,树的分裂准则如下:
a
当决策树结构已知时,令损失函数二阶泰勒近似函数的导数为0,可以求出每个叶子节点的预测值:;
b
将预测值代入到损失函数中,可以求得损失函数的最小值;
c
计算分裂前后损失函数的差值为,采用差值最大的分裂节点进行分裂;具体而言(>https://zhuanlan.zhihu.com/p/125594314) :1)先计算未分裂时一阶导和二阶导在各个样本处的值,
2)然后遍历所有特征(这里特征属性为连续值),每个特征下按特征值大小对样本排序,
3)然后从左往右依次选择分割点,计算该分割点下的损失差值,
4)找到损失差值最大时对应的特征与分割点,以此为当前节点进行分裂。
这样做确实能准确的找到特征与分割点,但是太耗时了。如果有几百个特征,几百万个训练样本,按这种方式遍历黄花菜都凉了,所以需要一种较为快速的近似方法
去替代精确解。 - GBDT在每轮迭代时,使用全部的训练数据,XGBoost则加入了行采样(样本)和列采样(特征);
- GBDT没有对缺失值进行处理,XGBoost能够自动学习
缺失值的处理策略
;
3.3.2 近似算法
不遍历训练样本所有特征值去找最佳分割点,而是人为设计一些分割点,然后将训练样本划分到不同的分割区间中,步骤如下:
image.png对于每一个特征,进行固定的分割点选取,其中对于第k个特征,分割点的首尾分别是该特征属性值的最小最大值。这样每个特征下每个分割点都能计算出损失差,选取最小损失差对应的特征、分割点即可。这里分割点的用法也用两种,一种是global,一种是local。global意味着只进行一次初始的分割选取,后面每个节点的都是在初始分割点上选取最优点;local则是每分裂一次,重新调整分割点的选取,分割区间会越来越小,因为分裂后的每个节点的样本数在减少。用local方法,则分割点不用设计太多,分割区间也不用太细;用global方法则需要较多的分割点,同样分割区间也要更细。在数据集上的验证结果表明,用远少于训练样本数的分割点,这种近似算法的效果与前面提到的遍历所有样本的效果差不多,如下图:
eps表示分割区间,区间越小,分割点越多
3.3.3 缺失值处理
每次分裂时,对缺失值样本分别放在左右两个叶节点,计算损失下降值,哪边增益大就放哪边。
3.3.4 工程优化
-
特征值排序并存储pre-sorted
上文提到对于每个特征,需要遍历所有的特征值去选择最佳分割点。如果在训练之前就排好序并存储在内存block中,每一个特征对应一个block。这样在构建第k棵树的过程中,可以同时对所有的叶结点进行分割点的遍历,也可以同时对所有特征进行分割点的遍历,这样特征的选择和叶结点的分裂可以同时进行,达到并行化计算的目的,可以进行分布式或多线程计算,缩短训练时间。 -
cache-aware预取
在分块并行中,block存储了排序的列,并建立和原来样本的一一映射,这样可以通过特征值来找到原始样本获得梯度,但是原始样本是存放是按照列值的原始顺序的,相邻内存的样本他们对应的列值可能不是连续的,而我们现在根据排序后的列值来找原样本,那么肯定会出现在内存上的跳跃式查找,就非连续内存访问,可能导致CPU cache命中率降低。所以在线程中开辟一块连续空间,对需要用到的梯度 进行预取和存储。在数据集较大的时候,缓存机制效果比较好 -
out-of-core computation
当训练样本太大无法全部加载到内存中时,会把数据分成许多个block并存储在硬盘中,需要计算的时候,用另一个线程加载数据到内存中,这样读取与计算可以同步进行。但是我们知道从磁盘读取数据会比较耗时,因此作者又提出了两个优化方法去解决这个问题。
第一个方法叫做Block compression,将block按列压缩存储,读取的时候用另外的线程边读取边解压;第二个方法叫做Block sharding,是将数据划分到不同磁盘上,为每个磁盘分配一个预读取线程,并将数据提取到内存缓冲区中,然后训练线程交替地从每个缓冲区读取数据。这有助于在多个磁盘可用时增加磁盘读取的吞吐量。
4 LightGBM
LightGBM和XGBoost一样是对GBDT的高效实现,原理上它和GBDT及XGBoost类似,都采用损失函数的负梯度作为当前决策树的残差近似值,去拟合新的决策树。
LightGBM在很多方面会比XGBoost表现的更为优秀。它有以下优势:
- 更快的训练效率
- 低内存使用
- 更高的准确率
- 支持并行化学习
- 可处理大规模数据
- 支持直接使用category特征
参考资料
XGBoost的优化方法: https://zhuanlan.zhihu.com/p/125594314
XGBoost入门系列第一讲: https://zhuanlan.zhihu.com/p/27816315
《统计学习方法》 李航