LightGBM参数调优代码详解

1.总体调参思路

对于基于决策树的模型,调参的方法都是大同小异。一般都需要如下步骤:

  1. 首先选择较高的学习率,大概0.1附近,这样是为了加快收敛的速度。这对于调参是很有必要的。
  2. 对决策树基本参数调参
  3. 正则化参数调参
  4. 最后降低学习率,这里是为了最后提高准确率

现将数据集为一个(4400+, 1000+)的数据集,全是数值特征,由于该问题是一个回归问题,故metric采用均方根误差。

2. 学习率和估计器及数目

通常先把学习率先定一个较高的值,取 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     ###   根据问题来定咯,由于我的数据集不是很大,所以选择了一个适中的值,其实4-10都无所谓。
'num_leaves': 50  ###   由于lightGBM是leaves_wise生长,官方说法是要小于2^max_depth
'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。但是还是建议,在硬件条件允许的条件下,学习率还是越小越好。

2. 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
### 我们可以创建lgb的sklearn模型,使用上面选择的(学习率,评估器数目)
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)
gsearch1.best_params_, gsearch1.best_score_

{‘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的负数,所以就均方差来说,也就变成负数越大越好了。

所以,可以看到,最优解的分数为-1.860,转化为均方差为np.sqrt(-(-1.860)) = 1.3639,明显比step1的分数要好很多。

至此,我们将我们这步得到的最优解代入第三步。其实,我这里只进行了粗调,如果要得到更好的效果,可以将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)
gsearch2.best_params_, gsearch2.best_score_

{‘max_depth’: 7, ‘num_leaves’: 68},
-1.8602436718814157)

3. 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)
gsearch3.best_params_, gsearch3.best_score_

{‘min_child_samples’: 20, ‘min_child_weight’: 0.001},
-1.8602436718814157)

这是我经过粗调后细调的结果,可以看到,min_data_in_leaf的最优值为20,而min_sum_hessian_in_leaf对最后的值几乎没有影响。且这里调参之后,最后的值没有进行优化,说明之前的默认值即为20,0.001。

4. 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)
gsearch4.best_params_, gsearch4.best_score_

{‘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)
gsearch5.best_params_, gsearch5.best_score_

{‘feature_fraction’: 0.7},
-1.8541224387666373
好吧,feature_fraction就是0.7了

5. 正则化参数

正则化参数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.b1, 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)
gsearch6.best_params_, gsearch6.best_score_

{‘reg_alpha’: 0, ‘reg_lambda’: 0},
-1.8541224387666373
哈哈,看来我多此一举了。

6. 降低learning_rate

之前使用较高的学习速率是因为可以让收敛更快,但是准确度肯定没有细水长流来的好。最后,我们使用较低的学习速率,以及使用更多的决策树n_estimators来训练数据,看能不能可以进一步的优化分数。

我们可以用回lightGBM的cv函数了 ,我们代入之前优化好的参数。

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])

这就是一个大概过程吧。
参考
https://www.cnblogs.com/bjwu/p/9307344.html
https://www.jianshu.com/p/b4ac0596e5ef
http://lightgbm.apachecn.org/#/docs/6
https://blog.csdn.net/u012735708/article/details/83749703

  • 39
    点赞
  • 249
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Python lightgbm参数可以在官方文档中找到。具体来说,可以查看LightGBM的Python API文档,其中包含了详细的参数说明和用法。另外,还可以参考LightGBM的文档和一些技术博客来获取更多关于参数的信息。 在Python中,可以使用lightgbm库提供的相关类来创建和训练LightGBM模型。例如,使用lightgbm.sklearn.LGBMClassifier()类可以创建一个LightGBM分类器模型。 需要注意的是,LightGBM的底层实现是一致的,无论是使用Python还是其他语言,都可以使用import lightgbm as lgb来导入相关库。 因此,如果你想了解Python lightgbm参数,请参考官方文档和其他参考资料,以便获得更详细和全面的信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Lightgbm原理、参数详解及python实例](https://blog.csdn.net/qq_24591139/article/details/100085359)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [lightgbm的使用和参数说明](https://blog.csdn.net/qq_37774098/article/details/120076102)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值