当GridSearch遇上XGBoost 一段代码解决调参问题

栏目: 编程工具 · 发布时间: 6年前

内容简介:数据比赛,GBM(Gredient Boosting Machine)少不了,我们最常见的就是XGBoost和LightGBM。模型是在数据比赛中尤为重要的,但是实际上,在比赛的过程中,大部分朋友在模型上花的时间却是相对较少的,大家都倾向于将宝贵的时间留在特征提取与模型融合这些方面。在实战中,我们会先做一个baseline的demo,尽可能快尽可能多的挖掘出模型的潜力,以便后期将精力花在特征和模型融合上。这里就需要一些调参功底。本文从这两种模型的一共百余参数中选取重要的十余个进行探讨研究。并给大家展示快速

数据比赛,GBM(Gredient Boosting Machine)少不了,我们最常见的就是XGBoost和LightGBM。

模型是在数据比赛中尤为重要的,但是实际上,在比赛的过程中,大部分朋友在模型上花的时间却是相对较少的,大家都倾向于将宝贵的时间留在特征提取与模型融合这些方面。在实战中,我们会先做一个baseline的demo,尽可能快尽可能多的挖掘出模型的潜力,以便后期将精力花在特征和模型融合上。这里就需要一些调参功底。

本文从这两种模型的一共百余参数中选取重要的十余个进行探讨研究。并给大家展示快速轻量级的调参方式。当然,有更高一步要求的朋友,还是得戳LightGBM和XGBoost这两个官方文档链接。

为了更好的试验,我将预处理后的数据放在百度云上。大家戳链接下载。

XGBoost 的一些重要参数

XGBoost的参数一共分为三类:

  1. 通用参数 :宏观函数控制。
  2. Booster参数 :控制每一步的booster(tree/regression)。booster参数一般可以调控模型的效果和计算代价。我们所说的调参,很这是大程度上都是在调整booster参数。
  3. 学习目标参数 :控制训练目标的表现。我们对于问题的划分主要体现在学习目标参数上。比如我们要做分类还是回归,做二分类还是多分类,这都是目标参数所提供的。

通用参数

  1. booster :我们有两种参数选择, gbtreegblinear 。gbtree是采用树的结构来运行数据,而gblinear是基于线性模型。
  2. silent :静默模式,为 1 时模型运行不输出。
  3. nthread : 使用线程数,一般我们设置成 -1 ,使用所有线程。如果有需要,我们设置成多少就是用多少线程。

Booster参数

  1. n_estimator : 也作 num_boosting_rounds

    这是生成的最大树的数目,也是最大的迭代次数。

  2. learning_rate : 有时也叫作 eta ,系统默认值为 0.3 ,。

    每一步迭代的步长,很重要。太大了运行准确率不高,太小了运行速度慢。我们一般使用比默认值小一点, 0.1 左右就很好。

  3. gamma :系统默认为 0 ,我们也常用 0

    在节点分裂时,只有分裂后损失函数的值下降了,才会分裂这个节点。 gamma 指定了节点分裂所需的最小损失函数下降值。 这个参数的值越大,算法越保守。因为 gamma 值越大的时候,损失函数下降更多才可以分裂节点。所以树生成的时候更不容易分裂节点。范围: [0,∞]

  4. subsample :系统默认为 1

    这个参数控制对于每棵树,随机采样的比例。减小这个参数的值,算法会更加保守,避免过拟合。但是,如果这个值设置得过小,它可能会导致欠拟合。 典型值: 0.5-10.5 代表平均采样,防止过拟合. 范围: (0,1]注意不可取0

  5. colsample_bytree :系统默认值为1。我们一般设置成0.8左右。

    用来控制每棵随机采样的列数的占比(每一列是一个特征)。 典型值: 0.5-1 范围: (0,1]

  6. colsample_bylevel :默认为1,我们也设置为1.

    这个就相比于前一个更加细致了,它指的是每棵树每次节点分裂的时候列采样的比例

  7. max_depth : 系统默认值为 6

    我们常用 3-10 之间的数字。这个值为树的最大深度。这个值是用来控制过拟合的。 max_depth 越大,模型学习的更加具体。设置为 0 代表没有限制,范围: [0,∞]

  8. max_delta_step :默认 0 ,我们常用 0 .

    这个参数限制了每棵树权重改变的最大步长,如果这个参数的值为 0 ,则意味着没有约束。如果他被赋予了某一个正值,则是这个算法更加保守。通常,这个参数我们不需要设置,但是当个类别的样本极不平衡的时候,这个参数对逻辑回归优化器是很有帮助的。

  9. lambda :也称 reg_lambda ,默认值为 0

    权重的L2正则化项。(和Ridge regression类似)。这个参数是用来控制XGBoost的正则化部分的。这个参数在减少过拟合上很有帮助。

  10. alpha :也称 reg_alpha 默认为 0 ,

    权重的L1正则化项。(和Lasso regression类似)。 可以应用在很高维度的情况下,使得算法的速度更快。

  11. scale_pos_weight :默认为 1

    在各类别样本十分不平衡时,把这个参数设定为一个正值,可以使算法更快收敛。通常可以将其设置为负样本的数目与正样本数目的比值。

学习目标参数

objective [缺省值=reg:linear]

reg:linear
reg:logistic
binary:logistic
binary:logitraw
count:poisson
multi:softmax
multi:softprob

eval_metric [缺省值=通过目标函数选择]

rmse
mae
logloss
error
merror
mlogloss
auc
ndcg
map

一般来说,我们都会使用 xgboost.train(params, dtrain) 函数来训练我们的模型。这里的 params 指的是 booster 参数。

两种基本的实例

我们要注意的是,在xgboost中想要进行二分类处理的时候,我们仅仅在 objective 中设置成 binary ,会发现输出仍然是一堆连续的值。这是因为它输出的是模型预测的所有概率中最大的那个值。我们可以后续对这些概率进行条件处理得到最终类别,或者直接调用 xgboost 中的 XGBClassifier() 类,但这两种函数的写法不太一样。大家看我下面的例子。

import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

train_data = pd.read_csv('train.csv')   # 读取数据
y = train_data.pop('30').values   # 用pop方式将训练数据中的标签值y取出来,作为训练目标,这里的‘30’是标签的列名
col = train_data.columns   
x = train_data[col].values  # 剩下的列作为训练数据
train_x, valid_x, train_y, valid_y = train_test_split(x, y, test_size=0.333, random_state=0)   # 分训练集和验证集
train = xgb.DMatrix(train_x, train_y)
valid = xgb.DMatrix(valid_x, valid_y)   # train函数下需要传入一个Dmatrix值,具体用法如代码所示

params = {
            'max_depth': 15,
            'learning_rate': 0.1,
            'n_estimators': 2000,
            'min_child_weight': 5,
            'max_delta_step': 0,
            'subsample': 0.8,
            'colsample_bytree': 0.7,
            'reg_alpha': 0,
            'reg_lambda': 0.4,
            'scale_pos_weight': 0.8,
            'silent': True,
            'objective': 'binary:logistic',
            'missing': None,
            'eval_metric': 'auc',
            'seed': 1440,
            'gamma': 0
}    # 这里的params特指booster参数,注意这个eva_metric是评估函数

xlf = xgb.train(params, train, evals=[(valid, 'eval')], 
                num_boost_round=2000, early_stopping_rounds=30, verbose_eval=True)   
                # 训练,注意验证集的写法, 还有early_stopping写法,这里指的是30轮迭代中效果未增长便停止训练
y_pred = xlf.predict(valid_x, ntree_limit=xlf.best_ntree_limit) 
# xgboost没有直接使用效果最好的树作为模型的机制,这里采用最大树深限制的方法,目的是获取刚刚early_stopping效果最好的,实测性能可以
auc_score = roc_auc_score(valid_y, y_pred)  # 算一下预测结果的roc值

复制代码

以上是 xgboost.train() 写法,这是xgboost最原始的封装函数。这样训练我们预测输出的是一串连续值,是xgboost在这几个类别上概率最大的概率值。我们如果想要得到我们的分类结果,还需要进行其他操作。

幸运的是,xgboost为了贴合sklearn的使用,比如gridsearch这些实用工具,又开发了 XGBoostClassifier()XGBoostRegression() 两个函数。可以更加简单快捷的进行分类和回归处理。注意xgboost的sklearn包没有 feature_importance 这个量度,但是 get_fscore() 函数有相同的功能。当然,为了和sklearn保持一致,写法也发生变化,具体请看下面代码:

import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

train_data = pd.read_csv('train.csv')   # 读取数据
y = train_data.pop('30').values   # 用pop方式将训练数据中的标签值y取出来,作为训练目标,这里的‘30’是标签的列名
col = train_data.columns   
x = train_data[col].values  # 剩下的列作为训练数据
train_x, valid_x, train_y, valid_y = train_test_split(x, y, test_size=0.333, random_state=0)   # 分训练集和验证集
# 这里不需要Dmatrix

xlf = xgb.XGBClassifier(max_depth=10,
			learning_rate=0.01,
			n_estimators=2000,
			silent=True,
			objective='binary:logistic',
			nthread=-1,
			gamma=0,
			min_child_weight=1,
			max_delta_step=0,
			subsample=0.85,
			colsample_bytree=0.7,
			colsample_bylevel=1,
			reg_alpha=0,
			reg_lambda=1,
			scale_pos_weight=1,
			seed=1440,
			missing=None)
xlf.fit(train_x, train_y, eval_metric='error', verbose=True, eval_set=[(valid_x, valid_y)], early_stopping_rounds=30)
# 这个verbose主要是调节系统输出的,如果设置成10,便是每迭代10次就有输出。
# 注意我们这里eval_metric=‘error’便是准确率。这里面并没有accuracy命名的函数,网上大多例子为auc,我这里特意放了个error。
y_pred = xlf.predict(valid_x, ntree_limit=xlf.best_ntree_limit)
auc_score = roc_auc_score(valid_y, y_pred)
y_pred = xlf.predict(valid_x, ntree_limit=xlf.best_ntree_limit) 
# xgboost没有直接使用效果最好的树作为模型的机制,这里采用最大树深限制的方法,目的是获取刚刚early_stopping效果最好的,实测性能可以
auc_score = roc_auc_score(valid_y, y_pred)  # 算一下预测结果的roc值

复制代码

那么我们介绍了这么多,重点就来了:如何又快又好的调参?首先我们需要了解grid search是个什么原理。

GridSearch 简介

这是一种调参手段; 穷举搜索 :在所有候选的参数选择中,通过循环遍历,尝试每一种可能性,表现最好的参数就是最终的结果。其原理就像是在数组里找最大值。(为什么叫网格搜索?以有两个参数的模型为例,参数a有3种可能,参数b有4种可能,把所有可能性列出来,可以表示成一个3*4的表格,其中每个cell就是一个网格,循环过程就像是在每个网格里遍历、搜索,所以叫grid search)

其实这个就跟我们常用的遍历是一样的。建议大家使用sklearn里面的GridSearch函数,简洁速度快。

import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

train_data = pd.read_csv('train.csv')   # 读取数据
y = train_data.pop('30').values   # 用pop方式将训练数据中的标签值y取出来,作为训练目标,这里的‘30’是标签的列名
col = train_data.columns   
x = train_data[col].values  # 剩下的列作为训练数据
train_x, valid_x, train_y, valid_y = train_test_split(x, y, test_size=0.333, random_state=0)   # 分训练集和验证集
# 这里不需要Dmatrix

parameters = {
              'max_depth': [5, 10, 15, 20, 25],
              'learning_rate': [0.01, 0.02, 0.05, 0.1, 0.15],
              'n_estimators': [500, 1000, 2000, 3000, 5000],
              'min_child_weight': [0, 2, 5, 10, 20],
              'max_delta_step': [0, 0.2, 0.6, 1, 2],
              'subsample': [0.6, 0.7, 0.8, 0.85, 0.95],
              'colsample_bytree': [0.5, 0.6, 0.7, 0.8, 0.9],
              'reg_alpha': [0, 0.25, 0.5, 0.75, 1],
              'reg_lambda': [0.2, 0.4, 0.6, 0.8, 1],
              'scale_pos_weight': [0.2, 0.4, 0.6, 0.8, 1]

}

xlf = xgb.XGBClassifier(max_depth=10,
			learning_rate=0.01,
			n_estimators=2000,
			silent=True,
			objective='binary:logistic',
			nthread=-1,
			gamma=0,
			min_child_weight=1,
			max_delta_step=0,
			subsample=0.85,
			colsample_bytree=0.7,
			colsample_bylevel=1,
			reg_alpha=0,
			reg_lambda=1,
			scale_pos_weight=1,
			seed=1440,
			missing=None)
			
# 有了gridsearch我们便不需要fit函数
gsearch = GridSearchCV(xlf, param_grid=parameters, scoring='accuracy', cv=3)
gsearch.fit(train_x, train_y)

print("Best score: %0.3f" % gsearch.best_score_)
print("Best parameters set:")
best_parameters = gsearch.best_estimator_.get_params()
for param_name in sorted(parameters.keys()):
    print("\t%s: %r" % (param_name, best_parameters[param_name]))

复制代码

我们需要注意的是,Grid Search 需要交叉验证支持的。这里的 cv=3 ,是个int数,就代表3-折验证。实际上cv可以是一个对象,也可以是其他类型。分别代表不同的方式验证。具体的大家可看下面这段表述。

Possible inputs for cv are:
        - None, to use the default 3-fold cross-validation,
        - integer, to specify the number of folds.
        - An object to be used as a cross-validation generator.
        - An iterable yielding train/test splits.
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learn Python the Hard Way

Learn Python the Hard Way

Zed Shaw / Example Product Manufacturer / 2011

This is a very beginner book for people who want to learn to code. If you can already code then the book will probably drive you insane. It's intended for people who have no coding chops to build up t......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具