LightGBM

参考文献:LightGBM: A Highly Efficient Gradient Boosting Decision Tree, Guolin Ke, 2017.

GBDT类算法对于每个特征都需要扫描所有的数据实例来估计所有可能拆分点的信息增益,计算复杂度与特征的数量和实例的数量成正比,因此在特征维数较高和数据量较大时其耗时久、内存使用量大,针对大数据场景下的这一问题,LightGBM的作者提出了两种新的技术即基于梯度的单边采样(gradient-based one-side sampling, GOSS)和互斥特征捆绑(exclusive feature bundling, EFB),前者排除了很大一部分具有小梯度的数据实例,只使用其余的数据实例来估计信息增益,由于梯度较大的数据实例在信息增益的计算中起着更重要的作用,GOSS可以用更小的数据量得到相当准确的信息增益估计。EFB通过捆绑互斥的特征来减少特征数量,尽管寻找互斥特征的最优捆绑是np困难的,但贪婪算法可以达到相当好的近似(有效地减少特征数量的情况下不会过多损害分割点的精度)。

LightGBM是对XGBoost的改进,属于GBDT的一种,可以理解为

\textup{LightGBM = XGBoost + Histogram + GOSS + EFB},

相比之下LightGBM在损失了少量精度的情况下极大缩短了训练时间、减少了内存使用,其整体算法框架与XGBoost相似差别是使用了数据压缩和降维方法。与PCA、下采样等方法相比,LightGBM损失的信息会少很多。

直方图算法

直方图算法

学习决策树最耗时的部分是寻找最佳分割点,寻找分割点最流行的算法之一是预排序算法,它在预排序的特征值上枚举所有可能的分裂点,该算法简单,可以找到最优分割点,但在训练速度和内存消耗方面效率较低。另一种流行的算法是直方图算法(Histogram algorithm),将数值型特征的值域分成离散的bins(分桶方法见本节最后),在训练时使用这些bins来构建特征直方图(每个bin里面都落入了一些样品,我们将不同的bin对应的取值范围作为柱状图的柱子,某些指标作为柱子的高度,形成直方图,指标包括bin包含的样品个数、一阶梯度值g、二阶梯度值h)。首先从根节点开始,构建每个特征的直方图(先分桶然后画直方图,分桶和树无关,因此仅需在整个LightGBM算法执行之初进行一次即可,后面每棵树训练时用到的梯度都和前面的树有关,因此直方图中的柱子高度是每棵树训练之初要重新计算的),分别对每个特征找到最优切分点,再从这些特征中挑选切分后收益提升最大的特征进行节点分裂,分裂后分裂属性的直方图也会分裂成两半,其他属性的直方图相应调整,为了加速训练,子结点上非分裂属性只需算出样品数较少的那边的直方图,然后用该属性父结点直方图减去此直方图即可得到另一边直方图。

由于基于直方图的算法在内存消耗和训练速度方面都更具效率,我们将在其基础上进行我们的工作。直方图构建成本为O(#data×#feature),分割点查找成本为O(#bin×#feature)。由于#bin通常比#data小得多,直方图的构建将主导计算复杂度。如果可以减少#data或#feature,就能大大加快GBDT的训练。

带深度限制的 Leaf-wise 算法

在Histogram算法之上,LightGBM进行进一步的优化。首先它抛弃了大多数GBDT工具(包括XGBoost)使用的按层(level-wise)决策树生长策略,使用带有深度限制的按叶子生长(leaf-wise)策略。每次从当前所有未分裂结点中(不论在哪一层),找到分裂增益最大的一个结点进行分裂,如此循环。同level-wise相比,leaf-wise在分裂次数相同的情况下可以降低更多的误差,得到更好的精度,但是也会由于可能长出较深的树而产生过拟合,因此LightGBM会对树设置一个最大深度限制,在保证高效率的同时防止过拟合。

特征分桶方法

对数值型特征,给特征分桶时有max_bin和min_data_in_bin两个重要参数,前者表示最多能用几个桶,后者表示每个桶里最少要装几个样品(设置min_data_in_bin是为了正则化,防止分不分没差别的情况,因为对于连续型特征其样本观测值每个都不等,假设取min_data_in_bin=1那分桶后和没分桶是一样的)。将特征的样本观测值从小到大排序,挨个放进桶中,一个桶中的样品数达到最低要求则换下一个桶,注意取同一个值的若干样品只能装在同一个桶里。假设第i个桶中样品的最小和最大值为l_iu_i,则此桶容纳的样品取值范围是

(\frac{u_{i-1}+l_{i}}{2}, \frac{u_i+l_{i+1}}{2}],

第一个桶左边界为-∞,最后一个桶的右边界为+∞。

例:某特征X的样本为

D_X=\{0.5,0.8,1,1,1,2,2,2.5,3,3,3,3,4,4,5,5,6\},

其观测值集合为

V_X=\{0.5,0.8,1,2,2.5,3,4,5,6\},

每个观测值的出现次数为

C_X=\{1,1,3,2,1,4,2,2,1\}.

若min_data_in_bin=3,且桶数足够,则取{0.5,0.8,1}的5个样品放进桶1,取{2,2.5}的3个样品放进桶2,取3的4个样品放进桶3,取{4,5,6}的5个样品放进桶4(尽管4和5已经能装够桶4但是剩下的6不能装够桶5因此将6也装桶4并不设桶5),每个桶的容纳范围是

\textup{bins}_X=\{(-\infty, 1.5], (1.5, 2.75], (2.75, 3.5], (3.5, +\infty]\}.

若桶数不够多,则每个桶可能要装比min_data_in_bin更多的样品,令

mean_bin_size = sum(C_X) / max_bin

即每个桶平均要装的样品数。C_X[i]≥mean_bin_size的取值D_X[i]独占一个桶,其他取值按桶数足够的情况由小到大往桶里放,凑够了一个桶(≥mean_bin_size)再换下一个桶。例如max_bin=3,则mean_bin_size=5.67,第一个桶放{0.5,0.8,1,2}的7个样品,第二个桶放{2.5,3,4}的7个样品,第三个桶放{5,6}的3个样品。每个桶的容纳范围是

\textup{bins}_X=\{(-\infty, 2.25], (2.25, 4.5], (4.5, +\infty]\}.

对类别特征,每个特征值单独分配一个bin,将特征的取值按样本中出现次数从多到少来排序,排序后,先丢弃排在最后的1%样本,再丢弃出现次数小于min_data_in_bin的样本。

GOSS

基于梯度的单边抽样(GOSS)从减少样本的角度出发,排除大部分小梯度的样本,仅用剩下的样本计算信息增益,它是一种在减少数据量和保证精度上平衡的算法。

虽然GBDT算法中数据实例不像在AdaBoost中那样具有权重,但我们注意到,具有不同梯度的数据实例在信息增益的计算中扮演不同的角色。特别是,根据信息增益的定义,那些梯度较大的实例(即训练不足的实例)会对信息增益做出更多贡献。因此,在对数据实例进行下采样时,为了保持信息增益估计的准确性,我们应该更多地保留那些具有较大梯度的实例(例如,大于预定义的阈值,或位于最高百分位数),并对具有小梯度的实例(训练误差很小且已经过良好训练)执行随机抽样,没抽到的丢掉。在目标采样率相同的情况下,这种处理方法可以得到比均匀随机抽样方法更精确的增益估计,特别是当信息增益的值有较大的范围时。

由于丢弃那些具有小梯度的数据实例会改变数据分布,损害学习模型的准确性,为了补偿对数据分布的影响,GOSS在计算信息增益时,对梯度小的数据实例引入一个常数乘法器。具体地,GOSS首先根据其梯度的绝对值对数据实例进行排序,选择最高的a×100%的实例。然后从其余的数据中随机抽取b×100%的实例。之后,GOSS在计算信息增益时,将采样的小梯度数据放大一个常数(1-a)/b。由此将更多的注意力放在未经训练的实例上,而不会对原始数据分布造成太大的改变。注意以上抽样过程在每棵树训练之前都要进行一次,参数ab的值始终是固定的。

例如,样本量是10,取a=0.3,b=0.2,将10个样本点按梯度的绝对值从大到小排序,前面10*a=3个样品保存下来,后面7个样品随机抽取10*b=2个,由于原来的7个样品只留下来2个,为了让它们发挥原有的作用,给它们对应的梯度和二阶导乘上(1-a)/b=7/2使得这部分样本在树分裂中计算增益时能够发挥原来的7个样品的影响。

EFB

实际应用中,高维数据通常非常稀疏。虽然特征数量很多,但特征空间是相当稀疏的,因此我们设计一种几乎无损的方法来减少特征数量。具体地,在稀疏特征空间中,许多特征是互斥或近似互斥的,即它们很少同时取非零值。我们可以捆绑这些互斥特征将其合并为一个特征(互斥特征捆绑,EFB)。通过一个精心设计的特征扫描算法,我们可以从特征bundle中构建与从单个特征中相同的特征直方图。这样,直方图构建的复杂性从O(#data×#feature)变为O(#data×#bundle),#bundle << #feature。在不影响准确性的前提下,显著加快GBDT的训练速度。对此,首先需要确定哪些特性应该捆绑在一起,其次如何构造bundle。

对第一点,可以证明最优捆绑策略是NP-Hard,这表明在多项式时间内不可能找到精确解。为了找到近似算法,我们将最优捆绑问题简化为图着色问题(给定无向图,图和用尽量少的颜色对图中顶点进行着色,使得相邻的顶点颜色不同。相同颜色的点就相当于互斥的特征,能够被捆绑在一起),并通过贪婪算法产生bundle。具体的,将特征作为顶点构造加权无向图,对任意两个不互斥(冲突)的特征用边将其相连,边的权重为两个特征的冲突比例(两个特征的冲突比例指二者同时取非零值的实例数除以二者不同时为零的实例数,冲突比例越大越不互斥)。注意到通常会有很多特征尽管不是100%互斥的但也很少同时取非零值。如果我们的算法允许程度不高的冲突则可以进一步提高计算效率。假设γ是我们设置的最大冲突比例,在画出的无向图中令权重小于γ的边删掉(代表两个顶点视为互斥)。接下来给图着色,流程为按度(顶点的度指与顶点直接相连的边的数量)从大到小的顺序依次给顶点着色,给相连的顶点涂上不同颜色,不相邻的尽可能涂相同颜色即可。涂完色后将图中颜色相同的顶点(特征)捆绑在一起。

对第二点,我们需要适当地将特征合并到一个bundle(指捆绑后产生的那个新特征)中。关键是确保可以从特征bundle中识别出原始特征的值。由于我们首先通过直方图算法将特征离散化了,因此可以通过让互斥特征分到不同的容器中来构建一个特征bundle,这一点通过向特性的原始值添加偏移量来实现,即先取待捆绑特征中的一个特征A,然后取另一个特征B将其取值加上样本观测值中A的最大值然后捆绑到A上,二者成为一个特征后再将C以同样方式捆绑进去,直到捆绑完所有特征。例如我们在一个特性包中有两个特性,原本特征A取[0, 10),特征B取值[0, 20)。然后我们在特征B的值上增加10的偏移量,使其特征的值从[10, 30)。之后,可以安全地合并特征A和特征B,使用范围为[0, 30)的合并特征替换原特征AB

总结

LightGBM由XGBoost改进而来,区别是其在数据压缩和特征选择等问题上做出的改进能极大提高训练效率,训练之前首先进行连续特征离散化(分箱,似乎数值型离散特征也可以用分箱来减少分裂点),再对这些离散型变量进行EFB(互斥特征捆绑降维),然后开始逐棵训练决策树,每棵树训练之前先用GOSS采样对数据进行压缩,与XGBoost不同,其训练过程中使用leaf-wise的方式来分裂结点。LightGBM可以直接处理类别特征,按"特征分桶方法"一节中的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值