目录
1.XGBoost
XGBoost能自动利用CPU的多线程,而且适当改进了gradient boosting,加了剪枝,控制了模型复杂度
- 传统GBDT以CART作为基分类器,特指梯度提升决策树算法,而XGBoost还支持线性分类器(gblinear),这个时候XGBoost就相当于带L1正则和L2正则项的logistics回归(分类问题)或者线性回归(回归问题)
- 传统的GBDT只用到一阶导数信息,xgboost则对代价函数进行了二阶泰勒展开,同时用到了一阶和二阶导数。
- xgboost在代价函数里加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数、每个叶子节点上输出的score的L2模的平方和。从Bias variance tradeoff角度来讲,正则项降低了模型的variance,使学习出来的模型更加简单,防止过拟合,这也是xgboost优于传统的GBDT的一个特性
xgboost中树节点分裂时所采用的公式:
- Shrinkage(缩减),相当于学习速率(xgboost中的eta)。xgboost在进行完一次迭代后,会将叶子节点的权重乘上该系数,主要是为了削减每棵树的影响,让后面有更大的学习空间。实际应用中,一般把eta设置得小一点,然后迭代次数设置得大一点(传统gbdt的实现也有学习速率)
- 列抽样(column subsampling)。xgboost借鉴随机森林的做法,支持列抽样,不仅能降低过拟合,还能减少计算,这也是xgboost不同于gbdt的一个特性
- 对缺失值的处理。对于特征的值有缺失的样本,xgboost可以自动学习出它的分裂方向
- xgboost工具支持并行。注意:xgboost的并行不是tree粒度的并行,xgboost也是一次迭代完才能进行下一次迭代的(第t次迭代的代价函数里包含了前面t-1次迭代的预测值)。xgboost的并行是在特征粒度上的。决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要确定最佳分割点),xgboost在训练之前,预先对数据进行了排序,然后保存为block结构,后面的迭代中重复地使用这个结构,大大减少计算量。这个block结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选择增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行。(特征粒度上的并行,block结构,预排序)
- 上面这个公式形式上跟ID3算法、CART算法是一致的,都是用分裂后的某种值减去分裂前的某种值,从而得到增益。为了限制树的生长,我们可以加入阈值,当增益大于阈值时才让节点分裂,上式中的gamma即阈值,它是正则项里叶子节点数T的系数,所以xgboost在优化目标函数的同时相当于做了预剪枝。另外上式中还有一个系数lambda,是正则项里leaf score的L2模平方的系数,对leaf score做了平滑,也起到了防止过拟合的作用,这个是传统gbdt里不具备的特性。
xgboost的分裂步骤:
- 首先,对所有特征按数值进行预排序
- 其次,在每次的样本分割时,用O(#data)的代价找到每个特征的最优分割点
- 最后,找到最后的特征以及分割点,将数据分割成左右两个子节点。
- 优点:这种pre-sorting算法能够准确找到分裂点,但是在空间和时间上有很大的开销;
- 缺点:1:需要对特征进行预排序,且需要保存排序后的索引值(为了后续快速的计算分裂点),因此内存需要训练数据的两倍
- 缺点:2:在遍历每一个分裂点的时候,都需要进行分裂增益的计算,消耗的代价大。
xgboost总结
- 显式地将树模型的复杂度作为正则项加在优化目标
- 公式推导中用到了二阶导数信息,而gbdt只用到一阶导数
- 允许使用列抽样(column subsampling)来防止过拟合,借鉴了random forest的思想,
- 实现了一种分裂节点寻找的近似算法,用于加速和减小内存消耗
- 节点分裂算法能自动利用特征的稀疏性
- 样本数据事先排好序并以block的形式存储,利于并行计算
- penalty function Omega 主要是对树的叶子节点数和叶子分数做惩罚,这点确保了树的简单性
- 支持分布式计算,可以运行在MPI,YARN上,得益于底层支持容错的分布式通信框架rabit
LightGBM:基于决策树算法的分布式梯度提升框架
LightGBM在模型的训练速度和内存方面的优化
- 基于树模型的boosting算法,很多算法比如xgboost都是用预排序(pre-sorting)算法进行特征的选择和分裂
- LightGBM采用HistoGram算法,其思想是将连续的浮点特征离散成k个离散值,并构造宽度为k的Histogram。然后遍历训练数据,计算每个离散值在直方图中的累计统计量。在进行特征选择时,只需要根据直方图的离散值,遍历寻找最优的分割点。
LightGBM的leaf-wise 的生长策略
- 它摒弃了现在大部分gbdt使用的按层生长(level-wise)的决策树生长策略,使用带有深度限制的按叶子生长(leaf-wise)策略。level-wise过一次的数据可以同时分裂同一层 的叶子,容易进行多线程优化,也好控制模型复杂度,不容易过拟合。但实际上level-wise是一种低效的算法,因为它不加区分的对待同一层的叶子,带来了很多没必要的开销,因为实际上很多叶子的分裂增益较低,没必要进行搜索和分裂。
- leaf-wise则是一种更为高效的策略,每次从当前所有叶子中,找到分裂增益最大的一个叶子,然后分裂,如此循环。因此同level-wise相比,在分裂次数相同的情况下,leaf-wise可以降低更多的误差,得到更好的精度。leaf-wise的缺点是可能会长出比较深的决策树,产生过拟合。因此LightGBM在leaf-wise之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合。
LightGBM支持类别型特征
实际上大多数机器学习工具都无法直接支持类别型特征,一般需要把类别特征转化为one-hotting特征,降低空间和时间的效率。而类别特征的使用是在实践中很常用的。基于这个考虑LightGBM优化了对类别特征的支持,可以直接输入类别特征,不需要额外的0/1展开。并在决策树算法上增加了类别特征的决策规则:
- Histogram算法并不是完美的。由于特征被离散化后,找到的并不是很精确的分割点,所以会对结果产生影响。但在实际的数据集上表明,离散的分割点对最终的精度影响并不大,甚至会更好一点。原因在于decision tree本身就是一个弱学习器,采用Histogram算法会起到正则化的效果,能有效的防止过拟合
- 时间上的开销由原来的O(#data*#features)将到O(#k*#features)。由于离散化,#bin远小于#data,因此时间上有很大的提升。
- Histogram算法还可以进一步加速。一个叶子节点的Histogram可以直接由父节点的Histogram和兄弟节点的Histogram做差得到。一般情况线下构造Histogram需要遍历该叶子上的所有数据,通过该方法,只需要遍历Histogram的k个桶。速度提升了一倍。
xgboost与LightGBM的区别
- 切分算法(切分点的选取)
- 占用的内存更低,只保存特征离散化后的值,而这个值一般用8位整型存储就足够了,内存消耗可以降低为原来的1/8
- LightGBM直接支持类别特征
- 决策树生长策略不同
XGBoost采用的是带深度限制的level-wise生长策略。level-wise过一次数据可以能够同时分裂同一层的叶子,容易进行多线程优化,不容易过拟合;但不加区分的对待同一层叶子,带来了很多没必要的开销(实际上很多叶子的分裂增益较低,没必要进行搜索和分裂)
LightGBM采用leaf-wise生长策略,每次从当前所有叶子中找到分裂增益最大(数据量最大)的一个叶子,进行分裂,如此循环;但会生长出比较深的决策树,产生过拟合(因此LightGBM在leaf-wise之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合)