1. 说明 官方文献说明,想深入研究的可以戳进去进一步学习
lightGBM是一个基于树模型的分布式Boosting算法,该算法是有微软开源贡献,说到tree-based模型一般都会想到XGBOOST算法,毕竟也是曾经的大杀器,那下面就把这两个算法进行一些对比。
2.Xgboost的优缺点 优点:(不详细说了,默认有树模型基础)
- 1.Xgboost利用的二阶梯度,相对于lightGBM在进行节点划分的时候,会有更高的精度
- 2.利用局部近似算法,对分裂节点的贪心算法进行优化,取适当的收益时,可以提高算法的性能和训练速度。
- 3.在损失函数中加入L1和L2正则化,降低模型的复杂度,提高模型的适用性,鲁棒性。
- 4.提供并行计算能力,主要是在树节点求不同的候选的分裂点的Gain Infomation(分裂后,损失函数的差值)。
- 5.Tree Shrinkage,column subsampling等不同的处理细节。
缺点: - 1.需要对特征值进行预排序,这样会消耗很多的内存空间。(2 *data * features,索引和值)
- 2.数据分割点上,由于xgboost对不同的特征进行了预排序,所以不同的特征的排序顺序是不同的,所以在分割时,要对每个特征的每个值进行单独的分割,遍历次数为data * features,以此将所有的数据分配到左右子支。
- 3.尽管使用了局部近似算法,但是分割的粒度依然很细
- 4.由于做了预排序的处理,在寻找特征分裂点是(level - wise),会产生大量的cache随机访问。
- 1.LightGBM基于histogram算法代替pre-sorted所构建的数据结构,利用histogram后,会有很多有用的tricks。例如histogram做差,提高了cache命中率(主要是因为使用了leaf-wise)。
- 2.在机器学习当中,我们面对大数据量时候都会使用采样的方式(根据样本权值)来提高训练速度。又或者在训练的时候赋予样本权值来关于于某一类样本(如Adaboost)。LightGBM利用了GOSS来做采样算法。
- 3.由于histogram算法对稀疏数据的处理时间复杂度没有pre-sorted好。因为histogram并不管特征值是否为0。因此我们采用了EFB来预处理稀疏数据。
相对于pre-sorted算法,它的内存空间需要相对小很多。因为pre-sorted算法需要保存起来每一个特征的排序结构,所以其需要的内存大小是2 * #data * #feature * 4Bytes(而histogram只需保存离散值bin value(EFB会谈到bin)而且我们不需要原始的feature value,所以占用的内存大小为:#data * # feature * 1Byte,因为离散值bin value使用uint8_t已经足够了。另外对于求子节点相应的feature histogram时,我们只需构造一个子节点的feature histogram,另外一个子节点的feature histogram我们用父节点的histogram减去刚构造出来的子节点的histogram便可,时间复杂度就压缩到O(k),k为histogram的桶数。这是一个很巧妙的做差法。
- 直方图优化示意图
- 针对特征值划分出bin,这样就可以将连续的特征值压缩到K个bin中
文章图片
- 针对特征值划分出bin,这样就可以将连续的特征值压缩到K个bin中
- 内存优化示意图
- 左边图是xgboost的内存使用情况,需要存储排序的索引Sorted_Indices和特征值Features_Values,并且全部是使用的4Byte
- 右边图是lightGBM的内存使用情况,不需要存储索引,仅仅需要存储bin的值就可以了,并且存储使用的是单字节1Byte
文章图片
其中文为梯度单边采样。大致的意思是根据样本某一特征上的单梯度作为样本的权值进行训练。其采样的方式有点巧妙:
- 1.选取前a%个较大梯度的值作为大梯度值的训练样本。
- 2.从剩余的1 - a%个较小梯度的值中,我们随机选取其中的b%个作为小梯度值的训练样本。
- 3.对于较小梯度的样本,也就是b% * (1 - 1%) * #samples,我们在计算信息增益时将其放大(1 - a) / b倍。
- 1.总的来说就是a% * #samples + b% * (1 - a%) * #samples个样本作为训练样本。
- 2.这样的构造是为了尽可能保持与总的数据分布一致,并且保证小梯度值的样本得到训练。
EFB中文名叫独立特征合并,顾名思义它就是将若干个特征合并在一起。使用这个算法的原因是因为我们要解决数据稀疏的问题。在很多时候,数据通常都是几千万维的稀疏数据。因此我们对不同维度的数据合并一起使得一个稀疏矩阵变成一个稠密矩阵。
这里就有两个问题:
- 1.如何确定哪些特征用于融合且效果为较好。
- 2.如何将这些特征合并到一齐。
注意:这一部分在官网我没看到,不确定是怎么使用的。
- 大多树的决策树生长方式是按照level - wise方式进行生长的,大概是按照下面这种:
文章图片
- lightGBM的决策树生长方式是按照leaf - wise方式进行生长,大概是按照下面这种:
文章图片
- 那么两者有什么区别呢?
- LightGBM对于树的生长使用的是Leaf-wise,而不是Level-wise。这样的做法主要是因为LightGBM认为Level-wise的做法会产生一些低信息增益的节点,浪费运算资源。其实通常来说,Level-wise对于防止过拟合还是很有作用的,所以大家都比较青睐与它相比与Leaf-wise。作者认为Leaf-wise能够追求更好的精度,让产生更好精度的节点做分裂。但这样带来过拟合的问题,所以作者使用的max_depth来控制它的最大高度。还有原因是因为LightGBM在做数据合并,Histogram Algorithm和GOSS等各个操作,其实都有天然正则化的作用,所以使用Leaf-wise来提高精度是一个很不错的选择。
对比项目 | leaf - wise | level - wise |
---|---|---|
应用 | lightGBM | xgboost |
资源使用 | 低 | 高 |
分裂方式 | 选择增益最大 | 全部节点进行分裂 |
精度 | 高 | 低 |
过拟合风险 | 高 | 低 |
过拟合控制 | 最大深度 | 风险较低 |
对比项目 | xgboost | LightGBM |
---|---|---|
正则项 | L1、L2 | L1、L2 |
列采样 | yes | yes |
Exact Gradient | yes | yes |
近似算法 | yes | no |
稀疏数据 | yes | yes |
分布式并行 | yes | yes |
缓存 | yes | no |
out of core | yes | no |
加权数据 | yes | yes |
树生长方式 | level-wise | leaf-wise |
最大深度控制 | 无 | 有 |
基于算法 | pre-sorted | histgram |
dropout | no | yes |
bagging | yes | yes |
应用 | 回归、分类、rank | 回归、分类、lambdrank |
GPU支持 | no | yes |
网络通信 | point-to-point | collective-communication |
Categorical Features | 无优化 | 有优化 |
Continued train with input GBDT model | no | yes |
Continued train with input | no | yes |
Early Stopping(both training and prediction) | no | yes |
- task: 默认值=train,可选项=train,prediction;指定我们希望执行的任务,该任务有两种类型:训练 和 预测;
- application: 默认值=regression,type=enum,options=options;
- regression: 执行回归任务;binary:二分类;
- multiclass:多分类;
- lambdarank:lambrank应用;
- data: type=string; training data,LightGBM将从这些数据中进行训练;
- num_iterations: 默认值为100,类型为int。表示提升迭代次数,也就是提升树的棵树;
- num_leaves: 每个树上的叶子数,默认值为31,类型为int;
- device: 默认值=cpu;可选项:cpu,gpu。也就是我们使用什么类型的设备去训练我们的模型。选择GPU会使得训练过程更快;
- mindatain_leaf: 每个叶子上的最少数据;
- feature_fraction: 默认值为1;指定每次迭代所需要的特征部分;
- bagging_fraction: 默认值为1;指定每次迭代所需要的数据部分,并且它通常是被用来提升训练速度和避免过拟合的。
- mingainto_split: 默认值为1;执行分裂的最小的信息增益;
- max_bin: 最大的桶的数量,用来装数值的;
- mindatain_bin: 每个桶内最少的数据量;
- numthreads: 默认值为OpenMPdefault,类型为int。指定LightGBM算法运行时线程的数量;
- label: 类型为string;指定标签列;
- categorical_feature: 类型为string;指定我们想要进行模型训练所使用的特征类别;
- num_class: 默认值为1,类型为int;仅仅需要在多分类的场合。
def train(params,# 参数设置,格式为字典格式
train_set, # 训练集,或者测试集
num_boost_round=100, # 迭代次数
valid_sets=None,# 交叉验证集
valid_names=None, # 交叉验证集的名字
fobj=None, # 自定义目标函数
feval=None, # 自定义评估函数,需要设置两个参数:preds, train_data,
init_model=None,# LightGBM模型或者其他Booster模型的文件名字,可用于加载模型
feature_name='auto', # 特征名字,如果是‘auto’就会自动识别DataFrame数据格式的列名
categorical_feature='auto', # 可以是"int"或者"string"类型的一个列表
early_stopping_rounds=None,# 可以是"int"类型的值,如果验证集上在这个数的范围内分数不再提高,就会自动停止训练。
evals_result=None, # 用来存储在验证集上每次迭代产生的结果
verbose_eval=True, # 控制台打印,如果为TRUE,就每次都打印;如果是5,就5次打印一次
learning_rates=None, # 学习率
keep_training_booster=False, # 是否返回一个Booster被用于继续训练,如果设置为False,返回值在返回前将会被转化成一个"_InnerPredictor",可以使用这个"_InnerPredictor"作为"init_model"。用于今后的模型训练。
callbacks=None)
5.参数调优 【机器学习算法|树类算法之---lightGBM使用与调参】LightGBM使用基于depth-wise的分裂的leaf-wise分裂算法,这使得它能够更快地收敛。但是,它也会导致过拟合。因此,这里给出一个LightGBM参数调优的快速指南。
5.1 控制过拟合
- numleaves:这个参数是用来设置组成每棵树的叶子的数量。numleaves 和 maxdepth理论上的联系是: numleaves = 2^(maxdepth)。然而,但是如果使用LightGBM的情况下,这种估计就不正确了:因为它使用了leafwise而不是level-wise分裂叶子节点。因此,numleaves必须设置为一个小于2^(maxdepth)的值。否则,他将可能会导致过拟合。LightGBM的numleave和max_depth这两个参数之间没有直接的联系。因此,我们一定不要把两者联系在一起。
- mindatain_leaf : 它也是一个用来解决过拟合的非常重要的参数。把它的值设置的特别小可能会导致过拟合,因此,我们需要对其进行相应的设置。因此,对于大数据集来说,我们应该把它的值设置为几百到几千。
- max_depth: 它指定了每棵树的最大深度或者它能够生长的层数上限。
文章图片
- bagging_fraction : 它被用来执行更快的结果装袋;
- feature_fraction : 设置每一次迭代所使用的特征子集;
- maxbin : maxbin的值越小越能够节省更多的时间:当它将特征值分桶装进不同的桶中的时候,这在计算上是很便宜的
- 使用更大的训练数据集;
- num_leaves : 把它设置得过大会使得树的深度更高、准确率也随之提升,但是这会导致过拟合。因此它的值被设置地过高不好。
- maxbin : 该值设置地越高导致的效果和numleaves的增长效果是相似的,并且会导致我们的训练过程变得缓慢。
推荐阅读
- 机器学习算法系列(七)-对数几率回归算法(一)(Logistic Regression Algorithm)
- 机器学习算法系列(六)- 弹性网络回归算法(Elastic Net Regression Algorithm)
- 机器学习算法系列(五)- Lasso回归算法(Lasso Regression Algorithm)
- 机器学习算法系列(四)- 岭回归算法(Ridge Regression Algorithm)
- 机器学习算法系列(二)- 口袋算法(Pocket Algorithm)
- 机器学习算法系列(一)- 感知器学习算法(PLA)
- 机器学习算法系列(〇)- 基础知识
- HMM之维特比算法
- spark|ALS算法推荐