LightGBM sklearn API实现与进阶
Ch.4 LightGBM sklearn API实现与进阶
1.LightGBM算法特性
根据上一小节的LGBM优化策略的总结,我们不难发现LGBM算法具备如下特性:
- 超高的计算效率
其实从上面的和GBDT的对比中不难发现,LGBM最大的特点就是计算效率上进行了诸多优化,这方面的优化在具体建模过程中表现为两个方面,其一是建模时间极大缩短,其二则是计算过程的内存占用大幅减少,并且,LGBM同时提供多线程并行计算、分布式计算和GPU加速计算等多种计算实现方式,选择合适的计算方式,可以进一步提升计算效率;
- 性能强劲
而同时,算法原理层面的“简化操作”并不会对LGBM的实际预测效率产生太大的影响,尽管从理论上来说,LGBM算法的精确性是介于RF和XGB之间(强于随机森林、弱与XGB),但实际建模过程中,这些微弱的理论层面的性能差异并不会带来太多实际影响,并且复杂度降低有时候反而会使得模型更克服过拟合问题,从而获得一个更好的预测结果。在实际使用过程中,LGBM和XGB性能层面并没有明显差异。
- 功能完善
并且作为新兴的(次世代)集成学习算法,LGBM提供了 Python、R 和 C++ 的 API,易于与其他机器学习库集成,且支持Windos、Linux、MacOS等平台部署,实现层面也同时拥有sklearn API和原生API等多种调用方式,功能层面同样支持多种损失函数、能够应对排序任务、时间序列任务等。
功能完善、性能强劲,同时能保持高效的计算效率,这也是Light一词的精髓所在。
我们将在Ch3.LightGBM原理进阶进行更加完整深入的原理介绍。在不影响LGBM使用的情况下,接下来我们将开始介绍
2.LightGBM算法的快速使用
在了解了LGBM基本原理和性能特性后,接下来让我们尝试快速使用先尝试着快速使用LGBM算法,并在实际使用过程中,逐步总结LGBM的计算效率和算法性能上的特性。
1.1 LGBM算法库安装
首次使用LGBM算法前,需要进行LGBM算法库的安装,这里推荐直接使用pip进行安装,在命令行中输入如下命令进行LGBM算法库的安装:
安装完成后,即可按照如下方式进行导入:
1 | import lightgbm as lgb |
1 | lgb? |
[1;31mType:[0m module
[1;31mString form:[0m <module 'lightgbm' from 'D:\\anaconda3\\lib\\site-packages\\lightgbm\\__init__.py'>
[1;31mFile:[0m d:\anaconda3\lib\site-packages\lightgbm\__init__.py
[1;31mDocstring:[0m
LightGBM, Light Gradient Boosting Machine.
Contributors: https://github.com/microsoft/LightGBM/graphs/contributors.
目前课程采用的LGBM版本是3.3.5,可以通过如下方式查看LGBM版本号:
1 | lgb.__version__ |
'3.3.5'
如果是低于这个版本的LGBM,则可在命令行中输入以下命令对LGBM进行升级:
1.2 LGBM的sklearn API快速使用
接下来我们尝试训练LGBM模型。对于LGBM来说,支持多种不同类型的数据输入以及多种不同类型的训练方式,这里我们先从最简单的应用情况开始介绍,即围绕CSV格式数据进行DATaFrame数据格式读取,并采用类sklearn的建模风格进行模型的训练。这里我们先采用鸢尾花数据集进行简单模型测试,数据导入和数据集划分如下:
1 | # 读取数据 |
1 | data.head() |
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | target | |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | 0.0 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | 0.0 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | 0.0 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | 0.0 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | 0.0 |
1 | data.shape |
(150, 5)
1 | # 划分数据集 |
1 | X_train.head() |
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
46 | 5.1 | 3.8 | 1.6 | 0.2 |
81 | 5.5 | 2.4 | 3.7 | 1.0 |
122 | 7.7 | 2.8 | 6.7 | 2.0 |
116 | 6.5 | 3.0 | 5.5 | 1.8 |
101 | 5.8 | 2.7 | 5.1 | 1.9 |
1 | y_train |
46 0.0
81 1.0
122 2.0
116 2.0
101 2.0
...
83 1.0
92 1.0
12 0.0
24 0.0
11 0.0
Name: target, Length: 120, dtype: float64
然后是模型实例化过程。和XGB类似,LGBM不同类型的模型(及功能)可以直接通过导入子模块的方式来调用,也可以直接通过父模块.子模块的方式直接进行调用,例如我们可以通过如下方式调用LGBM的分类模型:
1 | gbm = lgb.LGBMClassifier() |
LGBMClassifier()
也可以先导入,再调用:
1 | from lightgbm import LGBMClassifier |
1 | gbm = LGBMClassifier() |
LGBMClassifier()
在sklearn API中,模型已经设置好了默认超参数取值,可以完全不认识任何模型超参数的情况下进行建模。sklearn API中LGBM的超参数情况如下:
1 | LGBMClassifier? |
具体的模型训练过程和sklearn中其他模型一样,通过fit进行训练,并利用predict进行结果输出:
1 | # 训练模型 |
LGBMClassifier()
然后输出预测结果,同样可以输出类别结果和概率预测结果:
1 | gbm.predict(X_test) |
array([1., 0., 2., 1., 2., 2., 1., 2., 2., 2., 2., 1., 0., 2., 0., 1., 0.,
0., 1., 2., 2., 0., 1., 1., 1., 0., 1., 2., 2., 2.])
1 | gbm.predict_proba(X_test) |
我们可以借助argmax方法将概率预测结果转化为类别预测结果:
1 | np.argmax(gbm.predict_proba(X_test), 1) |
array([1, 0, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 0, 2, 0, 1, 0, 0, 1, 2, 2, 0,
1, 1, 1, 0, 1, 2, 2, 2], dtype=int64)
同样,我们可以调用accuracy_score函数快速查看最终模型在训练集和测试集上的准确率:
1 | accuracy_score(y_train, gbm.predict(X_train)), accuracy_score(y_test, gbm.predict(X_test)) |
(1.0, 0.9666666666666667)
至此,我们就完成了一次简单的LGBM算法的sklearn API调用。
2.LightGBM sklearn API超参数解释与使用方法
接下来我们进一步解释LGBM的sklearn API中各评估器中的超参数及使用方法。尽管此时我们并未深入讲解LGBM的算法原理,但LGBM评估器的整体超参数构成和GBDT、XGB类似,我们可以借助此前的知识、并通过类比的方法了解LGBM的每个超参数的具体作用。
在LGBM的sklearn API中,总共包含四个模型类(也就是四个评估器),分别是lightgbm.LGBMModel、LGBMClassifier 和 LGBMRegressor 以及LGBMRanker:
其中LGBMModel是 LightGBM 的基本模型类,它是一个泛型模型类,可以用于各种类型的问题(如分类、回归等)。通常,我们不直接使用 LGBMModel,而是使用针对特定任务的子类使用不同的类,即分类问题使用 LGBMClassifier 、回归问题使用 LGBMRegressor,而排序问题则使用LGBMRanker。接下来我们重点解释分类和回归模型类的超参数。
2.1 LGBMClassifier超参数概览
和sklearn中其他评估器命名规则一致,Classifier是用于分类问题的评估器,Regressor是用于回归问题的评估器,两个评估器的超参数构成类似,这里我们先看LGBMClassifier的超参数构成:
1 | LGBMClassifier? |
总的来看,我们可以将LGBMClassifier的超参数分为决策树剪枝超参数、Boosting过程控制超参数、特征和数据处理类超参数和其他超参数四类。其中决策树剪枝超参数包括max_depth(树的最大深度)、num_leaves(叶子节点数)、min_child_samples(子节点的最小样本数)等,都是大家非常熟悉的超参数;Boosting过程控制超参数和XGB的booster类似,包含boosting_type(提升类型,如gbdt、dart、goss、rf),n_estimators(迭代次数)、learning_rate(学习率)和reg_alpha(L1正则化系数)、reg_lambda(L2正则化系数);而特征和数据处理类超参数则主要与数据采样有关,包含subsample(样本子集的比例)、subsample_freq(进行子采样的频率)、colsample_bytree(列采样的比例)等;而其他参数则是一些对建模效果并没有重要影响的超参数,例如random_state(随机数种子)、n_jobs(并行计算所用的CPU核心数)、class_weight(类别权重)等。
从整体来看,LGBMClassifier的超参数构成并不复杂,对比XGB,甚至可以说是更加简洁清晰。
接下来我们就逐个解释这些超参数,并对其使用方法进行说明。
2.2 LGBMClassifier的决策树剪枝超参数
LGBM中决策树剪枝超参数和其他评估器中剪枝超参数并无区别,这类超参数已经在课程中反复解释过多次,超参数及解释如下:
Name | Description |
---|---|
num_leaves | 一棵树上的叶子节点数,默认为 31 |
max_depth | 树的最大深度,默认值为 -1,表示无限制 |
min_split_gain | 相当于min_impurity_decrease,再分裂所需最小增益。默认值为 0,表示无限制 |
min_child_weight | 子节点的最小权重和。默认值为 1e-3。较大的 min_child_weight 可以防止过拟合 |
min_child_samples | 相当于min_samples_leaf,单个叶子节点上的最小样本数量。默认值为 20。较大的 min_child_samples 可以防止过拟合 |
能够发现,相比决策树或者随机森林,LGBM的决策树剪枝类参数有所精简,保留了最能影响决策树生长的核心超参数。
2.3 LGBMClassifier的Boosting过程控制超参数解释
然后来看更加重要的Boosting过程控制超参数,首先较为复杂的是boosting_type,该超参数解释如下:
- boosting_type: 使用的梯度提升算法类型,默认为 ‘gbdt’,可选项包括 ‘gbdt’(梯度提升决策树)、‘dart’(Dropouts meet Multiple Additive Regression Trees)、‘goss’(Gradient-based One-Side Sampling)和 ‘rf’(Random Forest,随机森林)。其中GBDT是最常用、且性能最稳定的 boosting 类型,也是boosting_type默认取值;而dart (Dropouts meet Multiple Additive Regression Trees)则是一种结合了 Dropout 和多重加性回归树的方法。它在每次迭代过程中随机选择一部分树进行更新,会较大程度增加模型随机性,可以用于存在较多噪声的数据集或者数据集相对简单(需要减少过拟合风险)的场景中;GOSS 是一种基于梯度的单侧采样方法。它在每次迭代中只使用具有较大梯度的样本进行训练,从而降低计算复杂度。goss(Gradient-based One-Side Sampling)则是前文介绍的梯度的单边采样算法,可以在保持较高精度的同时加速训练过程,适用于大规模数据集,可以在保持较高精度的同时加速训练过程,有些时候精度不如GBDT;而rf则是采用随机森林来进行“Boosting过程”,或者说此时就不再是Boosting,而是替换成了Bagging过程,类似于XGBRFClassifier的计算过程,此时LGBM本质上将按照RF的计算范式进行计算。
然后与之相关的是subsample_for_bin参数:
- subsample_for_bin:该参数表示对连续变量进行分箱时(直方图优化过程)抽取样本的个数,默认取值为200000,当实际抽样个数大于输入训练数据样本数量时,会带入全部样本进行计算。而如果boosting_type选择的是goss,则在直方图优化时会自动完成抽样,具体抽样策略是:会保留所有较小梯度的样本(即那些已经被模型很好拟合的样本),并对较大梯度的样本进行采样。这种策略能够在加速训练(大梯度样本的贡献)的同时有效防止过拟合(小梯度样本的贡献)。因此,如果boosting_type选择的是 “goss”,。则subsample_for_bin参数会失去作用,此时无论subsample_for_bin取值多少都不影响最终结果。
如果需要控制goss过程,则需要借助top_rate 和 other_rate 这两个参数,但是这两个参数只存在于LGBM原生API中,在sklearn中并没有,因此在使用 LightGBM 的 sklearn API 时,GOSS 采样方法会自动进行调整。关于这两个参数的解释和使用,我们将在介绍LGBM原生API时讲解。
其他参数和GBDT及XGB类似,具体解释如下:
Name | Description |
---|---|
learning_rate | 学习率,即每次迭代中梯度提升的步长,默认值为 0.1 |
n_estimators | 迭代次数,即生成的基学习器的数量,默认值为 100 |
reg_alpha | L1 正则化系数,默认值为 0 |
reg_lambda | L2 正则化系数。默认值为 0 |
2.4 LGBMClassifier的特征和数据处理类超参数
LGBM中特征和数据处理类超参数主要用于每次迭代时数据和特征的分配,核心作用是控制模型训练过程的随机性,其超参数的基本解释如下:
Name | Description |
---|---|
subsample | 模型训练时抽取的样本数量,取值范围为 (0, 1],表示抽样比例,默认为1.0 |
subsample_freq | 抽样频率,表示每隔几轮进行一次抽样,默认取值为0,表示不进行随机抽样 |
colsample_bytree | 在每次迭代(树的构建)时,随机选择特征的比例,取值范围为 (0, 1],默认为1.0 |
这里有以下几点需要注意:
-
subsample和subsample_for_bin之间的关系
这两个参数尽管从字面理解都是抽样比例,但实际上这两个参数是完全独立的,彼此之间并不影响。其中subsample_for_bin抽样结果用于直方图构建,而subsample抽样结果则是用于模型训练,这两个抽样过程彼此独立,互不影响; -
subsample和subsample_freq之间的关系
更加关键的是subsample_freq参数,如果subsample_freq=0,则无论subsample取值为多少,模型训练时都不会进行随机抽样;换而言之,只有subsample_freq不等于0,且subsample不等于1.0时,才会进行抽样; -
subsample_freq和colsample_bytree之间的关系
不同于subsample是样本抽样,colsample_bytree是每次迭代(每次构建一颗树时)进行的特征抽样,并且colsample_bytree不受subsample_freq影响,即无论subsample_freq取值为多少,每次建树时都会根据colsample_bytree设置的比例进行列抽样。 -
LGBM和RF的不同特征抽样(分配)规则
同时需要注意的是,LGBM和随机森林不同,随机森林是每棵树的每次分裂时都随机分配特征,而LGBM是每次构建一颗树时随机分配一个特征子集,这颗树在成长过程中每次分裂都是依据这个特征子集进行生长。
2.5 LGBMClassifier的其他超参数
最后则是一些用于辅助建模的超参数,具体超参数及解释如下:
Name | Description |
---|---|
objective | 指定目标函数,默认为None,会自动判断是二分类还是多分类问题,这里我们也可以手动设置 ‘binary’(用于二分类问题)或’multiclass’(用于多分类问题) |
class_weight | 样本权重设置参数 |
importance_type | 特征重要性计算方式,默认为 ‘split’,表示使用特征在模型中被选中作为分裂特征的次数,可选 ‘gain’,表示使用特征在模型中的分裂收益之和作为重要性评估指标 |
random_state | 随机数种子 |
n_jobs | 并行的线程数,默认为-1,调用全部可用线程 |
silent | 是否沉默(不输出日志),默认为’warn’,仅显示警告和报错,可选’info’,用于打印全部信息 |
首先是关于目标函数的设置,对于LGBM的sklearn API来说,objective参数较为简单,只有’binary’和’multiclass’两种,其中’binary’表示逻辑回归损失,也就是二分类交叉熵损失,而’multiclass’则代表多分类交叉熵损失。
当然,LGBM也支持softmax损失,只不过无法通过objective传入。softmax损失默认是只有原生API才支持调用,若需要传入sklearn API中,则需要借助**kwargs参数,以原生API形式进行传输。原生API的调用方法我们将在下一小节进行探讨。
此外,需要注意用于计算特征重要性的importance_type参数,这也是LGBM算法的特点之一——即提供了两种不同的用于评估特征重要性的方法。很多时候我们在特征工程阶段都会创建海量特征来增强数据表现,并且通过一些数值指标或者模型来进行特征筛选,进而兼顾建模效率和预测效果。考虑到LGBM同时拥有非常高的计算效率,这使得LGBM算法成为筛选特征的最常用的模型之一。
具体特征衍生方法,我们将在特征工程阶段进行详细介绍。
至此,我们就完整解释了LGBMClassifier的全部超参数。接下来我们继续讨论LGBMRegressor超参数。LGBMRegressor和LGBMClassifier只有两点不同,其一是LGBMRegressor没有class_weight参数,其二则是LGBMRegressor的损失函数和LGBMClassifier完全不同。接下来我们就LGBMRegressor的损失函数选取进行解释。
2.6 LGBMRegressor损失函数
1 | from lightgbm import LGBMRegressor |
1 | LGBMRegressor? |
LGBMRegressor的损失函数包含了GBDT和XGB的各类回归类损失函数,相关计算过程及应用场景此前都有详细讨论,这里只进行简要说明:
- 均方误差(MSE, Mean Squared Error):最常用的的损失函数,此时objective=‘regression’ 或 objective=‘regression_l2’;
- 平均绝对误差(MAE, Mean Absolute Error):通常用于标签存在异常值情况,此时objective=‘regression_l1’;
- Huber损失(Huber Loss):适用于目标值存在大量异常值或者噪声时。Huber损失在预测误差较小时表现为均方误差,在预测误差较大时表现为平均绝对误差,这使得它对异常值具有更好的鲁棒性。此时objective=‘quantile’;
- Quantile损失(Quantile Loss):用于分位数回归,最小化预测值与真实值之间的分位数损失,适用于需要对预测分布进行精细控制的场景(例如围绕某种分布进行预测)。此时objective=‘quantile’;
- Poisson损失(Poisson Loss): 适用于计数问题,即目标值是非负整数且服从泊松分布。此时objective=‘poisson’
- Gamma损失(Gamma Loss):适用于预测非负实数且服从伽马分布的目标值。此时objective=‘gamma’
- Tweedie损失(Tweedie Loss):适用于广义线性模型(Generalized Linear Models, GLMs)中的 Tweedie 分布(非对称分布)的数据集。此时objective=‘tweedie’。
能够发现,大多数损失函数都是针对标签存在某个具体分布时进行的预测,一般情况下我们都是在均方误差(MSE)、平均绝对误差(MAE)和Huber损失中进行选择,通常情况首选MSE,而当标签存在噪声或者异常点时,MAE会表现出更好的泛化能力。并且由于MAE较为特殊的计算过程,导致其在正常情况数据集下精度不如MSE。而Huber则是二者的综合,适用于标签存在少量异常值的数据集,Huber对异常值较为鲁棒,同时又可以保留较好的精度。
2.LightGBM sklearn API进阶使用方法
接下来,我们进一步尝试进行更复杂的LGBM API的调用,以满足更加复杂的建模过程。这里我们仍然是分sklearn API和原生API两种调用方式进行尝试。
首先是sklearn API进阶调用方法。在实际建模过程中,如果需要进一步借助sklearn功能模块进行建模,例如需要进行网格搜索超参数优化、构建机器学习流或者和sklearn其他评估器进行模型融合等,则可以调用LGBM的sklearn API进行快速执行。当然,大多数sklearn的相关功能都在此前的课程中有所尝试,这里我们对此快速进行回顾。
2.1 交叉验证
首先是交叉验证,通过调用LGBM的sklearn API,我们可以将LGBM作为评估器输入到交叉验证相关函数中进行快速计算:
1 | from sklearn.model_selection import cross_val_score |
1 | cross_val_score? |
1 | cross_val_score(LGBMClassifier(), X_train, y_train) |
array([0.83333333, 1. , 1. , 1. , 0.875 ])
2.2 网格搜索
接着,我们进一步尝试借助网格搜索对LGBM评估器进行超参数优化。当然此时我们还未详细解读LGBM的超参数含义,这里我们先以测试相关功能为主,关于LGBM超参数的解读会在介绍完算法原理后进行探讨。这里我们简单设置超参数搜索空间为’n_estimators’: [90, 100, 110]进行网格搜索测试,LGBM和其他GBDT框架下的集成学习一样,n_estimators都代表迭代次数或者基础学习器个数。
1 | gbm = LGBMClassifier() |
1 | LGBMClassifier? |
1 | param_grid = {'n_estimators': [90, 100, 110]} |
1 | LGBM_search = GridSearchCV(estimator=gbm, param_grid=param_grid, n_jobs=10) |
1 | LGBM_search.fit(X_train, y_train) |
GridSearchCV(estimator=LGBMClassifier(), n_jobs=10,
param_grid={'n_estimators': [90, 100, 110]})
1 | LGBM_search.best_score_ |
0.9416666666666668
1 | LGBM_search.best_params_ |
{'n_estimators': 90}
2.3 构建Pipeline
然后我们尝试借助LGBM的sklearn API构建Pipeline。Pipeline也是sklearn特有的一项功能,通过Pipeline的构建,我们可以将数据清洗、特征衍生和机器学习封装成一个评估器,进而进行快速的数据处理和预测,甚至我们还可以围绕这个pipeline进行超参数优化,进而达到自动数据清洗、自动机器学习算法超参数优化等目的。
这里我们尝试将多项式特征衍生、标准化和LGBM三个评估器封装为一个pipeline,在后续预测时,数据会自动按照二阶多项式衍生和Z-Score标准化的流程先进行处理,然后再带入LGBM模型中进行预测:
1 | LGBM_pipe = make_pipeline(PolynomialFeatures(), |
1 | PolynomialFeatures? |
然后以Pipeline作为完整的评估器,围绕数据集进行数据处理和模型训练:
1 | LGBM_pipe.fit(X_train, y_train) |
Pipeline(steps=[('polynomialfeatures', PolynomialFeatures()),
('standardscaler', StandardScaler()),
('lgbmclassifier', LGBMClassifier())])
最终输出预测结果:
1 | LGBM_pipe.score(X_test, y_test) |
0.9666666666666667
2.4 Pipeline超参数优化与自动机器学习
最后,我们尝试围绕上述Pipeline进行超参数优化。在Lesson 6中我们曾介绍,对于一个Pipeline来说,其中的每个评估器中的每个超参数,都可以放在一个超参数空间中进行搜索和优化,因此这里我们可以通过网格搜索的方法,自动搜索出(某个小范围内)最佳多项式特征衍生的阶数和LGBM的最佳基础分类器个数:
1 | LGBM_pipe.get_params() |
1 | param_pipe = {'polynomialfeatures__degree': [2, 3, 4], |
1 | LGBM_pipe_search = GridSearchCV(estimator=LGBM_pipe, param_grid=param_pipe, n_jobs=10) |
1 | LGBM_pipe_search.fit(X_train, y_train) |
GridSearchCV(estimator=Pipeline(steps=[('polynomialfeatures',
PolynomialFeatures()),
('standardscaler', StandardScaler()),
('lgbmclassifier', LGBMClassifier())]),
n_jobs=10,
param_grid={'lgbmclassifier__n_estimators': [90, 100, 110],
'polynomialfeatures__degree': [2, 3, 4]})
1 | LGBM_pipe_search.best_params_ |
{'lgbmclassifier__n_estimators': 90, 'polynomialfeatures__degree': 3}
1 | LGBM_pipe_search.score(X_test, y_test) |
0.9666666666666667
不难看出,此过程能够一步到位实现自动数据清洗和自动模型超参数优化。不过上述流程目前为止还是过于简单,在本课程最后的案例阶段,我们会有对此更进一步探讨。
此外,通过调用sklearn API,我们还能够对LGBM评估器进行诸如模型本地保存、构造模型融合评估器等,这些内容我们也将在后续部分内容中逐步进行介绍。
- LGBM各模型的sklearn API简介
当然,除了分类模型外,LGBM的sklearn API还包括回归模型和排序模型两种,分别可以通过如下方式进行调用:
1 | # LGBM回归模型的sklearn API |
1 | LGBMRegressor? |
1 | # LGBM排序模型的sklearn API |
1 | LGBMRanker? |
其中排序模型更多的应用于时间序列和推荐系统等领域。相关API说明可以参考LGBM官方API说明文档,各API的具体调用方法和超参数说明我们会在实践环节具体讨论。