文章目录
接上篇Xgboost。
来自 大神的《AI算法工程师手册》
4.lightgbm,light gradient boosting machine
- 训练快,效率高
- 使用很少的内存
- 精确率不错,和xgboost差不多
- 可以并行算法
- 可以处理大量数据
主要思想:如果减少训练样本的数量,或减少样本的训练特征数量,可以大幅度加快训练速度。
使用了如下两种方法:
- GOSS(gradient-based one-side sampling):
goss随机排除了一些只有小梯度的样本,用剩余的样本去评估信息增益.(先挑选大梯度样本,再从小梯度中随机抽样,进行计算,避免过拟合) - EFB(exclusive feature bunding):
将互斥特征进行特征捆绑,减少样本的特征
4.1 GOSS
在GBT中,将每个样本的负梯度代替残差,拟合新树。如果样本的梯度较小,代表样本已经得到了较好的拟合。因此GOSS将样本的梯度作为权重,梯度较小、拟合较好的样本,在本轮拟合中权重较小。
- 先根据样本梯度进行排序,然后选择top a x 100%的样本;从剩下的样本中随机抽样b x 100%。
- 将小梯度样本进行修正:对保留下来的小梯度样本,将梯度乘以系数 1 − a b \frac{1-a}{b} b1−a,代表从不重要的样本中随机保留的样本的比例的导数。
4.1.1 寻找最佳分裂点算法 histogram-based alogrithm
先把连续的浮点特征值离散化成k个整数,同时构造宽度为k的直方图。遍历数据时
- 根据离散化后的值作为索引在直方图中累计统计量
- 当遍历一次数据后,直方图累计了需要的统计量
- 根据直方图的离散值,遍历寻找最优分裂点
4.1.2 获得新样本训练模型算法 gradient-based one-side sampling
输入:
训练集;大梯度采样比a;小梯度采样比b
输出:
下一个子树
h
m
(
x
)
h_m(x)
hm(x)
算法:
- 计算:
- f a c t o r = 1 − a b factor = \frac{1-a}{b} factor=b1−a ,修正因子
- t o p N = a × l e n ( I ) topN = a \times len(I) topN=a×len(I),重要样本数
- r a n N = b × l e n ( I ) ranN = b \times len(I) ranN=b×len(I),随机样本数
- 根据梯度绝对值大小,将样本排序
- 取 t o p N topN topN个样本作为重要样本
- 在 t o p N topN topN之外,随机选取 r a n d N randN randN 个样本做保留样本
- 构建新的训练集:
- t o p N topN topN个重要样本,每个样本权重都是1
- r a n d N randN randN 个随机保留的样本,每个样本的权重都是fractor
- 根据新的训练集和权重,训练决策树 h m ( x ) h_m(x) hm(x)来拟合残差(即负梯度)
4.2 EFB
高维数据通常是稀疏的,许多特征间互斥。他们不会同时拥有非零值。我们可以把互斥特征进行bundle(捆绑),通过算法可以随同一个bundle里的特征做相同的直方图,大幅减少特征的数量。
4.2.1 发现互斥特征算法 greedy bundling
用特征构建图:
-
将每个特征视为图中的一个顶点。遍历每个样本,如果此样本中特征 j , k j,k j,k之间不互斥
- 如果在图上 i , j i,j i,j间不存在边,则连接一条边,权重为1
- 如果存在边,权重加1
-
最终,如果顶点之间不存在边,则这两个特征互斥,可以放到同一个打包特征集中。
-
但某些特征间不完全互斥,存在少量冲突。如果允许少量冲突,则可以将更多特征放图打包特征集中,减少更多的特征。
4.2.2 互斥特征打包 merge exclusive features
互斥特征打包的思想
可以从打包的特征中分离出原始的特征。
距离:假设特征 a 的取值范围为 [0,10), 特征 b 的取值范围为 [0,20) 。如果a,b 是互斥特征,那么打包的时候:对于特征 b的值,给它一个偏移量,比如 20。最终打包特征的取值范围为:[0,40)。
- 如果打包特征的取值在 [0,10), 说明该值来自于特征 a 。
- 如果打包特征的取值在[20,40),说明该值来自于特征 b 。
依然用直方图寻找最佳分裂点
将 [0,x] 区间的数值属于特征 a, 将 [x+offset,y] 区间的数值属于特征 b。 其中 offset > 0 。
算法
输入:
- 样本集
- 待打包的特征集合B
算法: - 令 t o t a l B i n totalBin totalBin记录总的分桶数量(即集合B中特征各自区间数目之和); b i n R a n g e s binRanges binRanges记录不同的特征的边界,(即从第几个区间开始属于不同的特征)。初始化 t o t a l B i n = 0 , b i n R a n g e s = ∅ totalBin=0,binRanges=\empty totalBin=0,binRanges=∅
- 计算特征边界:遍历所有的特征
j
∈
B
j \in B
j∈B(打包集合中的特征):
- 获取特征 j j j的分桶数量 n u m ( j ) num(j) num(j)(即区间划分数量),增加到 t o t a l B i n : t o t a l B i n + = n u m ( j ) totalBin :totalBin += num(j) totalBin:totalBin+=num(j)
- 获取特征的分桶边界: b i n R a n g e s . a p p e n d ( t o t a l B i n ) binRanges.append(totalBin) binRanges.append(totalBin)
- 创建新特征,它有 t o t a l B i n totalBin totalBin个桶。
- 计算分桶点:遍历每个样本
- 计算每个特征
j
∈
B
j \in B
j∈B:
- 如果样本中 j j j特征值不为0(这时集合中其他特征值为0),如果该样本在特征 j j j的第k个分桶中,那么在打包后的特征中,它位于桶 b i n R a n g e s [ j ] + k binRanges[j] +k binRanges[j]+k中
- 如果样本中 j j j特征值为0,不考虑
- 计算每个特征
j
∈
B
j \in B
j∈B:
4.3 优化
- 基于直方图的最佳分裂点寻找
- 带深度限制的leaf_wise叶子生长策略
- 直方图做差加速
- 支持类别(categorical)特征
- 并行优化
4.3.1 leaf_wise和level_wise
lightgbm采用了leaf_wise策略,而xgboost采用了level_wise(每层上做惩罚)的策略。
- level_wise:
对每一层的节点做无差别分裂,可能有些节点的增益非常小,对结果影响不大,但xgboost也会对其分裂,浪费了资源。(树的结构是平衡二叉树) - leaf_wise:
当前叶节点中选择分裂收益最大的节点进行分裂,这样容易过拟合,陷入较大的深度,因此必须设置树深。
4.3.2 直方图差加速
通常构造直方图,需要遍历该叶子上所有数据,但事实上一个叶子的直方图可以由它的父节点直方图和兄弟节点的直方图得到。因此在构造了一个叶子的直方图后,可以用非常微小的代价得到兄弟叶子的直方图,在速度上可以提升一倍。
4.3.3 categorical feature
- xgboost必须将别型特征one-hot 编码;
- 将类别型特征转换为one-hot会耗用内存,引起树的不平衡,需要很大的树深才能达到较好的精度
- 一个可替代的优化方法是对分类特征进行二分,这样就会有 2 k − 1 − 1 2^{k-1}-1 2k−1−1个分裂点(例如,有三个值,第一个值是1,其他值都是0,这就是二分类)
- lightgbm不需要提前对类别特征one-hot处理;
根据类别特征和目标变量的相关性进行重新排序。即根据分类特征的累计值(sun_gradient/sum_hessian)对直方图进行重排,然后在排序号的直方图上寻找最佳分裂点。
4.3.4 并行
- 特征并行
- 每个机器都有全部样本的全部特征集合
- 每个机器在本地数据集中寻找最佳划分点:(划分特征,划分阈值)。但不同的机器在不同的特征集上运行。
- 将所有的机器上的最佳分裂点整合,得到全局最佳
- 再用全局最佳对数据集划分
- 数据并行
- 用reduce scatter的方式对不同机器上的不同特征进行整合。
- 通过直方图做查分加速