在Hyperopt框架下使用XGboost与交叉验证

H y p e r o p t   t u t o r i a l s : X g b o o s t + C V Hyperopt \ tutorials: Xgboost + CV Hyperopt tutorialsXgboost+CV

前言

Xgboost中内置了交叉验证,如果我们需要在Hyperopt中使用交叉验证的话,只需要直接调用即可。前边我们依旧采用第一篇教程使用过的代码。如果你已经看过前一篇文章,那么我建议你直接跳到交叉验证部分。

第一篇教程-如何使用hyperopt对xgboost进行自动调参相同的是,本处教程中的代码也可以很好的被套用。并且可以很好的迁移到lightgbm与catboost上面。源代码请前往Github教程地址下载下载。

加载数据

读取数据并分割

因为我们这里使用的是交叉验证因此我们也就不再需要,将数据集分割为三份了,只需要分割出百分之十的数据用于预测就好。注意随机数的问题。

from hyperopt import fmin, tpe, hp, partial
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import mean_squared_error, zero_one_loss
import xgboost as xgb
import pandas as pd

def GetNewDataByPandas():
    wine = pd.read_csv("../data/wine.csv")
    wine['alcohol**2'] = pow(wine["alcohol"], 2)
    wine['volatileAcidity*alcohol'] = wine["alcohol"] * wine['volatile acidity']
    y = np.array(wine.quality)
    X = np.array(wine.drop("quality", axis=1))

    columns = np.array(wine.columns)

    return X, y, columns

分割数据并转换

首先将数据分割为三份,一部分用于预测,训练数据则同样分成额外的两部分用于evallist参数。

同时为了加快速度和减少内存,我们将数据转换为xgboost自带的读取格式。

# Read wine quality data from file
X, y, wineNames = GetNewDataByPandas()

# split data to [[0.8,0.2],01]
x_train_all, x_predict, y_train_all, y_predict = train_test_split(X, y, test_size=0.10, random_state=100)

x_train, x_test, y_train, y_test = train_test_split(x_train_all, y_train_all, test_size=0.2, random_state=100)

dtrain = xgb.DMatrix(data=x_train,label=y_train,missing=-999.0)
dtest = xgb.DMatrix(data=x_test,label=y_test,missing=-999.0)

evallist = [(dtest, 'eval'), (dtrain, 'train')]

利用交叉验证训练

训练模型

在之前的代码中,我将数据分割为 6:3:1,其分别为,训练数据,性能监视用数据,和最后的预测数据。这个比例只是为了示例用,并不具有代表性。

本处则主要介绍交叉验证方法。

交叉验证与Hyperopt结合

xgboost进行交叉验证与Hyperopt结合有两种方案,第一种方案是使用本身自带的CV方法,但是这种方案的存在一个问题,就是CV中无法直接传递分开的参数,而只能传递唯一参数params,因此我们需要先生成一个model,然后通过get_params()来获取参数,这种方式代码会稍微多几行。不过相较于与sklearn结合的形式,计算时间上则有很大的提升。

第二种方案:也可以直接使用sklearn.model_selection中的多种交叉验证方案,只将xgboost作为单个模型传入。但是个人并不建议这样做。首先是和sklearn的交互会一定程度上导致计算性能的下降,而且计算时间上差距可能会很大。所以个人建议只有在必要的时候,可以采用最传统的train_test_split方案时使用类似的代码结构,但是还是不适用和sklearn结合形式的交叉验证,具体怎么做会在其他例子中介绍。

使用CV方法进行交叉验证

直接使用xgboost中的cv方法进行交叉验证应该是最好的方案。唯一的问题是如何传入唯一的params参数。不知道为什么在我翻译玩hyperopt中文文档的这近一年,都没有见到有人写这一类的。有可能是没想到如何解决吧这个问题吧。

import hyperopt

def hyperopt_objective(params):
    
    model = xgb.XGBRegressor(
        max_depth=int(params['max_depth'])+5,
        learning_rate=params['learning_rate'],
        silent=1,
        objective='reg:linear',
        eval_metric='rmse',
        seed=619,
        nthread=-1,
    )
     
    res = xgb.cv(model.get_params(), dtrain, num_boost_round=10, nfold=5,
             callbacks=[xgb.callback.print_evaluation(show_stdv=False),
                        xgb.callback.early_stop(3)])
    
    return np.min(res['test-rmse-mean']) # as hyperopt minimises
from numpy.random import RandomState

params_space = {
    'max_depth': hyperopt.hp.randint('max_depth', 6),
    'learning_rate': hyperopt.hp.uniform('learning_rate', 1e-3, 5e-1),
}

trials = hyperopt.Trials()

best = hyperopt.fmin(
    hyperopt_objective,
    space=params_space,
    algo=hyperopt.tpe.suggest,
    max_evals=50,
    trials=trials,
    rstate=RandomState(123)
)

print("\n展示hyperopt获取的最佳结果,但是要注意的是我们对hyperopt最初的取值范围做过一次转换")
print(best)
[0]	train-rmse:3.24774	test-rmse:3.24823
Multiple eval metrics have been passed: 'test-rmse' will be used for early stopping.

Will train until test-rmse hasn't improved in 3 rounds.
[1]	train-rmse:2.07359	test-rmse:2.0891
[2]	train-rmse:1.36012	test-rmse:1.40987
[3]	train-rmse:0.928331	test-rmse:1.02378
[4]	train-rmse:0.657333	test-rmse:0.827554
[5]	train-rmse:0.488443	test-rmse:0.732572
[6]	train-rmse:0.382361	test-rmse:0.690592
[7]	train-rmse:0.310456	test-rmse:0.669706
[8]	train-rmse:0.257609	test-rmse:0.661822
[9]	train-rmse:0.216769	test-rmse:0.657073
[0]	train-rmse:3.09603	test-rmse:3.09669
Multiple eval metrics have been passed: 'test-rmse' will be used for early stopping.

...

[5]	train-rmse:0.511304	test-rmse:0.670014
[6]	train-rmse:0.473608	test-rmse:0.65754
[7]	train-rmse:0.450189	test-rmse:0.647339
[8]	train-rmse:0.428634	test-rmse:0.642954
[9]	train-rmse:0.410831	test-rmse:0.64032

展示hyperopt获取的最佳结果,但是要注意的是我们对hyperopt最初的取值范围做过一次转换
{'learning_rate': 0.44307009444016143, 'max_depth': 0}

使用sklearn进行交叉验证

这里要注意的是运算速度上也是有一定差距的。而且可能很大。本例运行于我个人的笔记本(i7-5500u,Ubuntu18.04)时候,与sklearn结合的方案用时约是完全使用xgboost的3-6倍,而在我的另外一个系统上(i7-8750H,windows10),与sklearn结合的版本则只是xgboost的45%的运行时间。计算时间差异,也可能是由数据集的大小和硬件等多种原因造成的,因此具体情况建议自行实验。我在这里也很难给出一个较准确的答案。

def XGBRegressor_CV(params):
    from sklearn.model_selection import cross_val_score
    
    model = xgb.XGBRegressor(
        max_depth=int(params['max_depth'])+5,
        learning_rate=params['learning_rate'],
        silent=1,
        objective='reg:linear',
        eval_metric='rmse',
        seed=619,
        nthread=-1,
        early_stopping_rounds=3
    )

#     x_train, x_predict, y_train, y_predict
    metric = cross_val_score(model, x_train, y_train, cv=5, scoring="neg_mean_squared_error")

    return min(-metric)
trials_2 = hyperopt.Trials()

best_2 = hyperopt.fmin(
    XGBRegressor_CV,
    space=params_space,
    algo=hyperopt.tpe.suggest,
    max_evals=50,
    trials=trials_2,
    rstate=RandomState(123)
)

print("\n展示hyperopt获取的最佳结果,但是要注意的是我们对hyperopt最初的取值范围做过一次转换")
print(best_2)
展示hyperopt获取的最佳结果,但是要注意的是我们对hyperopt最初的取值范围做过一次转换
{'learning_rate': 0.06047936704428278, 'max_depth': 4}
  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
Hyperopt是一个Python库,用于使用贝叶斯优化算法来调整机器学习模型的超参数。下面是Hyperopt在调整XGBoost超参数时的步骤: 1. 定义参数空间:首先需要定义需要调整的超参数以及其取值范围。例如,可以使用Uniform分布来定义连续型参数的取值范围,使用qUniform分布来定义整数型参数的取值范围。 2. 定义评估函数:评估函数是用来计算模型的性能指标的,例如准确率、AUC等。在每次迭代中,Hyperopt会根据当前超参数的取值调用评估函数来计算模型的性能指标。 3. 定义搜索算法:Hyperopt支持多种搜索算法,例如随机搜索、贝叶斯优化等。在这里,我们选择使用贝叶斯优化算法。 4. 运行优化器:定义好参数空间、评估函数和搜索算法后,就可以运行Hyperopt的优化器来寻找最优超参数组合了。在每次迭代中,Hyperopt会根据当前的超参数取值计算模型的性能指标,并根据贝叶斯优化算法来更新超参数的取值,直到达到预设的最大迭代次数或收敛为止。 下面是一个使用Hyperopt优化XGBoost超参数的示例代码: ```python from hyperopt import fmin, tpe, hp from sklearn.datasets import load_boston from sklearn.metrics import mean_squared_error from sklearn.model_selection import train_test_split import xgboost as xgb # 加载数据集 data = load_boston() X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.2, random_state=42) # 定义参数空间 space = { 'max_depth': hp.quniform('max_depth', 3, 10, 1), 'learning_rate': hp.loguniform('learning_rate', -5, 0), 'n_estimators': hp.quniform('n_estimators', 50, 200, 1), 'min_child_weight': hp.quniform('min_child_weight', 1, 10, 1), 'subsample': hp.uniform('subsample', 0.5, 1), 'gamma': hp.uniform('gamma', 0, 1), 'colsample_bytree': hp.uniform('colsample_bytree', 0.5, 1), 'reg_alpha': hp.uniform('reg_alpha', 0, 1), 'reg_lambda': hp.uniform('reg_lambda', 0, 1), } # 定义评估函数 def objective(params): model = xgb.XGBRegressor(**params) model.fit(X_train, y_train) y_pred = model.predict(X_test) mse = mean_squared_error(y_test, y_pred) return mse # 定义搜索算法 algo = tpe.suggest # 运行优化器 best = fmin(fn=objective, space=space, algo=algo, max_evals=100) print(best) ``` 在这个示例中,我们使用Hyperopt库来优化XGBoost回归模型的超参数。我们首先加载了Boston房价数据集,并将其分成训练集和测试集。然后,我们定义了需要调整的超参数以及其取值范围,并定义了评估函数。最后,我们选择使用tpe.suggest算法来搜索最优超参数,并将最优超参数打印出来。 需要注意的是,由于贝叶斯优化算法是一种启发式算法,因此在每次运行时得到的最优超参数可能会有所不同。因此,为了确保得到的结果是稳定的,通常需要运行多次优化器并取平均值。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Font Tian

写的很好,请给我钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值