LighGBM
前言
LighGBM作为GBDT算法的衍生模型,在其他论文研究以及数学建模比赛中十分常见。如果不熟悉GBDT算法的可以去看看我的上一篇文章,过多关于GBDT的细节不再过多描述。主要将讲述一下LighGBM较于GBDT算法的改进以及独特算法细节优化,以及比XGBoost和CatBoost算法较好的应用场景。总体而言,LightGBM在性能和效率方面都有很大的优势,特别适用于中小规模的数据集和高维度的特征。
一、LighGBM算法概述
LightGBM(Light Gradient Boosting Machine)是一种基于梯度提升决策树(Gradient Boosting Decision Tree,简称GBDT)算法的机器学习框架。GBDT是一种集成学习方法,它通过逐步训练一系列决策树来提升模型性能。每个新的决策树会尝试纠正前面树的预测误差。LightGBM是一种基于GBDT的算法,但它在构建决策树和训练过程中采用了一些优化策略,以提高效率和性能。下表为GBDT衍生模型优化对比:
算法差异点 | GBDT | XGBoost | LightGBM | CatBoost |
---|---|---|---|---|
弱学习器 | CART回归树 | 1.CART回归树2.线性学习器3.Dart树 | Leaf-wise树 | 对称树 |
寻找分裂点 | 贪心算法 | 近似算法 | 直方图算法 | 预排序算法 |
稀疏值处理 | 无 | 稀疏感知算法 | EFB(互斥特征捆绑) | 无 |
类别特征 | 不直接支持,可自行编码后输入模型 | 同GBDT | 直接支持,GS编码 | 直接支持,Ordered TS编码 |
并行支持 | 不可以 | 可以 | 可以 | 可以 |
一图流展示优化点:
既然LightGMB算法模型建立的比XGBoost晚,那么其算法必然在XGBoost模型上进行进一步优化。首先XGBoost空间消耗大,因为XGBoost构建决策树的算法基本思想是预排序算法,这样的算法需要保存数据的特征值,还保存了特征排序的结果,这就需要消耗训练数据两倍的内存。其次,时间上也有较大的开销,在遍历每一个分割点的时候,都需要进行分裂增益的计算,消耗的代价大。
因此LightGMB主要着重解决的是构建决策树以及算法开销上的优化。
二、算法改进之处
1.Leaf-wise生长策略
LightGBM采用了leaf-wise的生长策略,与大多数GBDT传统的level-wise策略相比,能够更快地找到更优的分割点。这是因为leaf-wise策略每次选择能够降低损失函数最多的叶子节点进行分裂,从而更快地构建深度树。
1.1选择最佳分割点
在每次构建分割节点时,Leaf-wise策略会选择能够最大程度降低损失函数的特征和分割点。这是通过遍历特征的所有可能分割点,并计算分割后的两个子节点上的损失函数来实现的。
1.2贪心选择
Leaf-wise策略是一种贪心算法,每次选择能够最大程度减小损失函数的特征和分割点。这种选择策略使得树能够更快地学习到数据的细节和特征之间的关系。
1.3剪枝
在构建完一个节点后,Leaf-wise策略还会进行剪枝操作,即比较当前节点的损失减小值与一个阈值。如果损失减小值不满足阈值条件,就停止节点的继续分割,从而避免过拟合。
1.4叶子节点分配
Leaf-wise策略中,新的样本会被分配到现有的叶子节点中。如果某个叶子节点的分割后损失函数下降不足,该节点会停止继续分割,成为一个叶子节点。
1.5深度
由于Leaf-wise策略的贪心特性,它能够构建更深的树。然而,由于每次只选择一个分割点,有时候会导致某些叶子节点包含较少样本,可能会引发过拟合问题。因此,在训练时需要通过参数来控制树的最大深度或者其他正则化手段。
2.直方图特征优化
LightGBM中的直方图优化是一种针对特征处理的技术,用于加速决策树的构建过程。它通过将连续的特征值划分为一系列离散的直方块(即直方图),从而减少了计算复杂度和内存占用。
2.1特征值划分
对于每个连续特征,LightGBM首先会将特征的取值范围按照一定的间隔(bin)划分成离散的区间,形成一个直方图。每个区间被称为一个bin,其中包含了该特征值在这个区间内的样本。这种离散化分桶思路其实有很多优点的, 首先最明显就是内存消耗的降低,xgboost需要用32位的浮点数去存储特征值, 并用32位的整型去存储索引,而Lightgbm的直方图算法不仅不需要额外存储预排序的结果,而且可以只保存特征离散化后的值,而这个值一般用8位整型存储就足够了,内存消耗可以降低为原来的1/8。
以下图片来自https://blog.csdn.net/wuzhongqiang/article/details/105350579 推荐阅读。
2.2统计梯度和Hessian
每个bin中,LightGBM会计算样本的梯度和Hessian的累积值。这些值用于在寻找最佳分割点时评估损失函数的变化。
2.3选择分割点
在寻找最佳分割点时,LightGBM会遍历每个bin之间的边界,以及每个bin内部的候选分割点。它使用累积的梯度和Hessian值来评估在这些分割点上的损失减小情况,从而选择最优的分割点。直方图优化还能够直接处理类别特征和缺失值。对于类别特征,LightGBM会将不同类别分配到不同的bin中。对于缺失值,LightGBM会将缺失值分配到一个特殊的bin中,从而有效地处理缺失信息。
3.单边梯度抽样算法(GOSS)
一般来说我们会在数据预处理部分就会开始做数据均衡工程,但是LightGBM内置GOSS算法的主要目标是加速训练过程,同时保持模型性能。它通过保留梯度较大的样本来减少数据集的大小,以便在每次迭代中更有效地更新模型。而数据均衡算法主要关注处理样本不平衡问题,通过调整样本权重或采样策略来平衡不同类别的影响。
GBDT中每个数据都会有不同的梯度值,即梯度小的样本,训练误差也比较小,梯度比较小的样本对于降低残差的作用效果不是太大,所以我们可以关注梯度高的样本。
算法流程如下:
通过GOSS算法,LightGBM能够在保持模型性能的同时,降低训练数据集的大小,从而加速训练过程。这对于大规模数据集尤其有用,可以减少每次迭代所需的计算和存储资源。需要注意的是,GOSS算法可能会引入一些噪声,因为它会丢弃一部分样本,但通常情况下,这种噪声的影响可以通过调整超参数来控制。
4.互斥特征捆绑算法(EFB)
“互斥特征捆绑算法”(Exclusive Feature Bundling,EFB)是LightGBM中用于处理高维度数据中特征相关性问题的一种技术。其思想是将高度相关的特征捆绑在一起,将它们视为一个整体进行处理,以降低模型的复杂性和过拟合风险。
4.1特征相关性捆绑
在高维度数据中,有时会存在许多高度相关的特征。这些特征可能会导致模型过拟合,因为它们提供了类似的信息,但会增加模型的复杂性。EFB的思想是将这些高度相关的特征捆绑在一起,视为一个特征组。
极端稀疏数据如下图就可以比较直观的看到效果,当然实际算法和PCA降维算法类似。
4.2特征组代表
在每个特征组中,EFB会选择一个特征作为代表性特征。这个代表性特征在特征组内与其他特征的相关性较低,因此它可以被视为特征组的代表。
EFB 算法利用特征和特征间的关系构造一个加权无向图,并将其转换为图着色的问题来求解,求解过程中采用的贪心策略。
- 首先将所有的特征看成图的各个顶点,将不相互独立的特征用一条边连起来,边的权重就是两个相连接的特征的总冲突值(也就是这两个特征上同时不为0的样本个数)。
- 然后按照节点的度对特征降序排序, 度越大,说明与其他特征的冲突越大
- 对于每一个特征, 遍历已有的特征簇,如果发现该特征加入到特征簇中的矛盾数不超过某一个阈值,则将该特征加入到该簇中。 如果该特征不能加入任何一个已有的特征簇,则新建一个簇,将该特征加入到新建的簇中。
4.3特征转换
在训练过程中,EFB会将特征组内的特征进行转换,使其与代表性特征之间的相关性最小化。这有助于减少特征捆绑对模型性能的影响。通过将高度相关的特征捆绑在一起,EFB减少了模型中的特征数量,从而降低了模型的复杂性。这有助于减少过拟合风险,提高模型的泛化能力。
讲了太多理论内容怕大家一时半会消化不过来,直接上实例展示一下lightgbm算法的强大。
三、基于LightGBM用户购买意愿预测模型搭建
经过了上面的学习我们清楚LightGBM模型的几个要点,不需要再对数据进行数据均衡处理,也不需要额外的缺失值处理,并且还不需要特征降维操作,能够直接处理类别特征,直接免去了大量的数据工程。
那么我们首先预览一下数据集:
这是2021 华数杯全国大学生数学建模竞赛C题数据集,列表每一个维度特征对应着客户个人特征调查表中收集的维度数据。
以及
- a1、舒适性(环保与空间座椅)整体表现满意度得分
- a2、经济性(耗能与保值率)整体 满意度得分
- a3、安全性表现(刹车和行车视野)整体满意度得分
- a4、动力性表现(爬 坡和加速)整体满意度得分
- a5、驾驶操控性表现(转弯和高速的稳定性)整体满意度得 分
- a6、外观内饰整体表现满意度得分
- a7、配置与质量品质整体满意度得分
如果根据a1到a7正常来推算购买意愿是比较容易的算法,但是结合用户特征表B表的数据,我们还需要根据问题不同来处理每一个对应维度的数据是否定类还是定量。那么这些问题如果采用传统的机器学习来说就会比较麻烦,需要数据清洗和数据均衡,因为有购买意愿的用户是极少的:
且数据也存在大量空值需要处理:
但是我们使用LightGBM就可以无视以上这些情况直接训练,以下是一些常用的LightGBM训练参数:
- boosting_type(提升类型): 可选值包括’gbdt’(传统的梯度提升树)、‘rf’(随机森林)、‘dart’(Dropouts meet Multiple Additive Regression Trees)和’goss’(Gradient-based One-Side Sampling)等。
- num_leaves(叶子节点数): 定义每棵树的叶子节点数量,较大的值可以增加模型的复杂性,但也可能导致过拟合。
- learning_rate(学习率): 控制每次迭代中模型参数的更新步长。较小的值会使训练过程更加稳定,但可能需要更多的迭代次数。
- n_estimators(迭代次数): 指定训练的树的数量,通常需要根据问题的复杂程度来设置。
- max_depth(树的最大深度): 限制每棵树的最大深度,可以用于防止过拟合。
- min_child_samples(叶子节点最小样本数): 指定每个叶子节点上的最小样本数,用于控制剪枝,防止生成过深的树。
- subsample(子采样比例): 控制每棵树训练时的样本子采样比例,用于防止过拟合。
- colsample_bytree(特征子采样比例): 控制每棵树训练时的特征子采样比例,用于防止特征间的强相关性影响。
- reg_alpha(L1正则化项) 和 reg_lambda(L2正则化项): 用于控制模型复杂性,防止过拟合。
- scale_pos_weight(正负样本权重平衡): 用于处理类别不平衡问题,增加少数类别的样本权重。
- objective(目标函数): 定义要最小化的损失函数,例如’regression’(回归问题)或’binary’(二分类问题)等。
- metric(评估指标): 用于评估模型性能的指标,如’rmse’(均方根误差)、‘auc’(ROC曲线下面积)等。
这只是一些常用的LightGBM训练参数示例,实际使用中还有很多其他参数可以进行调节。不同的问题和数据集可能需要不同的参数配置,因此在使用LightGBM时,您可以根据问题的特点进行参数调优,以获得最佳的模型性能。可以通过查阅LightGBM的官方文档和相关资源,深入了解每个参数的含义和使用方法。
import lightgbm as lgb
from sklearn.model_selection import train_test_split
import joblib
from sklearn.metrics import mean_squared_errorX_train, X_test, y_train, y_test = train_test_split(X, target, test_size=0.2)# 创建成lgb特征的数据集格式
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)# 定义训练参数
params = {'boosting_type': 'gbdt','objective': 'binary', # 适用于二分类问题'metric': 'binary_logloss', # 适用于二分类问题的损失函数'num_leaves': 31,'learning_rate': 0.05,'feature_fraction': 0.9,'bagging_fraction': 0.8,'bagging_freq': 5,'verbose': 0
}# 训练模型
num_round = 100 # 迭代次数
bst = lgb.train(params, lgb_train, num_round, valid_sets=[lgb_eval], early_stopping_rounds=10)# 保存模型
model_filename = 'lgb_model.pkl'
joblib.dump(bst, model_filename)# 预测数据集
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration)# 评估模型
print('The rmse of prediction is:', mean_squared_error(y_test,y_pred))
混淆矩阵:
from sklearn.metrics import confusion_matrix
import numpy as np
# 使用 NumPy 将小于 0.5 的值归为 0,大于等于 0.5 的值归为 1
y_pred_binary = (y_pred >= 0.5).astype(int)labels=[0,1]
cm= confusion_matrix(y_test, y_pred_binary,labels=[0,1])
sns.heatmap(cm,annot=True ,fmt="d",xticklabels=labels,yticklabels=labels)plt.title('confusion matrix') # 标题
plt.xlabel('Predict lable') # x轴
plt.ylabel('True lable') # y轴
plt.show()
样本案例的数据不太好,太不均衡了没办法,下次如果有好的数据集再重新跑一遍。
总结
最后还是和上篇算法的XGBoost算法对比一下:
LightGBM的优点:
- 更快的训练速度: LightGBM采用了GOSS(Gradient-based One-Side Sampling)和直方图优化等技术,使得它在训练速度上通常比XGBoost更快。这对于处理大规模数据集非常有益。
- 更低的内存消耗: LightGBM通过对特征值的离散化处理和直方图优化,减少了内存的使用,尤其适合处理大数据。
- 更好的处理高维稀疏数据: LightGBM在处理高维稀疏数据时表现更好,这是因为它可以使用直方图优化技术。
- 更好的处理类别特征: LightGBM能够直接处理类别特征,无需进行独热编码等处理。
- 支持并行化: LightGBM支持并行化计算,可以有效地利用多核处理器。
LightGBM的缺点:
- 对异常值敏感: LightGBM的样本采样技术可能对异常值比较敏感,因此在处理异常值时需要小心。
XGBoost的优点:
- 较强的正则化: XGBoost在正则化方面更强,可以有效防止过拟合。
- 广泛应用: XGBoost已经存在较长时间,在许多数据科学竞赛和实际应用中得到了广泛应用,有更多的实践经验。
XGBoost的缺点:
- 较大的内存消耗: XGBoost在内存消耗方面相对较大,对于大规模数据集可能会受到限制。
- 速度相对较慢: 相对于LightGBM,XGBoost的训练速度可能稍慢。
总体来说,LightGBM和XGBoost都是非常出色的梯度提升树算法实现,在不同场景下可能有不同的优势。选择哪个算法取决于数据集的大小、特征的性质、计算资源以及具体的问题需求。在实际使用中,通常需要尝试不同的算法并进行参数调优,以找到最适合问题的算法和配置。
泛应用,有更多的实践经验。
XGBoost的缺点:
- 较大的内存消耗: XGBoost在内存消耗方面相对较大,对于大规模数据集可能会受到限制。
- 速度相对较慢: 相对于LightGBM,XGBoost的训练速度可能稍慢。
总体来说,LightGBM和XGBoost都是非常出色的梯度提升树算法实现,在不同场景下可能有不同的优势。选择哪个算法取决于数据集的大小、特征的性质、计算资源以及具体的问题需求。在实际使用中,通常需要尝试不同的算法并进行参数调优,以找到最适合问题的算法和配置。