LightGMB的参数类型
- 核心参数
- 学习控制参数
- IO参数
- 目标函数参数
- 度量参数等
调参时不需要关注这么多参数,只需记住常用的一些参数。
从四个方向优化参数
1. 针对leaf-wise树的参数优化
num_leaves:控制了叶节点的数目。
它是控制树模型复杂度的主要参数。如果是level-wise,则该参数为 2^depth ,其中depth为树的深度。但是当叶子数量相同时,leaf-wise的树要远远深过level-wise树,非常容易导致过拟合。因此应该让num_leaves小于2^depth。在leaf-wise树中,并不存在depth的概念。因为不存在一个从leaves到depth的合理映射。min_data_in_leaf: 每个叶节点的最少样本数量。
它是处理leaf-wise树的过拟合的重要参数。将它设为较大的值,可以避免生成一个过深的树。但是也可能导致欠拟合。max_depth: 控制了树的最大深度。该参数可以显式的限制树的深度。
2. 针对更快的训练速度
- 通过设置 bagging_fraction 和 bagging_freq 参数来使用 bagging 方法
- 通过设置 feature_fraction 参数来使用特征的子抽样。
- 使用较小的 max_bin
- 使用 save_binary 在未来的学习过程对数据加载进行加速
3. 获得更好的准确率
- 使用较大的 max_bin(学习速度可能变慢)
- 使用较小的 learning_rate 和较大的 num_iterations
- 使用较大的 num_leaves (可能导致过拟合)
- 使用更大的训练数据
- 尝试DART
4. 缓解过拟合
- 使用较小的 max_bin, 分桶粗一些
- 使用较小的 num_leaves 不要在单棵树分的太细
- 使用 lambda_l1, lambda_l2 和 min_gain_to_split来使用正则
- 尝试 max_depth 来避免生成过深的树
- 使用 min_data_in_leaf 和 min_sum_hessian_in_leaf, 确保叶子节点有足够多的数据
LightGBM的调参过程和RF、GBDT等类似,其基本流程如下:
- 首先选择较高的学习率,大概0.1附近,这样是为了加快收敛的速度。这对于调参是很有必要的。
- 对决策树基本参数调参
- 正则化参数调参
- 最后降低学习率,这里是为了最后提高准确率
具体过程
Step1: 学习率和迭代次数
我们先把学习率先定一个较高的值,这里取 learning_rate = 0.1,其次确定估计器boosting/boost/boosting_type的类型,不过默认都会选gbdt。
Step2: 迭代的次数
也可以说是残差树的数目,参数名为n_estimators/num_iterations/num_round/num_boost_round。我们可以先将该参数设成一个较大的数,然后在cv结果中查看最优的迭代次数,具体如代码。
在这之前,我们必须给其他重要的参数一个初始值。初始值的意义不大,只是为了方便确定其他参数。下面先给定一下初始值:
主要参数:
'boosting_type'/'boosting': 'gbdt'
'objective': 'binary'
'metric': 'auc'
# 以下是选择的初始值
'max_depth': 5 # 由于数据集不是很大,所以选择了一个适中的值,其实4-10都无所谓。
'num_leaves': 30 # 由于lightGBM是leaves_wise生长,官方说法是要小于2^max_depth
'subsample'/'bagging_fraction':0.8 # 数据采样
'colsample_bytree'/'feature_fraction': 0.8 # 特征采样
调参过程
Step1:建立二分类lightGBM CV模型
此处以乳腺癌数据集作为示例。
%%time
# step1:基本参数,输出最优迭代
import pandas as pd
import lightgbm as lgb
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
canceData=load_breast_cancer()
X=canceData.data
y=canceData.target
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=2021,test_size=0.2)
data_train = lgb.Dataset(X_train, y_train)
# 基本参数设置
params = {
'boosting_type': 'gbdt',
'objective': 'binary',
'metric': 'auc',
'nthread':4,
'learning_rate':0.1,
'num_leaves':30,
'max_depth': 5,
'subsample': 0.8,
'colsample_bytree': 0.8,
}
cv_results = lgb.cv(params, data_train, num_boost_round=1000, nfold=5, stratified=False, shuffle=True, metrics='auc',early_stopping_rounds=50,seed=0)
print('best n_estimators:', len(cv_results['auc-mean']))
print('best cv score:', pd.Series(cv_results['auc-mean']).max())
根据输出结果得到最优迭代 n_estimators。
Step2: 更新n_estimators的值,确定max_depth和num_leaves
这是提高精确度的最重要的参数。这里我们引入sklearn里的GridSearchCV()函数进行搜索。
%%time
# update n_estimators,search max_depth and num_leaves
from sklearn.model_selection import GridSearchCV
params_test1={'max_depth': range(3,8,1),
'num_leaves':range(5, 100, 5)}
estimator = lgb.LGBMClassifier(boosting_type='gbdt',
objective='binary',
metrics='auc',
learning_rate=0.1,
n_estimators=137,
max_depth=6,
bagging_fraction = 0.8,
feature_fraction = 0.8)
gsearch1 = GridSearchCV(estimator, param_grid = params_test1, scoring='roc_auc',cv=5,n_jobs=-1)
gsearch1.fit(X_train,y_train)
print(gsearch1.best_params_)
gsearch1.best_params_得到最优的max_depth和num_leaves。
Step3: 确定min_data_in_leaf和max_bin
%%time
# step3:update max_depth and num_leaves,search max_bin and min_data_in_leaf
params_test2={'max_bin': range(5,256,10), 'min_data_in_leaf':range(1,102,10)}
estimator = lgb.LGBMClassifier(boosting_type='gbdt',
objective='binary',
metrics='auc',
learning_rate=0.1,
n_estimators=137,
max_depth=4,
num_leaves=10,
bagging_fraction = 0.8,
feature_fraction = 0.8)
gsearch2 = GridSearchCV(estimator,param_grid = params_test2, scoring='roc_auc',cv=5,n_jobs=-1)
gsearch2.fit(X_train,y_train)
print(gsearch2.best_params_)
gsearch2.best_params_得到最优的max_bin和min_data_in_leaf。
Step4: 确定feature_fraction、bagging_fraction、bagging_freq
%%time
# step4:update max_bin and min_data_in_leaf,search feature_fraction,bagging_fraction,bagging_freq
params_test3={'feature_fraction': [0.6,0.7,0.8,0.9,1.0],
'bagging_fraction': [0.6,0.7,0.8,0.9,1.0],
'bagging_freq': range(0,81,10)
}
estimator = lgb.LGBMClassifier(boosting_type='gbdt',
objective='binary',
metrics='auc',
learning_rate=0.1,
n_estimators=137,
max_depth=4,
num_leaves=10,
max_bin=35,
min_data_in_leaf=41)
gsearch3 = GridSearchCV(estimator,param_grid = params_test3, scoring='roc_auc',cv=5,n_jobs=-1)
gsearch3.fit(X_train,y_train)
print(gsearch3.best_params_)
Step5: 确定lambda_l1和lambda_l2
%%time
# step5:update feature_fraction,bagging_fraction,bagging_freq, search lambda_l1 and lambda_l2
params_test4={'lambda_l1': [1e-5,1e-3,1e-1,0.0,0.1,0.3,0.5,0.7,0.9,1.0],
'lambda_l2': [1e-5,1e-3,1e-1,0.0,0.1,0.3,0.5,0.7,0.9,1.0]
}
estimator = lgb.LGBMClassifier(boosting_type='gbdt',
objective='binary',
metrics='auc',
learning_rate=0.1,
n_estimators=137,
max_depth=4,
num_leaves=10,
max_bin=35,
min_data_in_leaf=41,
bagging_fraction=0.6,
bagging_freq= 0,
feature_fraction= 0.8)
gsearch4 = GridSearchCV(estimator,param_grid = params_test4, scoring='roc_auc',cv=5,n_jobs=-1)
gsearch4.fit(X_train,y_train)
print(gsearch4.best_params_)
Step6:确定 min_split_gain
%%time
# step6:update lambda_l1 and lambda_l2,search min_split_gain
params_test5={'min_split_gain':[0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]}
estimator = lgb.LGBMClassifier(boosting_type='gbdt',
objective='binary',
metrics='auc',
learning_rate=0.1,
n_estimators=137,
max_depth=4,
num_leaves=10,
max_bin=35,
min_data_in_leaf=41,
bagging_fraction=0.6,
bagging_freq= 0,
feature_fraction= 0.8,
lambda_l1=0,
lambda_l2=0)
gsearch5 = GridSearchCV(estimator,param_grid = params_test5, scoring='roc_auc',cv=5,n_jobs=-1)
gsearch5.fit(X_train,y_train)
print(gsearch5.best_params_)