XGBoost模型调参:GridSearchCV方法网格搜索优化参数
Posted Dark universe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XGBoost模型调参:GridSearchCV方法网格搜索优化参数相关的知识,希望对你有一定的参考价值。
文章目录
一、前言
本篇文章是继上一篇文章:使用K-Fold训练和预测XGBoost模型的方法,探讨对XGBoost模型调优的方法,所使用的代码和数据文件均是基于上一篇文章的,需要的小伙伴可以跳转链接自行获取。
二、数据处理
程序和上篇文章中的完全一致,不再赘述。
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from xgboost import XGBRegressor
feature_file = pd.read_csv("./DataHousePricePrediction/train.csv")
x = []# 特征数据
y = []# 标签
for index in feature_file.index.values:
#print('index', index)
#print(feature_file.values[0])
#print(feature_file.ix[index].values)
x.append(feature_file.values[index][2: -1]) # 从原文件中提取输入变量数据
y.append(feature_file.values[index][1]) # 从原文件中提取输出变量标签
x, y = np.array(x), np.array(y)
# 划分训练集和验证集
X_train,X_valid,y_train,y_valid = train_test_split(x,y,test_size=0.2,random_state=12345)
三、XGBoost参数调优
3.1 常见可调参数
一般调参会考虑以下几个超参数(需要在模型中初始化):
• learning_rate
• n_estimators
• max_depth
• min_child_weight
• subsample
• colsample_bytree
• gamma
• reg_alpha
• reg_lambda
这些参数的具体含义可见:XGBoost常用参数
定义模型:
#定义xgboost模型
xgb = XGBRegressor(learning_rate =0.1,
n_estimators=150,
max_depth=5,
min_child_weight=1,
gamma=0,
subsample=0.8,
colsample_bytree=0.8,
objective= 'reg:squarederror',
reg_alpha= 0,
reg_lambda= 1,
nthread=4,
scale_pos_weight=1,
seed=27)
3.2 GridSearchCV调参函数
不同于CV领域的神经网络,Scikit-learn为XGBoost模型提供了一个网格搜索最优化参数的方法:GridSearchCV(网格搜索交叉验证调参)。详细介绍见:sklearn.model_selection.GridSearchCV
在本文中,主要使用到了GridSearchCV中的以下几个参数:
- estimator:表示所要调优的模型。
- param_grid:字典类型变量。主要存储的是要尝试的参数,每一个参数中要尝试的值组成一个列表,不同的参数列表构成一个字典。
- n_jobs,int类型,表示要并行运行的作业数,-1表示使用所有的处理器。通过此参数可以认为控制使用CPU的核数。
- cv,int类型,表示要交叉验证拆分的数量,也就是K-Fold的数量。
GridSearchCV搜索原理:对param_grid中要尝试的变量进行排列组合,遍历每一种组合,通过交叉验证的方式返回所有参数组合下的评价指标得分,最后选择分数最高的组合对应的参数作为最优值。简单来说,GridSearchCV的搜索原理就是枚举,暴力搜索。
3.3 一般调参顺序
调参的要旨是:每次调一个或两个超参数,然后将找到的最优超参数代入到模型中继续调余下的参数。
XGBoost一般的调参顺序和排列组合是:
- 最佳迭代次数(树模型的个数):n_estimators
- min_child_weight以及max_depth
- gamma
- subsample以及colsample_bytree
- reg_alpha以及reg_lambda
- learning_rate
下面以min_child_weight以及max_depth两个参数为例展示对应的调参程序:
from sklearn.model_selection import GridSearchCV
#Need to research
#research_one: n_epoch
#research_one: max_depth
param_test1 =
'min_child_weight': [1, 2, 3],
'max_depth':[2, 3, 4, 5, 6, 7]
xgb_res = GridSearchCV(estimator = xgb,
param_grid = param_test1,
n_jobs=4,
cv=5)
xgb_res.fit(X_train, y_train)
3.4 调参结果可视化
在搜索完成后,本文使用了cv_results_、best_params_、best_score_
作为搜索输出,这三个方法都是GridSearchCV
方法的对象,含义是:
cv_results_
:输出cv(交叉验证)结果的,可以是字典形式也可以是numpy形式,还可以转换成DataFrame格式best_params_
:通过网格搜索得到的score最好对应的参数best_score_
:输出最好的成绩
print('max_depth_min_child_weight')
print('gsearch1.grid_scores_', xgb_res.cv_results_)
print('gsearch1.best_params_', xgb_res.best_params_)
print('gsearch1.best_score_', xgb_res.best_score_)
程序的输出为:
从输出的结果看出,GridSearchCV搜索确定了最佳的max_depth为3,最佳的min_child_weight为3,综合两种参数下模型的最佳得分为:0.65,获得了我们要的结果。
注:这里没有展示xgb_res.cv_results_
的输出结果(太长了),从上面的对param_test1
的定义可知,此次搜索中min_child_weight有3中取值,max_depth有6种取值,进行排列组合后有18种可能。cv_results_
展示的就是这18种情况对应的交叉验证值。
四、总结
GridSearchCV
是XGBoost模型最常用的调参方法,在调参时要注意调参顺序并且要有效设置参数的变化范围,提高效率。受限于暴力搜索的设计逻辑,GridSearchCV
并不适用于数据量大和超参数数量多的场景。当数据量大时,可以考虑坐标下降方法;当所调超参数数量多时,可以考虑使用随机搜索 RandomizedSearchCV
方法。
总的来说,有效的数据清洗和挖掘、符合使用场景的模型、灵活的训练和调参技巧是提高预测准确度的三大手段。
机器学习系列调参GridsearchCV随机森林GBDTLightGBM和XGBoost调参顺序,外加一些加速调参的小技巧(主要介绍坐标下降)
本文将记录一下几个可以将模型参数分开进行调参的树形模型的调参顺序。以及几个能够加快调参速度的小技巧。如果有帮到你,帮懒羊羊点个赞,关注一下我呗。
目录
2.1随机森林、GBDT、LightGBM和XGBoost调参顺序
1.GridSearchCV简介、好处和弊端
1.1简介
最为常见的调参方法就是使用网格搜索+交叉验证进行参数的优化(GridsearchCV)
GridSearchCV的sklearn官方网址:
sklearn.model_selection.GridSearchCV — scikit-learn 1.0.2 documentation
1.1.1简单示例
from sklearn import tree
clf = tree.DecisionTreeClassifier(class_weight='balanced')
#自动调参
tree_param_grid = 'criterion' : ["gini"],
'splitter': ["random"],
'max_depth' : range(5,30,5),
'min_samples_split': range(10,210,50),
'min_samples_leaf': [5,10],
tree_best = GridSearchCV(clf,param_grid = tree_param_grid,cv = 3,scoring="roc_auc",n_jobs= -1, verbose = 100)
#进行网格搜索交叉验证调参
tree_best.fit(feature_train,target_train)
print(tree_best.best_estimator_)
print(tree_best.best_params_," ","得分:",tree_best.best_score_)
y_predict = tree_best.predict(feature_test) # 进行预测
y_prob = tree_best.predict_proba(feature_test) # 进行预测
输出示例:
Fitting 3 folds for each of 40 candidates, totalling 120 fits DecisionTreeClassifier(class_weight='balanced', max_depth=15, min_samples_leaf=5, min_samples_split=160, splitter='random')
'criterion': 'gini', 'max_depth': 15, 'min_samples_leaf': 5, 'min_samples_split': 160, 'splitter': 'random' 得分: 0.9651868978885353
1.1.2参数说明
class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch=‘2*n_jobs’, error_score=’raise’, return_train_score=’warn’)
(1) estimator
选择使用的分类器,并且传入除需要确定最佳的参数之外的其他参数。以随机森林为例,初始化一个带有你能尽可能先确定的参数的RandomForestClassifier:estimator=RandomForestClassifier(min_samples_split=100,min_samples_leaf=20,max_depth=8,max_features='sqrt',random_state=10),
(2) param_grid
需要最优化的参数的取值,值为字典或者列表,例如:param_grid =tree_param_grid ,tree_param_grid = 'criterion' : ["gini"],
'splitter': ["random"],
'max_depth' : range(5,30,5),
'min_samples_split': range(10,210,50),
'min_samples_leaf': [5,10],
(3) scoring=None
模型评价标准,默认None,这时需要使用score函数;或者如scoring='roc_auc'.
可选:
Scoring | Function | Comment |
---|---|---|
Classification | ||
‘accuracy’ | ||
‘balanced_accuracy’ | ||
‘top_k_accuracy’ | ||
‘average_precision’ | ||
‘neg_brier_score’ | ||
‘f1’ | for binary targets | |
‘f1_micro’ | micro-averaged | |
‘f1_macro’ | macro-averaged | |
‘f1_weighted’ | weighted average | |
‘f1_samples’ | by multilabel sample | |
‘neg_log_loss’ | requires | |
‘precision’ etc. | suffixes apply as with ‘f1’ | |
‘recall’ etc. | suffixes apply as with ‘f1’ | |
‘jaccard’ etc. | suffixes apply as with ‘f1’ | |
‘roc_auc’ | ||
‘roc_auc_ovr’ | ||
‘roc_auc_ovo’ | ||
‘roc_auc_ovr_weighted’ | ||
‘roc_auc_ovo_weighted’ | ||
Clustering | ||
‘adjusted_mutual_info_score’ | ||
‘adjusted_rand_score’ | ||
‘completeness_score’ | ||
‘fowlkes_mallows_score’ | ||
‘homogeneity_score’ | ||
‘mutual_info_score’ | ||
‘normalized_mutual_info_score’ | ||
‘rand_score’ | ||
‘v_measure_score’ | ||
Regression | ||
‘explained_variance’ | ||
‘max_error’ | ||
‘neg_mean_absolute_error’ | ||
‘neg_mean_squared_error’ | ||
‘neg_root_mean_squared_error’ | ||
‘neg_mean_squared_log_error’ | ||
‘neg_median_absolute_error’ | ||
‘r2’ | ||
‘neg_mean_poisson_deviance’ | ||
‘neg_mean_gamma_deviance’ | ||
‘neg_mean_absolute_percentage_error’ |
(4) fit_params=None
(5) n_jobs=1
n_jobs: 并行数,int:个数,-1:跟CPU核数一致(即使用全部cpu进行模型训练), 1:默认值
(6) iid=True
iid:默认True,为True时,默认为各个样本fold概率分布一致,误差估计为所有样本之和,而非各个fold的平均。
(7) refit=True
默认为True,程序将会以交叉验证训练集得到的最佳参数,重新对所有可用的训练集与开发集进行,作为最终用于性能评估的最佳模型参数。即在搜索参数结束后,用最佳参数结果再次fit一遍全部数据集。
(8) cv=None
交叉验证参数,默认None,使用三折交叉验证。指定fold数量,默认为3,也可以是yield训练/测试数据的生成器。
(9) verbose=0, scoring=None
verbose:日志冗长度,int:冗长度,0:不输出训练过程,1:偶尔输出,>1:对每个子模型都输出。
(10) pre_dispatch=‘2*n_jobs’
指定总共分发的并行任务数。当n_jobs大于1时,数据将在每个运行点进行复制,这可能导致OOM,而设置pre_dispatch参数,则可以预先划分总共的job数量,使数据最多被复制pre_dispatch次
(11) error_score=’raise’
(12) return_train_score=’warn’
如果“False”,cv_results_属性将不包括训练分数
回到sklearn里面的GridSearchCV,GridSearchCV用于系统地遍历多种参数组合,通过交叉验证确定最佳效果参数。
1.1.3 属性
(1)cv_results_ : dict of numpy (masked) ndarrays
具有键作为列标题和值作为列的dict,可以导入到DataFrame中。
(2)best_estimator_ : estimator
通过搜索选择的估计器,即在左侧数据上给出最高分数(或指定的最小损失)的估计器。 如果refit = False,则不可用。
这个属性可以作为下一轮调参时的输入estimator。这是一个快速构建下一轮调参的小技巧。
(3)best_score_ : float best_estimator的分数
(4)best_params_ : dict 在保存数据上给出最佳结果的参数设置
(5)best_index_ : int 对应于最佳候选参数设置的索引(cv_results_数组)。
search.cv_results _ ['params'] [search.best_index_]中的dict给出了最佳模型的参数设置,给出了最高的平均分数(search.best_score_)。
(6)scorer_ : function
Scorer function used on the held out data to choose the best parameters for the model.
(7)n_splits_ : int
The number of cross-validation splits (folds/iterations).
(8)grid_scores_:给出不同参数情况下的评价结果
1.2GridsearchCV的好处和弊端
好处:
(1)一定会在给出的超参数集上给出最优参数解,不会陷入局部最优;
(2)理解起来比较容易
弊端:
(1)数据集一大,参数一多,调参所需时间复杂度就指数级上升,而许多模型的参数就是会很多。
2.调参顺序
树形模型的参数都比较多,如果使用在一轮gridsearchcv里将所有参数进行调参,会指数级提升运算复杂度,有可能一两天还调不出来一个随机森林的参数。因此将某些需要首先在一起调参的参数在一轮中调参,其他没有必要一起调参的参数或没有必要优先进行调参的参数在另一轮进行调整,以此类推,能够指数级节约调参时间。这一调参方法也被成称为数据量比较大的时候可以使用一个快速调优的方法——坐标下降,是一种贪心算法:拿当前对模型影响最大的参数调优,直到最优化;再拿下一个影响最大的参数调优,如此下去,直到所有的参数调整完毕。
2.1调参加速小技巧
(1)利用gridsearchcv的best_estimator_ 属性。目前网上的很多代码都是先进行一轮调参,找到最优参数后再使用这一轮调参的最优参数构建新的estimator,然后进行下一轮调参,这在实际操作中非常不方便,代码不具备可重用性,并且每次训练都要重新进行参数的设置。利用best_estimator_属性可以快速建立下一轮的调参,并且不用先查看上一轮的最优参数在进行估计器的构建。
(2)更改GridsearchcCV()参数cv。cv越小,进行交叉验证的次数越少,将cv改小可以减少寻优次数,个人实验证明在树形模型下,cv=3和cv=10的效果差不多,但不同的数据集可能有不同的结果。
(3)使用 sklearn.model_selection.RandomizedSearchCV替代GridsearchCV。引入随机性,对参数寻优进行随机搜索。RandomizedSearchCV的参数和属性与GridsearchCV几乎一样。
考察其源代码,其搜索策略如下:
(a)对于搜索范围是distribution的超参数,根据给定的distribution随机采样;
(b)对于搜索范围是list的超参数,在给定的list中等概率采样;
(c)对a、b两步中得到的n_iter组采样结果,进行遍历。
但这一方法有可能会使参数寻优陷入局部最优解,但实践中基本上没有很大区别。
2.1随机森林、GBDT、LightGBM和XGBoost调参顺序
随机森林:
比较重要的几个参数的调参顺序如下:
n_estimators-->min_samples_split-->max_features-->max_depth
#随机森林
def my_randomforest(feature_train,target_train,feature_test,target_test):
from sklearn import ensemble
rf = ensemble.RandomForestClassifier(class_weight='balanced')
rf_param_grid1 = 'n_estimators':[100,200,400,800,1000,1200,1500],
rf_best = GridSearchCV(rf,param_grid = rf_param_grid1,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
rf_best.fit(feature_train,target_train)
print(type(rf_best.best_params_))
rf_param_grid2 = 'min_samples_split':range(30,111,20)
rf_best2 = GridSearchCV(rf_best.best_estimator_,param_grid = rf_param_grid2,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
rf_best2.fit(feature_train,target_train)
rf_param_grid3 = 'max_features':range(5,76,10),
rf_best3 = GridSearchCV(rf_best.best_estimator_,param_grid = rf_param_grid3,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
rf_best3.fit(feature_train,target_train)
rf_param_grid4 = 'max_depth':range(3,22,3)
rf_best4 = GridSearchCV(rf_best.best_estimator_,param_grid = rf_param_grid6,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
rf_best4.fit(feature_train,target_train)
print(rf_best4.best_estimator_)
print(rf_best4.best_params_," ","得分:",rf_best4.best_score_)
y_predict = rf_best4.predict(feature_test) # 进行预测
y_prob = rf_best4.predict_proba(feature_test) # 进行预测
result_evaluation(target_test,y_prob,y_predict)
return rf_best6.best_params_,rf_best6,y_prob
注:result_evaluation()函数是我将求约登指数、给出默认阈值下的混淆矩阵和最佳阈值下的混淆矩阵以及ROC图集成在一个函数里的实现,见我个人主页另一篇文章。【机器学习系列】【模型评价】【ROC曲线、约登指数最佳阈值】一个函数中实现约登指数计算并集成到ROC图中,给出默认阈值及最佳阈值下的混淆矩阵_学金融的程序员懒羊羊的博客-CSDN博客输入实际标签、预测的概率值、预测标签,计算最佳阈值,输出ROC曲线,输出默认阈值下的混淆矩阵和最佳阈值下的混淆矩阵https://blog.csdn.net/standingflower/article/details/124564004?spm=1001.2014.3001.5502
gbdt:
比较重要的几个参数的调参顺序如下:
n_estimators-->max_depth和min_samples_split-->min_samples_split和min_samples_leaf-->max_features-->subsample->learning_rate
#GBDT
#https://blog.csdn.net/olizxq/article/details/89222908
def my_gbdt(feature_train,target_train,feature_test,target_test):
from sklearn.ensemble import GradientBoostingClassifier
gbdt = GradientBoostingClassifier()
gbdt_param_grid1 = 'n_estimators':[50,100,200,400,800],
gbdt_best = GridSearchCV(gbdt,param_grid = gbdt_param_grid1,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
gbdt_best.fit(feature_train,target_train)
gbdt_param_grid2 = 'max_depth':[5,10,15,20,25],
'min_samples_split':range(100,801,200)
gbdt_best2 = GridSearchCV(gbdt_best.best_estimator_,param_grid = gbdt_param_grid2,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
gbdt_best2.fit(feature_train,target_train)
gbdt_param_grid3 = 'min_samples_split':range(300,1701,200),
'min_samples_leaf':range(60,101,10)
gbdt_best3 = GridSearchCV(gbdt_best2.best_estimator_,param_grid = gbdt_param_grid3,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
gbdt_best3.fit(feature_train,target_train)
gbdt_param_grid4 = 'max_features':range(7,20,2)
gbdt_best4 = GridSearchCV(gbdt_best3.best_estimator_,param_grid = gbdt_param_grid4,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
gbdt_best4.fit(feature_train,target_train)
gbdt_param_grid5 = 'subsample':[0.6,0.7,0.75,0.8,0.85,0.9]
gbdt_best5 = GridSearchCV(gbdt_best4.best_estimator_,param_grid = gbdt_param_grid5,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
gbdt_best5.fit(feature_train,target_train)
gbdt_param_grid6 = 'learning_rate':[0.001,0.01,0.1,0.25]
gbdt_best6 = GridSearchCV(gbdt_best5.best_estimator_,param_grid = gbdt_param_grid6,cv = 3,scoring="roc_auc",n_jobs= -1, verbose=100)
gbdt_best6.fit(feature_train,target_train)
print(gbdt_best6.best_estimator_)
print(gbdt_best6.best_params_," ","得分:",gbdt_best6.best_score_)
y_predict = gbdt_best6.predict(feature_test) # 进行预测
y_prob = gbdt_best6.predict_proba(feature_test) # 进行预测
result_evaluation(target_test,y_prob,y_predict)
return gbdt_best6.best_params_,gbdt_best6,y_prob
LightGBM就不给代码示例了,顺序是:
n_estimators-->max_depth和min_samples_split-->min_samples_split和min_samples_leaf-->max_features-->subsample->learning_rate
XGBoost就不给代码示例了,顺序是:
n_estimators-->max_depth和min_child_weight-->gamma-->subsample-->reg_alpha-->learning_rate
以上是关于XGBoost模型调参:GridSearchCV方法网格搜索优化参数的主要内容,如果未能解决你的问题,请参考以下文章
时间序列——GridSearchCV&TimeSeriesSplit的调参(xgboost预测sin(x))