主要内容
知识点
1.GBDT
2.xgboost的核心算法
3.GBDT和xgboost的区别数据分析和参数调优过程
一、 简要说明
二、 数据分析
三、 调参前的一些说明
四、 使用 GridSearchCV调参
五、 进一步调参
六、结果汇总
知识点:
1.GBDT
(1)先提一下GBDT算法,因为xgboost本质上还是一个GBDT,但是比起GBDT,xgboost力争把速度和效率发挥到极致。
(2)GBDT算法:第一个分类器是预测出数据的结果,然后下一个弱分类器是用损失函数的负梯度来近似残差(残差:实际值与预测值之差),之后的弱学习器都是用残差去拟合预测结果,所有弱分类器的结果相加等于预测值。弱分类器的表现形式是各棵树。
2.xgboost的核心算法
(1)不断地添加树,不断地进行特征分裂来生长一棵树(即二叉树),每次添加一个树,其实是学习一个新函数,去拟合上次预测的残差。
(2)当我们训练完成得到k棵树,我们要预测一个样本的分数,其实就是根据这个样本的特征,在每棵树中会落到对应的一个叶子节点,每个叶子节点就对应一个分数
(3)最后只需要将每棵树对应的分数加起来就是该样本的预测值。
3.GBDT和xgboost的区别
二者较大的不同就是目标函数的定义,xgboost的目标函数引入了泰勒展开式,使得其最终的目标函数只依赖于每个数据点在误差函数上的一阶导数和二阶导数。
详细了解:通俗理解kaggle比赛大杀器xgboost
数据分析和参数调优过程
一、简要说明
1.任务类型:回归
2.背景介绍:
公共自行车低碳、环保、健康,并且解决了交通中“最后一公里”的痛点,在全国各个城市越来越受欢迎。本练习赛的数据取自于两个城市某街道上的几处公共自行车停车桩。我们希望根据时间、天气等信息,预测出该街区在一小时内的被借取的公共自行车的数量。
3.标杆模型
该模型预测结果的RMSE为:18.947
# -*- coding: utf-8 -*-
# 引入模块
from xgboost import XGBRegressor
import pandas as pd
# 读取数据
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
submit = pd.read_csv("sample_submit.csv")
# 删除id
train.drop('id', axis=1, inplace=True)
test.drop('id', axis=1, inplace=True)
# 取出训练集的y
y_train = train.pop('y')
# 建立一个默认的xgboost回归模型
reg = XGBRegressor()
reg.fit(train, y_train)
y_pred = reg.predict(test)
# 输出预测结果至my_XGB_prediction.csv
submit['y'] = y_pred
submit.to_csv('my_XGB_prediction.csv', index=False)
4.变量说明
二、数据分析
1.查看数据是否有缺失值
import pandas as pd
# 读取数据
train = pd.read_csv(r"D:\m\sofasofa\train.csv")
test = pd.read_csv(r"D:\m\sofasofa\test.csv")
submit = pd.read_csv(r"D:\m\sofasofa\sample_submit.csv")
print(train.info())
info()函数说明:
功能:用于给出样本数据的相关信息概览 :行数,列数,列索引,列非空值个数,列类型,内存占用
使用格式:data.info()
详细了解:https://blog.csdn.net/Dreamer_rx/article/details/100804378」
可以看到,有10000个观测值,没有缺失值
2.观察每个变量的基础描述信息
import pandas as pd
# 读取数据
train = pd.read_csv(r"D:\m\sofasofa\train.csv")
test = pd.read_csv(r"D:\m\sofasofa\test.csv")
submit = pd.read_csv(r"D:\m\sofasofa\sample_submit.csv")
print(train.describe())
describe()函数说明:
功能:直接给出样本数据的一些基本的统计量,包括均值,标准差,最大值,最小值,分位数等。
使用格式:data.describe()
详细了解:https://blog.csdn.net/Dreamer_rx/article/details/100804378
3.离群点分析
通过画出特征的箱线图来分析是否存在离群点。
箱线图了解:https://blog.csdn.net/uinglin/article/details/79895993
import pandas as pd
import seaborn as sn
import matplotlib.pyplot as plt
# 读取数据
train = pd.read_csv(r"D:\m\sofasofa\train.csv")
test = pd.read_csv(r"D:\m\sofasofa\test.csv")
submit = pd.read_csv(r"D:\m\sofasofa\sample_submit.csv")
fig, axes = plt.subplots(nrows=3,ncols=2) #画出 3*2=6 个子图
fig.set_size_inches(12, 10) #设置图的大小
sn.boxplot(data=train, y="y", orient="v", ax=axes[0][0]) #axes[0][0]表示子图的坐标或者位置
sn.boxplot(data=train, y="y", x="city", orient="v", ax=axes[0][1])
sn.boxplot(data=train, y="y", x="hour", orient="v", ax=axes[1][0])
sn.boxplot(data=train, y="y", x="is_workday", orient="v", ax=axes[1][1])
sn.boxplot(data=train, y="y", x="weather", orient="v", ax=axes[2][0])
sn.boxplot(data=train, y="y", x="wind", orient="v", ax=axes[2][1])
axes[0][0].set(ylabel='bike',title="Box Plot On bike")
axes[0][1].set(xlabel='city', ylabel='bike',title="Box Plot On bike Across city")
axes[1][0].set(xlabel='Hour Of The Day', ylabel='bike',title="Box Plot On bike Across Hour Of The Day")
axes[1][1].set(xlabel='is_workday', ylabel='bike',title="Box Plot On bike Across is_workday")
axes[2][0].set(xlabel='weather', ylabel='bike',title="Box Plot On bike Across Hour Of weather")
axes[2][1].set(xlabel='wind', ylabel='bike',title="Box Plot On bike Across wind")
plt.show()
为什么不描绘出temp_1和temp_2的箱线图呢?
(weathher:1为晴朗,2为多云、阴天,3为轻度降水天气,4为强降水天气)
y轴count包括很多超过上警戒线的离群点,还有以下结论:
(1)"weather"的箱线图:从中位数线可以看出,当weather=3,4的时候(3为轻度降水天气,4为强降水天气),频数较低,这和我们的常识相符吧,下雨骑单车的人会较少
(2)"Hour Of The Day"的箱线图:中位数在早7点-8点,晚5点-6点较高。这两个时间段正值上学放学、上班下班高峰期。
(3)"is_workday"的箱线图**:大多数离群点来自1,也就是"Working Day"而非"Non Working Day".
4.删除离群点
将y(即单车使用量)减去y的平均数,并将该差值大于3倍y的标准差的点作为离群点删去,小于的留下来,之所以这样界定离群点,应该跟正态分布类似,因为差值大于3倍标准差的数据的出现概率很小
import pandas as pd
import numpy as np
# 读取数据
train = pd.read_csv(r"D:\m\sofasofa\train.csv")
test = pd.read_csv(r"D:\m\sofasofa\test.csv")
submit = pd.read_csv(r"D:\m\sofasofa\sample_submit.csv")
#删去离群点
train_without_outliers = train[np.abs(train["y"]-train["y"].mean())<=(3*train["y"].std())] # np.mean():求均值 np.std():求标准差
# 查看删除离群点前 后 共有多少条数据
print("Shape Of The Before Ouliers: ",train.shape) # np.shape():功能是查看矩阵或者数组的维数。c.shape[1] 为第一维的长度(即多少列),c.shape[0] 为第二维的长度(即多少行)。
print("Shape Of The After Ouliers: ",train_without_outliers.shape)
运行结果:
5.相关性分析
分析变量之间的关系,特别是因变量公共自行车的使用数量受哪些特征影响,剔除一些相关性比较微弱的特征。为此,我们作y关于["city","hour","is_workday","weather","temp_1","temp_2","wind"]的关系热力图,从图中我们可以直接看出变量之间相关性的强弱
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sn
# 读取数据
train = pd.read_csv(r"D:\m\sofasofa\train.csv")
test = pd.read_csv(r"D:\m\sofasofa\test.csv")
submit = pd.read_csv(r"D:\m\sofasofa\sample_submit.csv")
#绘制关系热力图
corrMatt = train[["city","hour","is_workday","weather","temp_1","temp_2","wind","y"]].corr()
mask = np.array(corrMatt)
mask[np.tril_indices_from(mask)] = False
fig,ax= plt.subplots()
fig.set_size_inches(20,10)
sn.heatmap(corrMatt, mask=mask,vmax=0.8, square=True,annot=True)
plt.show()
运行结果:
由于这个结果是根据没有剔除前面分析的离群点得到的,看到公共自行车使用数量y与是否是工作日is_workday的相关系数只有0.029的时候,我在想会不会把离群点删去,得到的相关系数会有改变,因为运行之前觉得y与is_workday应该有一定程度的相关关系。然后我将数据删去离群点再运行了一次,发现结果是一样的,可能是离群点相较训练集而言,所占比重比较小,对变量之间的相关性影响不大。
由结果可以得到以下结论:
(1)hour, temp_1, temp_2 与y 存在弱的正相关关系,wind与y存在较弱的正相关关系,city, weather与y存在较弱的负相关关系。
(2)is_workday 与 y几乎没有相关性,可以考虑删去这个特征。
(3)“temp_1” and "temp_2"具有强烈的相关性。这和我们的常识相符,天气气温和我们感受到的温度接近,这两个预测变量存在强共线性,应该考虑删去一个。
6.删除一些相关性较弱的特征
#删掉一些相关性比较弱的特征
dropFeatures = ['temp_2',"is_workday"]
train = train.drop(dropFeatures,axis=1)
test = test.drop(dropFeatures,axis=1)
这里只删除了temp_2和相关性非常微弱(只有0.029)的is_wokday
三、调参前的一些说明
1.进行调优xgboost的几个参数说明:
(1) learning rate :每一步迭代的步长(或权重),该值太大,运行准确率不高,该值太小,运行速度慢。通过减少每一步的权重,可以提高模型的鲁棒性。 典型值为0.01-0.2。
(2)min_child_weight : 决定最小叶子节点样本权重和,这个参数用于避免过拟合,当它的值较大时,可以避免模型学习到局部的特殊样本。 但是如果这个值过高,会导致欠拟合。
(3)max_depth:树的最大深度,这个值也是用来避免过拟合的。参数范围常为:3-10
(4)gamma:在节点分裂时,只有分裂后损失函数的值下降了,才会分裂这个节点。Gamma指定了节点分裂所需的最小损失函数下降值。 这个参数的值越大,算法越保守。
(5)subsample:这个参数控制对于每棵树随机采样的比例。 减小这个参数的值,算法会更加保守,避免过拟合。但如果这个值设置得过小,可能会导致欠拟合。参数范围常为:0.5-1
(6)colsample_bytree : 用来控制每棵随机采样的列数的占比(每一列是一个特征)。参数范围常为:0.5-1
(7)reg_alpha:权重的L1正则化项。 可以应用在很高维度的情况下,使得算法的速度更快。
(8)reg_lambda:权重的L2正则化项。 这个参数是用来控制XGBoost的正则化部分的。
详细了解:xgboost的参数
2.gridSearchCV的一些参数和属性介绍
(1)estimator:选择使用的分类器,并且传入除需要确定最佳的参数之外的其他参数
(2)param_grid:需要最优化的参数的取值,值为字典或者列表,例如:param_grid =param_test1,param_test1 {'n_estimators':range(10,71,10)}。
(3)iid:默认True,为True时各个样本fold概率分布一致,误差估计为所有样本之和,而非各个fold的平均。
(4)cv:交叉验证参数,默认为None,使用3折。可指定数量。
(5)best_score_:提供优化过程期间观察到的最好的评分
(6)best_params_:描述已取得最佳结果的参数(组合)
其余参数和方法:gridSearchCV(网格搜索)的参数、方法及示例
3.调参过程中会用到一个工具:gridSearchCV(网格搜索),它的作用是自动调参,只要把参数输进去,就能给出最优化的结果和参数。但是这个方法适合于小数据集。
4.设置一些参数的初始值(可以设置不同的值):
(1)learning_rate = 0.1
(2)max_depth = 5 :这个参数的取值最好在3-10之间。选的起始值为5,也可以选择其它的值。起始值在4-6之间都是不错的选择。
(3)min_child_weight = 1
(4)gamma = 0
(5)subsample,colsample_bytree = 0.8
(6)scale_pos_weight = 1
(7)iid=False,
(8)cv=5
5.参数调优的一般方法。
- 选择较高的学习速率(learning rate)。一般情况下,学习速率的值为0.1。但是,对于不同的问题,理想的学习速率有时候会在0.05到0.3之间波动。选择对应于此学习速率的理想决策树数量。
- 对于给定的学习速率和决策树数量,进行决策树特定参数调优(max_depth, min_child_weight, gamma, subsample, colsample_bytree)。
- xgboost的正则化参数的调优。(reg_lambda, reg_alpha)。这些参数可以降低模型的复杂度,从而提高模型的表现。
- 降低学习速率,确定理想参数
四、使用 GridSearchCV调参
1.首先根据已经确定的learning_rate,调对应的n_estimators(决策树数量)
(1)对删去离群点和无用特征后的数据进行参数调优
from xgboost import XGBRegressor
from sklearn.model_selection import GridSearchCV
import pandas as pd
import numpy as np
# 读取数据
train = pd.read_csv(r"D:\m\sofasofa\train.csv")
test = pd.read_csv(r"D:\m\sofasofa\test.csv")
submit = pd.read_csv(r"D:\m\sofasofa\sample_submit.csv")
# 删除id
train.drop('id', axis=1, inplace=True)
test.drop('id', axis=1, inplace=True)
#删去离群点
train_without_outliers = train[np.abs(train["y"]-train["y"].mean())<=(3*train["y"].std())] # np.mean():求均值 np.std():求标准差
#删掉一些相关性比较弱的特征
dropFeatures = ['temp_2',"is_workday"]
train = train.drop(dropFeatures,axis=1)
test = test.drop(dropFeatures,axis=1)
# 取出训练集的y
y_train = train.pop('y')
param_test1 = {
'n_estimators': range(100, 1000, 50)
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, max_depth=5,
min_child_weight=1, gamma=0, subsample=0.8, colsample_bytree=0.8,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'n_estimators': 100} 0.7464271268024434
可以看出,算法的得分比较低
(2)考虑把与公共自行车使用量y的相关系数在0.1左右的特征剔除,剔除离群点的同时剔除"city", "is_workday", "weather", "wind","temp_2"这些特征,继续调 n_estimators的值
from xgboost import XGBRegressor
from sklearn.model_selection import GridSearchCV
import pandas as pd
import numpy as np
# 读取数据
train = pd.read_csv(r"D:\m\sofasofa\train.csv")
test = pd.read_csv(r"D:\m\sofasofa\test.csv")
submit = pd.read_csv(r"D:\m\sofasofa\sample_submit.csv")
# 删除id
train.drop('id', axis=1, inplace=True)
test.drop('id', axis=1, inplace=True)
#删去离群点
train_without_outliers = train[np.abs(train["y"]-train["y"].mean())<=(3*train["y"].std())] # np.mean():求均值 np.std():求标准差
#删掉一些相关性比较弱的特征
dropFeatures = ['city','is_workday','weather','wind','temp_2']
train = train.drop(dropFeatures,axis=1)
test = test.drop(dropFeatures,axis=1)
# 取出训练集的y
y_train = train.pop('y')
param_test1 = {
'n_estimators': range(100, 1000, 50)
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, max_depth=5,
min_child_weight=1, gamma=0, subsample=0.8, colsample_bytree=0.8,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'n_estimators': 100} 0.6238675776837738
可以看到得分更低了
(3)考虑不对数据进行任何处理,直接调参:
from xgboost import XGBRegressor
from sklearn.model_selection import GridSearchCV
import pandas as pd
# 读取数据
train = pd.read_csv(r"D:\m\sofasofa\train.csv")
test = pd.read_csv(r"D:\m\sofasofa\test.csv")
submit = pd.read_csv(r"D:\m\sofasofa\sample_submit.csv")
# 删除id
train.drop('id', axis=1, inplace=True)
test.drop('id', axis=1, inplace=True)
# 取出训练集的y
y_train = train.pop('y')
param_test1 = {
'n_estimators': range(100, 1000, 50)
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, max_depth=5,
min_child_weight=1, gamma=0, subsample=0.8, colsample_bytree=0.8,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'n_estimators': 200} 0.903184767739565
在上面的调试过程中发现:对数据进行处理后调参,算法的得分很低,不对数据做任何处理进行调参,得分高了挺多。可能是因为这些数据已经经过清洗了,需要处理的地方比较少。虽然有些特征与因变量的相关程度很低,但是可能删去这些特征后,数据的特征较少,更不利于算法进行预测。所以下面的调参过程用的数据都是原始数据
2.调参数:max_depth 和min_child_weight
先对这两个参数调优,是因为它们对最终结果有很大的影响。
(1)大范围地调
param_test1 = {
'max_depth': range(3, 10, 2),
'min_child_weight': range(1, 6, 2)
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.05, n_estimators=2500,
gamma=0, subsample=0.8, colsample_bytree=0.8,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'max_depth': 5, 'min_child_weight': 5} 0.9033017174911162
得分高了一点
(2)小范围地微调
可以看到理想的max_depth值为5,理想的min_child_weight值为5。在这个值附近可以再进一步调整,来找出理想值。把上下范围各拓展1,因为之前进行组合的时候,参数调整的步长是2。
param_test1 = {
'max_depth': [4, 5, 6],
'min_child_weight': [4, 5, 6]
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, n_estimators=200,
gamma=0, subsample=0.8, colsample_bytree=0.8,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:{'max_depth': 6, 'min_child_weight': 5} 0.9037898616664826
可以看到,得分有所上升
3.gamma参数调优
在已经调整好其它参数的基础上,就可以进行gamma参数的调优了,这里对gamma设置的取值范围比较小,也可以设其它范围。
param_test1 = {
'gamma':[i / 20.0 for i in range(0, 11)]
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth= 6,
min_child_weight=5, subsample=0.8, colsample_bytree=0.8,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'gamma': 0.5} 0.9041761291614719
4.调整subsample 和 colsample_bytree 参数
param_test1 = {
'subsample': [i / 10.0 for i in range(5, 10)],
'colsample_bytree': [i / 10.0 for i in range(5, 10)]
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth= 6,
min_child_weight=5, gamma=0.5,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'colsample_bytree': 0.8, 'subsample': 0.8} 0.9041761291614719
5.调正则化参数 reg_alpha 和 reg_lambda
param_test1 = {
'reg_alpha': [0, 0.001, 0.005, 0.01, 0.05, 0.1],
'reg_lambda': [0.05, 0.1, 0.5, 1, 1.5, 2, 2.5, 3]
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth=6, min_child_weight=5,
gamma=0.5, subsample=0.8, colsample_bytree=0.8,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'reg_alpha': 0.1, 'reg_lambda': 3} 0.9048829604868451
第一次提交:RMSE为15.042
from xgboost import XGBRegressor
import pandas as pd
# 读取数据
train = pd.read_csv(r"D:\m\sofasofa\train.csv")
test = pd.read_csv(r"D:\m\sofasofa\test.csv")
submit = pd.read_csv(r"D:\m\sofasofa\sample_submit.csv")
# 删除id
train.drop('id', axis=1, inplace=True)
test.drop('id', axis=1, inplace=True) #删除id那一列, 并在原来的数据上改变
# 取出训练集的y
y_train = train.pop('y')
reg = XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth=6,
min_child_weight=5, gamma=0.5, subsample=0.8, colsample_bytree=0.8,
reg_alpha=0.1, reg_lambda=3, nthread=4, scale_pos_weight=1, seed=27)
reg.fit(train, y_train)
y_pred = reg.predict(test)
#输出预测结果至my_LR_prediction.csv
submit['y'] = y_pred
submit.to_csv('my_LR_prediction.csv', index=False)
五、进一步调参
1.继续对正则化参数进行调优
(1)由于前面在对正则化参数reg_alpha 和 reg_lambda进行调优的过程中,给这2个参数设置的范围太小,所以考虑给reg_alpha 和 reg_lambda一个大一点的范围,继续调优
param_test1 = {
'reg_alpha': [1e-5, 1e-2, 0.1, 1, 100],
'reg_lambda': [1e-5, 1e-2, 0.1, 1, 100]
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth=6, min_child_weight=5,
gamma=0.5, subsample=0.8, colsample_bytree=0.8,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:{'reg_alpha': 100, 'reg_lambda': 1} 0.906035918446076
(2)缩小范围,继续调 reg_alpha'和reg_lambda
param_test1 = {
'reg_alpha': range(0, 110, 10),
'reg_lambda': [i / 10.0 for i in range(0, 11)]
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth=6, min_child_weight=5,
gamma=0.5, subsample=0.8, colsample_bytree=0.8,
nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'reg_alpha': 90, 'reg_lambda': 0.6} 0.9063725963693422
可以看到得分是目前最高的
提交结果,得到的RMSE为15.083,误差反而比前一次更大了,这可能是由于reg_alpha的值调得太大了,reg_alpha的值越大,越不容易过拟合。但是太大可能会导致算法欠拟合,泛化能力不高(这个说法只是个人推测,可能错误)
2.降低learning_rate,增加对应learning_rate下生成树的数量n_estimators。由于第二次调得的参数可能使算法欠拟合,所以可以考虑增加树的数量n_estimators
(1)令learning_rate = 0.05
param_test1 = {
'n_estimators': range(1000, 5000, 500)
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.05, max_depth=6,
min_child_weight=5, gamma=0.5, subsample=0.8, colsample_bytree=0.8,
reg_alpha=90, reg_lambda=0.6, nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'n_estimators': 1000} 0.9044943682927349
考虑进一步微调n_estimators的值,将其范围设在1000上下
param_test1 = {
'n_estimators': range(100, 1500, 50)
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.05, max_depth=6,
min_child_weight=5, gamma=0.5, subsample=0.8, colsample_bytree=0.8,
reg_alpha=90, reg_lambda=0.6, nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'n_estimators': 350} 0.906418990131387
(2)进一步缩小learning_rate的值,令learning_rate = 0.01
param_test1 = {
'n_estimators': range(1000, 5000, 500)
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.01, max_depth=6,
min_child_weight=5, gamma=0.5, subsample=0.8, colsample_bytree=0.8,
reg_alpha=90, reg_lambda=0.6, nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'n_estimators': 2000} 0.9066264768539061
3.由于第一次调gamma的值的时候,设置的范围太小,而gamma值的范围为:0到正无穷,所以考虑将gamma值的范围设置得大一点
param_test1 = {
'gamma':[0,1,2,3,4,5,6,7,8,9]
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.01, n_estimators=2000, max_depth=6,
min_child_weight=5, subsample=0.8, colsample_bytree=0.8,
reg_alpha=90, reg_lambda=0.6, nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:{'gamma': 5} 0.9066822275408573
缩小gamma的范围,继续微调gamma
param_test1 = {
'gamma':[i / 10.0 for i in range(41, 60)]
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.01, n_estimators=2000, max_depth=6,
min_child_weight=5, subsample=0.8, colsample_bytree=0.8,
reg_alpha=90, reg_lambda=0.6, nthread=4, scale_pos_weight=1, seed=27),
param_grid=param_test1, iid=False, cv=5)
gsearch1.fit(train, y_train)
print(gsearch1.best_params_, gsearch1.best_score_)
运行结果:
{'gamma': 5.0} 0.9066822275408573
其实我有一个疑问就是调参一定要按一定的顺序调吗,可以别的参数都调完再返回去调gamma的值吗,所以下面我试了按照前面的顺序从头开始调,但是在调gamma的值的时候,把范围扩大了一点再微调,看看结果会不会不同,结果如下:
提交
提交
可以看出14.852和前面的14.853相差不大,可能调gamma值的顺序对误差值的影响不大
六、结果汇总
目前调到最低的RMSE的值是14.852,比原来降低了4.095,排名50。以上文章有错误之处,欢迎指出
在调参的时候我有一个问题,因为是一个一个或者一组一组地调参,寻找最优的参数,那怎么能够保证这些调得最优参数的值组合起来也是最优的呢? 然后在网上看到一个挺好的回答:
→这样虽然不是最优,但可以达到局部最优,节约了很多时间。前提是对参数的分组要做好,尽可能使组间参数相互独立。 或者换个角度想,我们是不可能做到遍历所有的参数组合的,我们要做的是在有限的时间内找到尽可能最优的参数组合。在同样的时间内,分组调参的参数范围可以比单个组合大得多。效果未必会比单个组合差。
上面的回答来自于XGBoost参数调优完全指南(附Python代码) 的评论区
除了上面提及的链接,本文还参考了:
1.数据竞赛实战(3)——公共自行车使用量预测
2.sofasofa竞赛:一 公共自行车使用量预测
3.共享单车需求预测问题:分析篇
4 共享单车需求预测问题:建模篇
5 XGBoost参数调优完全指南(附Python代码)