Xgboost对特征工程和数据处理比较友好,相比之下调参成为用好Xgboost重要的一环,本文分别从参数、调参方法、Python实现的维度进行梳理,作为调参思路的记录。
本文将关注以下几个问题:
1.Xgboost哪些参数需要调参?
2.通用的调参方法有哪些 ? 如何实现?
下表列出了 xgboost 0.90版本下 xgboost.sklearn 中 XGBBaseModel 的所有输入参数;根据对全部31个参数功能的初步了解并参考了其他博文(包括XGBoost调参笔记_浅笑古今的博客-CSDN博客_xgboost调参,https://segmentfault.com/a/1190000014040317等),初步对xgboost 实践中各参数调参重要性进行了排序,详见rank列;其中3>2>1。需要说明的是,这种调参重要性的划分只是提供一种参考,仍需要根据具体问题具体分析。(TODO:其中有些None值和空值还需要完善)
参数名 | 简说明 | 范围 | 默认 | 典型值 | rank | 说明 |
n_estimators | 学习器的数量 | int | 100 | 100~500 | 3 | 基本学习器的数量 |
max_depth | 树深度 | 0,∞ | 3 | 3~10 | 3 | 每个基本学习器树的最大深度,值越大数越复杂 |
learning_rate | 学习率 | [0,1] | 0.1 | 0.01~0.2 | 3 | 每次迭代更新权重时的步长。值越小,训练的越慢。 |
gamma | 损失减少阈值 | 0,∞ | 0 | None | 3 | 分裂节点时,损失函数减小值只有大于等于gamma节点才分裂,gamma值越大,算法越保守 |
reg_alpha | L1正则化 | float | 0 | None | 3 | 增加该值会让模型更加收敛 |
reg_lambda | L2正则化 | float | 1 | None | 3 | 控制XGBoost的正则化部分的,可以减少过拟合 |
min_child_weight | 子集最小权重 | 0,∞ | 1 | None | 3 | 如果节点的样本权重和小于该阈值,就不再进行拆分,该指数越大越大算法越保守。回归中是指建立每个模型所需要的最小样本数 |
subsample | 样本子采样 | (0,1] | 1 | 0.5-0.9 | 3 | 随机选取一定比例的样本来训练树。设置为0.5,则意味着XGBoost将从整个样本集合中随机的抽取出50%子样本建立树模型 |
colsample_bytree | 列子采样 | (0,1] | 1 | 0.5-0.9 | 3 | 列采样率,也就是特征采样率。在建立树时对特征采样的比例 |
booster | 基模型类型 | gbtree gblinear | gbtree | None | 2 | gbtree使用基于树的模型进行提升计算,gblinear使用线性模型进行提升计算 |
colsample_bylevel | 列子采样 | (0,1] | 1 | None | 2 | 构建每一层时,列采样率 |
colsample_bynode | 列子采样 | [0,1] | 1 | None | 2 | 是每个节点(拆分)的列的子采样率 |
scale_pos_weight | 处理样本不平衡 | float | 1 | None | 2 | 处理样本不平衡问题。在样本高度不平衡时,将参数设置大于0,可以加快算法收敛。 |
random_state | 随机数种子 | int | 0 | None | 2 | 设置它可以复现随机数据的结果,也可以用于调整参数 |
max_delta_step | 树权重最大增量 | 0,∞ | 0 | 0~10 | 1 | 每棵树所被允许的权重估计为最大增量。如果该值设置为0,则表示没有约束。如果将其设置为正值,则有助于使更新步骤更加保守。通常不需要这个参数,但当类极不平衡时,它可能有助于logistic回归。 |
verbosity | 日志长度 | int | None | 1 | 日志冗长程度0-3 | |
tree_method | 指定树方法 | auto exact approx hist gpu_exact gpu_hist | auto | None | 1 | 指定要使用的树生成算法 |
base_score | 全局偏差 | int/float | 0.5 | 1 | 所有实例的初始预测得分,整体偏倚 | |
silent | 过程打印设置 | 0,1 or True,False | 0 | None | 1 | 取0时表示打印出运行时信息,取1时表示不打印运行时信息 |
importance_type | 特征重要性类型 | None | None | 1 | feature_importances_属性的特征重要性类型 | |
eval_metric | 指定评估指标 | rmse mae logloss error merror mlogloss auc | 回归:rmse 分类:error | 回归:rmse分类:error | 1 | 校验数据所需要的评价指标,不同的目标函数将会有缺省的评价指标 rmse:均方根误差,mae:平均绝对误差,logloss:负对数似然函数值,error:二分类错误率(阈值为0.5),merror:多分类错误率,mlogloss:多分类logloss损失函数,auc:曲线下面积 |
missing | 缺失值 | None | None | 0 | 需要作为缺失值存在的数据中的值,如果为none,则默认为np.nan | |
num_parallel_tree | 增强随机森林 | int | None | 0 | 用于增强随机森林 | |
kwargs | 字典形式传参 | dict | None | 0 | 以字典形式传递参数 | |
n_jobs | 线程数目 | int | 1 | None | 0 | 线程数目 |
nthread | 并行计算设置 | int | 默认当前系统可以获得的最大线程数 | None | 0 | XGBoost运行时的线程数 |
monotone_constraints | 变量单调性约束 | None | None | 0 | 变量单调性约束 | |
interaction_constraints | 交互约束 | None | None | 0 | 表示允许交互的交互约束 | |
gpu_id | gpu ID | None | None | 0 | 无 | |
validate_parameters | 验证参数 | None | None | 0 | 无 | |
objective | 指定损失函数 | reg:linear reg:logistic binary:logistic binary:logitraw count:poisson multi:softmax multi:softprob rank:pairwise | None | 0 | 指的是需要被最小化的损失函数 reg:linear:线性回归 reg:logistic:逻辑回归 binary:logistic:二分类 binary:logitraw:二分类 count:poisson:计数问题 multi:softmax:多分类 multi:softprob:多分类 rank:pairwise:排名 |
各参数的主要功能虽然已经在上表中列出,但为了方便对调参的过程有进一步的理解,本小节对以下9个重要参数进行略微详细的介绍。
n_estimators(基本学习器的数量):要拟合的弱学习器数量,该值越大,模型越复杂,越容易过拟合
max_depth(基本学习器的深度): 树的最大深度,该值越大,模型越复杂,越容易拟合训练数据,越容易过拟合;树生长停止条件之一
learning_rate(学习率):每个基模型的惩罚项,降低单个模型的影响,为了防止过拟合,该值越接近1越容易或拟合,越接近0精度越低
gamma(损失减少阈值):在树的叶节点上进一步划分所需的最小损失减少,在模型训练过程中,只有损失下降的值超过该值,才会继续分裂节点,该值越小模型越复杂,越容易过拟合,树生长停止条件之一
reg_alpha(L1正则化):L1正则化用于对叶子的个数进行惩罚,用于防止过拟合
reg_lambda(L2正则化):L2正则化用于对叶子节点的得分进行惩罚,L1和L2正则化项共同惩罚树的复杂度,值越小模型的鲁棒性越高
min_child_weight(子集最小权重):最小样本的权重之和,在树的生长过程中,如果样本的权重之和小于该值,将不再分裂;树生长停止条件之一
subsample(样本子采样):训练集对样本实例的采样率,用于防止过拟合
colsample_bytree(列子采样):每棵树对特征的采样率,用于防止过拟合
机器学习模型的训练过程,就是为模型找到最优超参数组合,使得模型在保证足够精度的情况下同时具有良好的鲁棒性;下面简单介绍四种常用的机器学习调参方法的基本思路和优缺点。
需要说明的是,下面几种搜索最佳参数的方法都需要事先指定要优化哪些超参数以及超参数优化的范围(有限可列集合),其中搜索代码都调用了sklearn.model_selection 模块。
1.手动调参
顾名思义,此方法手动从参数集中选择参与调优的参数,并手动设置超参数的数值,如果训练效果不佳再重新设置超参数的数值,直到达到满意的训练效果;这种方法依赖调参者对超参数在算法中影响的深刻理解,和丰富的调参经验,往往也很难验证调参结果是否是最优或接近最优的结果。手动调参方式比较随意,不附代码
2.网格搜索
网格搜索首先为每个待优化的超参数列出一个值列表,然后尝试列表中值的所有组合,这种方法的特点是尝试的参数组合最全,如果参数值步长足够小,参数足够全,理论上模型可以接近全局最优解,但是由于连续值参数我们仍然需要采样,因此仍然不能保证达到全局最优解。网格搜索的计算量也非常巨大,速度非常的慢。
#coding:utf-8 from xgboost.sklearn import XGBRegressor from sklearn.model_selection import GridSearchCV import pandas as pd import numpy as np from math import sqrt from sklearn.metrics import mean_squared_error #1.以CSV形式导入数据集 df_train = pd.read_csv(r"C:\Users\ld\Desktop\train.csv") df_test = pd.read_csv(r"C:\Users\ld\Desktop\test.csv") X_train = df_train[[i for i in df_train.columns.tolist() if i not in ["label"]]] #训练集 y_train = df_train["label"] #训练标签 X_test =df_test[[i for i in df_test.columns.tolist() if i not in ["label"]]] #测试集 y_test = df_test["label"] #测试标签 #2.参数集定义 param_grid = { 'max_depth': [2, 3, 4, 5, 6, 7, 8], 'n_estimators': [30, 50, 100, 300, 500, 1000,2000], 'learning_rate': [0.1, 0.2, 0.3, 0.4, 0.01, 0.02, 0.03, 0.05, 0.5], "gamma":[0.0, 0.1, 0.2, 0.3, 0.4], "reg_alpha":[0.0001,0.001, 0.01, 0.1, 1, 100], "reg_lambda":[0.0001,0.001, 0.01, 0.1, 1, 100], "min_child_weight": [2,3,4,5,6,7,8], "colsample_bytree": [0.6, 0.7, 0.8, 0.9], "subsample":[0.6, 0.7, 0.8, 0.9]} #3.网格搜索并打印最佳参数 gsearch1 = GridSearchCV(estimator=XGBRegressor(scoring='ls',seed=27), param_grid=param_grid, cv=5) gsearch1.fit(X_train, y_train) print("best_score_:",gsearch1.best_params_,gsearch1.best_score_) #4.用最佳参数进行预测 y_test_pre= gsearch1.predict(X_test) #5.打印测试集RMSE rmse = sqrt(mean_squared_error(np.array(list(y_test)), np.array(list(y_test_pre)))) print("rmse:",rmse)
3.随机搜索
随机搜索是指在超参数分布中随机选择参数值的方法;这种方法类似于对网格搜索的超参组合进行抽样后,再对抽样集进行网格搜索,随机搜索的速度比网格搜索快很多,但也很难保证模型收敛于全局最优解或最优解附近。
#coding:utf-8 from xgboost.sklearn import XGBRegressor from sklearn.model_selection import RandomizedSearchCV import pandas as pd import numpy as np from math import sqrt from sklearn.metrics import mean_squared_error #1.以CSV形式导入数据集 df_train = pd.read_csv(r"C:\Users\ld\Desktop\train.csv") df_test = pd.read_csv(r"C:\Users\ld\Desktop\test.csv") X_train = df_train[[i for i in df_train.columns.tolist() if i not in ["label"]]] #训练集 y_train = df_train["label"] #训练标签 X_test =df_test[[i for i in df_test.columns.tolist() if i not in ["label"]]] #测试集 y_test = df_test["label"] #测试标签 #2.参数集定义 param_grid = { 'max_depth': [2, 3, 4, 5, 6, 7, 8], 'n_estimators': [30, 50, 100, 300, 500, 1000,2000], 'learning_rate': [0.1, 0.2, 0.3, 0.4, 0.01, 0.02, 0.03, 0.05, 0.5], "gamma":[0.0, 0.1, 0.2, 0.3, 0.4], "reg_alpha":[0.0001,0.001, 0.01, 0.1, 1, 100], "reg_lambda":[0.0001,0.001, 0.01, 0.1, 1, 100], "min_child_weight": [2,3,4,5,6,7,8], "colsample_bytree": [0.6, 0.7, 0.8, 0.9], "subsample":[0.6, 0.7, 0.8, 0.9]} #3.随机搜索并打印最佳参数 gsearch1 = RandomizedSearchCV(XGBRegressor(scoring='ls',seed=27), param_grid, cv=5) gsearch1.fit(X_train, y_train) print("best_score_:",gsearch1.best_params_,gsearch1.best_score_) #4.用最佳参数进行预测 y_test_pre= gsearch1.predict(X_test) #5.打印测试集RMSE rmse = sqrt(mean_squared_error(np.array(list(y_test)), np.array(list(y_test_pre)))) print("rmse:",rmse)
4.贝叶斯搜索
前面介绍的三种搜索方法,参数组合之间的尝试是相互独立的,不会因为一个参数组合而影响其他参数组合;而贝叶斯优化算法在寻找最优参数时,会充分利用之前尝试过的参数组合信息,来学习目标函数的期望和走向,并找到使目标函数更优的参数组合,并迭代。但有时初始参数的选择不当可能导致贝叶斯搜索陷入局部最优解,因此贝叶斯分布会在还未取样的区域进行采样或后验概率分布下全局最值出现概率最大的区域进行采样中进行平衡。相比网格搜索,贝叶斯搜索的速度更快,相比随机搜索,贝叶斯搜索的可以更好的保留重要信息,搜索效果更稳健。
补充:除了上述几种基础的调参方法外,网上还有一种结合手动调参和网格搜索为Xgboost调参的半自动化方法,目前没有做尝试,仅作为记录;步骤如下:
(1)先网格搜索 n_estimators 参数,其他参数取定值
(2)取(1)中最优化结果加入参数定值,并网格搜索min_child_weight和max_depth两参数
(3)取(1)(2)中最优化结果加入参数定值,并网格搜索 gamma 参数
(4)取(1)~(3)中最优化结果加入参数定值,并网格搜索 subsample和colsample_bytree 参数
(5)取(1)~(4)中最优化结果加入参数定值,并网格搜索 reg_alpha 和 reg_lambda 参数
(6)取(1)~(5)中最优化结果加入参数定值,并网格搜索 learning_rate 参数
机器学习中四种调参方法总结
Sina Visitor System
贝叶斯优化(Bayesian Optimization)只需要看这一篇就够了,算法到python实现 - 知乎
几种机器学习常用调参方式对比(网格搜索,随机搜索,贝叶斯优化)_tomwang0322的博客-CSDN博客_网格搜索策略
机器学习:超参数调优的方法(网格搜索 、随机搜索、贝叶斯优化算法)_WellWang_S的博客-CSDN博客_网格搜索算法设置最优超参数
https://segmentfault.com/a/1190000014040317