XGBoost的剪枝参数与模型调参实战

Posted Peer Parker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XGBoost的剪枝参数与模型调参实战相关的知识,希望对你有一定的参考价值。

剪枝参数

作为 天生过拟合 的模型, XGBoost 应用的核心之一就是减轻过拟合带来的影响。作为树模型,减轻过拟合的方式主要是靠对决策树 剪枝 来降低模型的复杂度,以求降低方差。在之前的博文中,已经介绍了好几个可以用来防止过拟合的参数,包括上一节提到的复杂度控制,正则化的两个参数,控制迭代速度的参数以及管理每次迭代前进行的随机有放回抽样的参数subsample 。所有的这些参数都可以用来减轻过拟合。但除此之外,我们还有几个影响重大的,专用于剪枝的参数:

这些参数中, 树的最大深度是决策树中的剪枝法宝 ,算是最常用的剪枝参数,不过在XGBoost中,最大深度的功能与参数相似,因此如果先调节了,则最大深度可能无法展示出巨大的效果。当然,如果先调整了最大深度,则也有可能无法显示明显的效果。通常来说,这两个参数中我们只使用一个,不过两个都试试也是不错的选择。 三个随机抽样特征的参数中,前两个比较常用。在建立树时对特征进行抽样其实是决策树和随机森林中比较常见的一种方法,但是在XGBoost 之前,这种方法并没有被使用到 boosting 算法当中过。 Boosting 算法一直以抽取样本(横向抽样)来调整模型过拟合的程度,而实践证明其实纵向抽样( 抽取特征 )更能够防止过拟合。 参数 min_child_weight 不太常用,它是一篇叶子上的二阶导数之和,当样本所对应的二阶导数很小时,比如说为0.01, min_child_weight 若设定为 1 ,则说明一片叶子上至少需要 100个样本。本质上来说,这个参数其实是在 控制叶子上所需的最小样本量 ,因此对于样本量很大的数据会比较有效。就剪枝的效果来说,这个参数的功能也被替代了一部分,通常来说我们会试试看这个参数,但这个参数不是优先选择。

调参策略

通常当我们获得了一个数据集后,我们先使用网格搜索找出比较合适的 n_estimators(num_round) eta 组合,然后使用 gamma 或者max_depth 观察模型处于什么样的状态(过拟合还是欠拟合,处于方差 - 偏差图像的左边还是右边?),最后再决定是否要进行剪枝。通常来说,对于XGB 模型,大多数时候都是需要剪枝的。

波士顿房价数据集实战

import datetime
import xgboost as xgb
import matplotlib.pyplot as plt
from time import time
from sklearn.datasets import load_boston

# 加载数据
data = load_boston()
X = data.data
y = data.target

# 读取全数据
dfull = xgb.DMatrix(X,y)

# 参数设置
param1 = 'silent':True 
          ,'obj':'reg:linear'
          ,"subsample":1
          ,"max_depth":6
          ,"eta":0.3
          ,"gamma":0
          ,"lambda":1
          ,"alpha":0
          ,"colsample_bytree":1
          ,"colsample_bylevel":1
          ,"colsample_bynode":1
          ,"nfold":5
          ,'verbosity':0
num_round = 200

# 计算模型训练时间
time0 = time()
cvresult1 = xgb.cv(param1, dfull, num_round)
print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))

# 绘制迭代过程的均方误差
fig,ax = plt.subplots(1,figsize=(15,10))
ax.grid()
ax.plot(range(1,201),cvresult1.iloc[:,0],c="red",label="train,original")
ax.plot(range(1,201),cvresult1.iloc[:,2],c="orange",label="test,original")
ax.legend(fontsize="xx-large")
plt.show()

从曲线上可以看出,模型现在处于过拟合的状态。我们决定要进行剪枝。我们的目标是:训练集和测试集的结果尽量接近,如果测试集上的结果不能上升,那训练集上的结果降下来也是不错的选择(让模型不那么具体到训练数据,增加泛化能力)。在这里,我们要使用 三组曲线 。一组用于展示原始数据上的结果,一组用于展示上一个参数调节完毕后的结果,最后一组用于展示现在我们在调节的参数的结果。具体怎样使用,我们来看:
# 调参结果1
param2 = 'silent':True 
          ,'obj':'reg:linear'
          ,"subsample":1
          ,"max_depth":4
          ,"eta":0.05
          ,"gamma":20
          ,"lambda":3.5
          ,"alpha":0.2
          ,"colsample_bytree":0.4
          ,"colsample_bylevel":0.6
          ,"colsample_bynode":1
          ,"nfold":5
          ,'verbosity':0



# 调参结果2
param3 = 'silent':True 
          ,'obj':'reg:linear'
          ,"subsample":1
          ,"max_depth":2
          ,"eta":0.05
          ,"gamma":0
          ,"lambda":1
          ,"alpha":0
          ,"colsample_bytree":1
          ,"colsample_bylevel":0.4
          ,"colsample_bynode":1
          ,"nfold":5
          ,'verbosity':0


# 绘制对比图
fig,ax = plt.subplots(1,figsize=(15,8))
ax.set_ylim(top=5)
ax.grid()
ax.plot(range(1,201),cvresult1.iloc[:,0],c="red",label="train,original")
ax.plot(range(1,201),cvresult1.iloc[:,2],c="orange",label="test,original")
ax.plot(range(1,201),cvresult2.iloc[:,0],c="green",label="train,last")
ax.plot(range(1,201),cvresult2.iloc[:,2],c="blue",label="test,last")
ax.plot(range(1,201),cvresult3.iloc[:,0],c="gray",label="train,this")
ax.plot(range(1,201),cvresult3.iloc[:,2],c="pink",label="test,this")
ax.legend(fontsize="xx-large")
plt.show()

从上图可以看到,XGBoost模型通过剪枝,模型的过拟合被削弱,泛化能力增强,且模型的复杂度降低!!!

调参建议

  1. 可以使用网格搜索进行调参,但是建议至少先使用xgboost.cv来确认参数的范围,否则很可能花很长的时间做了无用功。并且,在使用网格搜索的时候,最好不要一次性将所有的参数都放入进行搜索,最多一次两三个。有一些互相影响的参数需要放在一起使用,比如学习率eta和树的数量n_estimators(num_round)。
  2. 调参的时候参数的顺序也会影响调参结果,因此在现实中,我们会优先调整那些对模型影响巨大的参数。在这里,我建议的剪枝上的调参顺序是:n_estimators(num_round)与eta共同调节,gamma或者max_depth,采样和抽样参数(纵向抽样影响更大),最后才是正则化的两个参数。当然,可以根据自己的需求来进行调整。
  3. 若调参之后测试集上的效果还没有原始设定上的效果好,但交叉验证曲线确实显示测试集和训练集上的模型评估效果是更加接近的,推荐使用调参之后的效果。我们希望增强模型的泛化能力,然而泛化能力的增强并不代表着在新数据集上模型的结果一定优秀,因为未知数据集并非一定符合全数据的分布,在一组未知数据上表现十分优秀,也不一定就能够在其他的未知数据集上表现优秀。因此不必过于纠结在现有的测试集上是否表现优秀。当然了,在现有数据上如果能够实现训练集和测试集都非常优秀,那模型的泛化能力自然也会是很强的。

继续加油,我们一定会成功的!!!

以上是关于XGBoost的剪枝参数与模型调参实战的主要内容,如果未能解决你的问题,请参考以下文章

XGBoost模型调参:GridSearchCV方法网格搜索优化参数

使用贝叶斯优化工具实践XGBoost回归模型调参

使用贝叶斯优化工具实践XGBoost回归模型调参

机器学习系列调参GridsearchCV随机森林GBDTLightGBM和XGBoost调参顺序,外加一些加速调参的小技巧(主要介绍坐标下降)

xgboost调参

XGBoost与GBDT(一)-几种最优化方法对比