调参方法:
对于基于决策树的模型,调参的方法都是大同小异。一般都需要如下步骤:
1、首先选择较高的学习率,大概0.1附近,这样是为了加快收敛的速度。这对于调参是很有必要的。
2、对决策树基本参数调参
3、正则化参数调参
4、最后降低学习率,这里是为了最后提高准确率
所以,下面的调参例子是基于上述步骤来操作。数据集为一个(4400+, 1000+)的数据集,全是数值特征,metric采用均方根误差。
(同义的参数用/划开,方便查看)
Step1. 学习率learning_rate和估计器boosting/boot/booting_type及其数目
不管怎么样,我们先把学习率先定一个较高的值,这里取 learning_rate = 0.1,其次确定估计器boosting/boost/boosting_type的类型,不过默认都会选gbdt。
为了确定估计器的数目(boosting迭代的次数),也可以说是残差树的数目,参数名为n_estimators/num_iterations/num_round/num_boost_round。我们可以先将该参数设成一个较大的数,然后在cv结果中查看最优的迭代次数,具体如代码。
在这之前,我们必须给其他重要的参数一个初始值。初始值的意义不大,只是为了方便确定其他参数。下面先给定一下初始值,以下参数根据具体项目要求定:
'boosting_type'/'boosting': 'gbdt'
'objective': 'regression'
'metric': 'rmse'
'max_depth': 6
'num_leaves': 50
'subsample'/'bagging_fraction':0.8
'colsample_bytree'/'feature_fraction': 0.8
特征采样
用LightGBM的cv函数进行演示:
params = {
'boosting_type': 'gbdt',
'objective': 'regression',
'learning_rate': 0.1,
'num_leaves': 50,
'max_depth': 6,
'subsample': 0.8,
'colsample_bytree': 0.8,
data_train = lgb.Dataset(df_train, y_train, silent=True)
cv_results = lgb.cv(
params,
data_train,
num_boost_round=1000,
nfold=5,
stratified=False,
shuffle=True,
metrics='rmse',
early_stopping_rounds=50,
verbose_eval=50,
show_stdv=True,
seed=0)
print('best n_estimators:', len(cv_results['rmse-mean']))
print('best cv score:', cv_results['rmse-mean'][-1])
best n_estimators: 43
best cv score: 1.3838664241
由于我的数据集不是很大,所以在学习率为0.1时,最优的迭代次数只有43。那么现在,我们就代入(0.1, 43)进入其他参数的tuning。但是还是建议,在硬件条件允许的条件下,学习率还是越小越好。
params 基学习器的参数
train_set 训练集
nfold n折交叉验证
metrics 评价标准。
num_boost_round 最大迭代次数。
early_stopping_rounds 早停轮数。
verbose_eval 每间隔n个迭代就显示一次进度
stratified 默认True,是否采用分层抽样,建议采用。
shuffle 默认True,是否洗牌,不建议采用。
seed 相当于random_state
param需要填写的参数
objective 树的类型。回归:regression;二分类:binary;多分类:multiclass;排序等。
boosting 有gbdt,rf,dart。
n_jobs
learning_rate
num_leaves
max_depth
subsample
colsample_bytree
返回值是一个字典,一般用到的方法有:
len(cv_results[‘rmse-mean’]) 确定基学习器的数量。
cv_results[‘rmse-mean’][-1] 确定最后得分
其中rmse由参数metric决定
Step2. max_depth 和 num_leaves
这是提高精确度的最重要的参数。
max_depth :设置树深度,深度越大可能过拟合
num_leaves:因为 LightGBM 使用的是 leaf-wise 的算法,因此在调节树的复杂程度时,使用的是 num_leaves 而不是 max_depth。大致换算关系:num_leaves = 2^(max_depth),但是它的值的设置应该小于 2^(max_depth),否则可能会导致过拟合。
我们也可以同时调节这两个参数,对于这两个参数调优,我们先粗调,再细调:
这里我们引入sklearn里的GridSearchCV()函数进行搜索。这个函数特别耗内存,特别耗时间,特别耗精力:
from sklearn.model_selection import GridSearchCV
model_lgb = lgb.LGBMRegressor(objective='regression',num_leaves=50,
learning_rate=0.1, n_estimators=43, max_depth=6,
metric='rmse', bagging_fraction = 0.8,
feature_fraction = 0.8)
params_test1={
'max_depth': range(3,8,2),
'num_leaves':range(50, 170, 30)
}
gsearch1 = GridSearchCV(estimator=model_lgb,
param_grid=params_test1,
scoring='neg_mean_squared_error',
cv=5,
verbose=1,
n_jobs=4)
gsearch1.fit(df_train, y_train)
print(gsearch1.grid_scores_,
gsearch1.best_params_,
gsearch1.best_score_)
输出结果:
Fitting 5 folds for each of 12 candidates, totalling 60 fits
[Parallel(n_jobs=4)]: Done 42 tasks | elapsed: 2.0min
[Parallel(n_jobs=4)]: Done 60 out of 60 | elapsed: 3.1min finished
[mean: -1.88629, std: 0.13750, params: {'max_depth': 3, 'num_leaves': 50},
mean: -1.88629, std: 0.13750, params: {'max_depth': 3, 'num_leaves': 80},
......
mean: -1.86024, std: 0.11364, params: {'max_depth': 7, 'num_leaves': 140}],
{'max_depth': 7, 'num_leaves': 80},
-1.8602436718814157
运行了12个参数组合,得到的最优解是在max_depth为7,num_leaves为80的情况下,分数为-1.860
sklearn模型评估里的scoring参数都是采用的higher return values are better than lower return values(较高的返回值优于较低的返回值)。但是,我采用的metric策略采用的是均方误差(rmse),越低越好,所以sklearn就提供了neg_mean_squared_erro参数,也就是返回metric的负数,所以就均方差来说,也就变成负数越大越好了。
至此,我们将我们这步得到的最优解代入第三步。其实,我这里只进行了粗调,如果要得到更好的效果,可以将max_depth在7附近多取几个值,num_leaves在80附近多取几个值。千万不要怕麻烦,虽然这确实很麻烦。
params_test2={
'max_depth':[6,7,8],
'num_leaves':[68,74,80,86,92]
gsearch2 = GridSearchCV(estimator=model_lgb,
param_grid=params_test2,
scoring='neg_mean_squared_error',
cv=5, verbose=1, n_jobs=4)
gsearch2.fit(df_train, y_train)
print(gsearch2.grid_scores_,
gsearch2.best_params_,
gsearch2.best_score_)
Fitting 5 folds for each of 15 candidates, totalling 75 fits
[Parallel(n_jobs=4)]: Done 42 tasks | elapsed: 2.8min
[Parallel(n_jobs=4)]: Done 75 out of 75 | elapsed: 5.1min finished
[mean: -1.87506, std: 0.11369, params: {'max_depth': 6, 'num_leaves': 68},
mean: -1.87506, std: 0.11369, params: {'max_depth': 6, 'num_leaves': 74},
......
mean: -1.86733, std: 0.12159, params: {'max_depth': 8, 'num_leaves': 86},
mean: -1.86665, std: 0.12174, params: {'max_depth': 8, 'num_leaves': 92}],
{'max_depth': 7, 'num_leaves': 68},
-1.8602436718814157
可见最大深度7是没问题的,但是看细节的话,发现在最大深度为7的情况下,叶结点的数量对分数并没有影响。
Step3: min_data_in_leaf 和 min_sum_hessian_in_leaf
说到这里,就该降低过拟合了。
min_data_in_leaf 是一个很重要的参数, 也叫min_child_samples,它的值取决于训练数据的样本个数和num_leaves. 将其设置的较大可以避免生成一个过深的树, 但有可能导致欠拟合。
min_sum_hessian_in_leaf:也叫min_child_weight,使一个结点分裂的最小海森值之和(Minimum sum of hessians in one leaf to allow a split. Higher values potentially decrease overfitting)
我们采用跟上面相同的方法进行:
params_test3={
'min_child_samples': [18, 19, 20, 21, 22],
'min_child_weight':[0.001, 0.002]
model_lgb = lgb.LGBMRegressor(objective='regression',num_leaves=80,
learning_rate=0.1, n_estimators=43, max_depth=7,
metric='rmse', bagging_fraction = 0.8, feature_fraction = 0.8)
gsearch3 = GridSearchCV(estimator=model_lgb,
param_grid=params_test3,
scoring='neg_mean_squared_error',
cv=5, verbose=1, n_jobs=4)
gsearch3.fit(df_train, y_train)
print(gsearch3.grid_scores_,
gsearch3.best_params_,
gsearch3.best_score_)
输出结果:
Fitting 5 folds for each of 10 candidates, totalling 50 fits
[Parallel(n_jobs=4)]: Done 42 tasks | elapsed: 2.9min
[Parallel(n_jobs=4)]: Done 50 out of 50 | elapsed: 3.3min finished
[mean: -1.88057, std: 0.13948, params: {'min_child_samples': 18, 'min_child_weight': 0.001},
mean: -1.88057, std: 0.13948, params: {'min_child_samples': 18, 'min_child_weight': 0.002},
......
mean: -1.86750, std: 0.13898, params: {'min_child_samples': 22, 'min_child_weight': 0.001},
mean: -1.86750, std: 0.13898, params: {'min_child_samples': 22, 'min_child_weight': 0.002}],
{'min_child_samples': 20, 'min_child_weight': 0.001},
-1.8602436718814157
这是我经过粗调后细调的结果,可以看到,min_data_in_leaf的最优值为20,而min_sum_hessian_in_leaf对最后的值几乎没有影响。且这里调参之后,最后的值没有进行优化,说明之前的默认值即为20,0.001。
Step4: feature_fraction 和 bagging_fraction
这两个参数都是为了降低过拟合的。
feature_fraction参数来进行特征的子抽样。这个参数可以用来防止过拟合及提高训练速度。
bagging_fraction+bagging_freq参数必须同时设置,bagging_fraction相当于subsample样本采样,可以使bagging更快的运行,同时也可以降拟合。bagging_freq默认0,表示bagging的频率,0意味着没有使用bagging,k意味着每k轮迭代进行一次bagging。
不同的参数,同样的方法。
params_test4={
'feature_fraction': [0.5, 0.6, 0.7, 0.8, 0.9],
'bagging_fraction': [0.6, 0.7, 0.8, 0.9, 1.0]
model_lgb = lgb.LGBMRegressor(objective='regression',
num_leaves=80,
learning_rate=0.1,
n_estimators=43,
max_depth=7,
metric='rmse',
bagging_freq = 5,
min_child_samples=20)
gsearch4 = GridSearchCV(estimator=model_lgb,
param_grid=params_test4,
scoring='neg_mean_squared_error',
cv=5, verbose=1, n_jobs=4)
gsearch4.fit(df_train, y_train)
print(gsearch4.grid_scores_, gsearch4.best_params_, gsearch4.best_score_)
输出结果:
Fitting 5 folds for each of 25 candidates, totalling 125 fits
[Parallel(n_jobs=4)]: Done 42 tasks | elapsed: 2.6min
[Parallel(n_jobs=4)]: Done 125 out of 125 | elapsed: 7.1min finished
([mean: -1.90447, std: 0.15841, params: {'bagging_fraction': 0.6, 'feature_fraction': 0.5},
mean: -1.90846, std: 0.13925, params: {'bagging_fraction': 0.6, 'feature_fraction': 0.6},
......
mean: -1.87266, std: 0.12271, params: {'bagging_fraction': 1.0, 'feature_fraction': 0.9}],
{'bagging_fraction': 1.0, 'feature_fraction': 0.7},
-1.8541224387666373
从这里可以看出来,bagging_feaction和feature_fraction的理想值分别是1.0和0.7,一个很重要原因就是,我的样本数量比较小(4000+),但是特征数量很多(1000+)。所以,这里我们取更小的步长,对feature_fraction进行更细致的取值。
params_test5={
'feature_fraction': [0.62, 0.65, 0.68, 0.7, 0.72, 0.75, 0.78 ]
model_lgb = lgb.LGBMRegressor(objective='regression',
num_leaves=80,
learning_rate=0.1,
n_estimators=43,
max_depth=7,
metric='rmse',
min_child_samples=20)
gsearch5 = GridSearchCV(estimator=model_lgb,
param_grid=params_test5,
scoring='neg_mean_squared_error',
cv=5, verbose=1, n_jobs=4)
gsearch5.fit(df_train, y_train)
print(gsearch5.grid_scores_, gsearch5.best_params_, gsearch5.best_score_)
输出结果:
Fitting 5 folds for each of 7 candidates, totalling 35 fits
[Parallel(n_jobs=4)]: Done 35 out of 35 | elapsed: 2.3min finished
([mean: -1.86696, std: 0.12658, params: {'feature_fraction': 0.62},
mean: -1.88337, std: 0.13215, params: {'feature_fraction': 0.65},
mean: -1.87282, std: 0.13193, params: {'feature_fraction': 0.68},
mean: -1.85412, std: 0.12698, params: {'feature_fraction': 0.7},
mean: -1.88235, std: 0.12682, params: {'feature_fraction': 0.72},
mean: -1.86329, std: 0.12757, params: {'feature_fraction': 0.75},
mean: -1.87943, std: 0.12107, params: {'feature_fraction': 0.78}],
{'feature_fraction': 0.7},
-1.8541224387666373)
feature_fraction就是0.7了。
Step5: 正则化参数
正则化参数lambda_l1(reg_alpha), lambda_l2(reg_lambda),毫无疑问,是降低过拟合的,两者分别对应l1正则化和l2正则化。我们也来尝试一下使用这两个参数。
params_test6={
'reg_alpha': [0, 0.001, 0.01, 0.03, 0.08, 0.3, 0.5],
'reg_lambda': [0, 0.001, 0.01, 0.03, 0.08, 0.3, 0.5]
model_lgb = lgb.LGBMRegressor(objective='regression',
num_leaves=80,
learning_rate=0.1,
n_estimators=43,
max_depth=7,
metric='rmse',
min_child_samples=20,
feature_fraction=0.7)
gsearch6 = GridSearchCV(estimator=model_lgb,
param_grid=params_test6,
scoring='neg_mean_squared_error',
cv=5, verbose=1, n_jobs=4)
gsearch6.fit(df_train, y_train)
print(gsearch6.grid_scores_, gsearch6.best_params_, gsearch6.best_score_)
输出结果:
Fitting 5 folds for each of 49 candidates, totalling 245 fits
[Parallel(n_jobs=4)]: Done 42 tasks | elapsed: 2.8min
[Parallel(n_jobs=4)]: Done 192 tasks | elapsed: 10.6min
[Parallel(n_jobs=4)]: Done 245 out of 245 | elapsed: 13.3min finished
([mean: -1.85412, std: 0.12698, params: {'reg_alpha': 0, 'reg_lambda': 0},
mean: -1.88148, std: 0.12622, params: {'reg_alpha': 0.5, 'reg_lambda': 0.5}],
{'reg_alpha': 0, 'reg_lambda': 0},
-1.8541224387666373)
step6: 降低learning_rate
之前使用较高的学习速率是因为可以让收敛更快,但是准确度肯定没有细水长流来的好。最后,我们使用较低的学习速率,以及使用更多的决策树n_estimators来训练数据,代入之前优化好的参数。
params = {
'boosting_type': 'gbdt',
'objective': 'regression',
'learning_rate': 0.005,
'num_leaves': 80,
'max_depth': 7,
'min_data_in_leaf': 20,
'subsample': 1,
'colsample_bytree': 0.7,
data_train = lgb.Dataset(df_train, y_train, silent=True)
cv_results = lgb.cv(params, data_train,
num_boost_round=10000,
nfold=5,
stratified=False,
shuffle=True,
metrics='rmse',
early_stopping_rounds=50,
verbose_eval=100,
show_stdv=True)
print('best n_estimators:', len(cv_results['rmse-mean']))
print('best cv score:', cv_results['rmse-mean'][-1])
lightGBM其他的参数优化方法按照以上方式进行优化即可。
lightgbm是xgboost的加强升级版.LightGBM=XGBoost+Histogram+GOSS+EFB其中,Histogram算法是直方图算法,作用:减少后选分类点的算法GOSS是基于梯度的单边采样算法,作用减少样本数量EFB算法是互斥特征捆绑算法,作用是减少特征数量基于以上三个算法,LightGBM生产一片叶子需要的复杂度大大降低了,从而极大节约了计算时间。同时Histogram算法还将特征浮点数转换成0~255位的证书进行存储,从而集打节约了内存存储空间。代码举例:impor
LightGBM 原理与代码实战案例讲解
作者:禅与计算机程序设计艺术 / Zen and the Art of Computer Programming / TextGenWebUILLM
LightGBM 原理与代码实战案例讲解
万字总结LightGBM原理、核心参数以及调优思路(上篇)
LightGBM sklearn API应用代码LightGBM sklearn API超参数解释与使用方法LGBM的原生API调用和XGB的原生API调用过程非常类似,一个最简单的流程如下:LightGBM 涉及的DataSet API
LightGBM 涉及的Training API以及各类参数详解
lightGBM可以用来解决大多数表格数据问题的算法。有很多很棒的功能,并且在kaggle这种该数据比赛中会经常使用。
但我一直对了解哪些
参数对性能的影响最大以及我应该如何
调优lightGBM参数以最大限度地利用它很感兴趣。
我想我应该做一些研究,了解更多关于
lightGBM的
参数…并分享我的旅程。
我希望读完这篇文章后,你能回答以下问题:
LightGBM中实现了哪些梯度增强方法,它们有什么区别?
一般来说,哪些
参数是重要的?
哪些正则化
参数需要调整?
如何调整
lightGBM参数在
python?
参考:https://www.freesion.com/article/76441004344/#LightGBM__sklearn__329
https://blog.csdn.net/qq_39777550/article/details/109277937
LightGBM的优点
lightgbm是xgboost的加强升级版.
LightGBM=XGBoost+Histogram+GOSS+EFB
其中,Histogram算法是直方图算法,作用:减少后选分类点的算法
GOSS是基于梯度的单边采样算法
我已经使用
lightGBM有一段时间了。对于大多数扁平数据问题,这是我的首选算法。它有很多突出特性,我建议你浏览一下。
但我一直很想了解哪些
参数对性能的影响最大,以及我应该如何调整
lightGBM 参数以充分利用它。
我想我应该做一些研究,更多地了解
lightGBM 参数…并分享我的研究过程。
具体来说我做了以下事项:
深入研究
LightGBM 的文档
浏览 Laurae 文章Lauraepp:xgboost / L.
关于在使用tensorflow2.0版本时,出现RuntimeError:tf.placeholder() is not compatible with eager execution.的问题
26849