本次数据取自于两个城市某街道上的几处公共自行车停车桩。我们希望根据时间、天气等信息,预测出该街区在一小时内的被借取的公共自行车的数量。
一、我们为什么要使用XGboost?
一、1、XGBoost的优势
XGBoost算法可以给预测模型带来能力的提升。他有很多的优势:
一、2、正则化
• 标准GBM的实现没有像XGBoost这样的正则化步骤。正则化对减少过拟合也是有帮助的。
• 实际上,XGBoost以“正则化提升(regularized boosting)”技术而闻名。
一、3、并行处理
• XGBoost可以实现并行处理,相比GBM有了速度的飞跃。
一、4、高度的灵活性
• XGBoost 允许用户定义自定义优化目标和评价标准
• 它对模型增加了一个全新的维度,所以我们的处理不会受到任何限制。
一、5、缺失值处理
• XGBoost内置处理缺失值的规则。
• 用户需要提供一个和其它样本不同的值,然后把它作为一个参数传进去,以此来作为缺失值的取值。XGBoost在不同节点遇到缺失值时采用不同的处理方法,并且会学习未来遇到缺失值时的处理方法。
一、6、剪枝
• 当分裂时遇到一个负损失时,GBM会停止分裂。因此GBM实际上是一个贪心算法。
• XGBoost会一直分裂到指定的最大深度(max_depth),然后回过头来剪枝。如果某个节点之后不再有正值,它会去除这个分裂。
• 这种做法的优点,当一个负损失(如-2)后面有个正损失(如+10)的时候,就显现出来了。GBM会在-2处停下来,因为它遇到了一个负值。但是XGBoost会继续分裂,然后发现这两个分裂综合起来会得到+8,因此会保留这两个分裂。
二、xgboost的目标函数
目标函数有两部分构成,第一就是损失函数,第二是正则项。
目标函数如下:
其中损失函数:
正则项:
T表示第K棵决策树中叶子节点的个数,w为该棵决策树叶子节点的预测值。
在XGboost模型中,涉及到的参数有:
变量:id,city,hour,is_workday,weather,temp_1,temp_2,wind,y
id:编号
city:该行记录所发生的城市,共有两个城市
hour:当时的时间(小时)
is_workday:1表示工作日,0表示节假日或者周末
temp_1:当时的气温(摄氏度)
temp_2:当时的体感温度(摄氏度)
weather:当时的天气状况,1为晴朗,2为多云、阴天,3为轻度降水天气,4为强降水天气
wind:当时的风速,数值越大表示风速越大
y:一小时内自行车被借取的数量,即需要被预测的数值。
评价方法:
初始代码:
# -*- coding: utf-8 -*-
# 引入模块
from xgboostimport XGBRegressor
import pandasas 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)
那么,代码有了,数据有了。我们应该如何提高准确率呢?
一、数据预处理
一、1.数据查看及处理
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
sample = 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')
导入数据
train.info()#查看是否有缺失值
共有10000个观测值,没有缺失值。这样就意味着可以直接利用xgboost模型进行预测,不用再进行数据处理。
#查看是否有重复值
d=0
for i in train.duplicated():
if i !=False:
d+=1
print("d:",d)
查看是否有重复值;得出d=14.
#train.drop_duplicates(subset=['city'], keep='first')
train=train.drop_duplicates( keep='first')#删除重复值
我们把重复值删掉。
一、2.查看数据间的相关性
corr = traindata.corr()
corr[np.abs(corr) < 0.2] = np.nan
print(corr)
(为了方便查看,绝对值低于0.2的用nan替代)
从相关性角度来看,用车的时间和当时的气温对借取数量y有较强的关系;气温和体感气温显强正相关,这个和常识一致。
二、Xgboost回归模型调参过程:
调参刚开始的时候,一般要先初始化一些值:
1,选择较高的学习速率(learning rate)。一般情况下,学习速率的值为0.1。但是对于不同的问题,理想的学习速率有时候会在0.05到0.3之间波动。选择对应于此学习速率的理想决策树数量。 Xgboost有一个很有用的函数“cv”,这个函数可以在每一次迭代中使用交叉验证,并返回理想的决策树数量。
2,对于给定的学习速率和决策树数量,进行决策树特定参数调优(max_depth,min_child_weight,gamma,subsample,colsample_bytree)。在确定一棵树的过程中,我们可以选择不同的参数。
3,Xgboost的正则化参数的调优。(lambda,alpha)。这些参数可以降低模型的复杂度,从而提高模型的表现。
4,降低学习速率,确定理想参数。
三、Xgboost使用GridSearchCV调参过程:
三、1、Xgboost 的默认参数如下(在sklearn库中的默认参数):
我们先定义一些值:
learning_rate: 0.1
(学习率)
n_estimators: 500
(数的个数)
max_depth: 5
(树的深度)
scale_pos_weight: 1
(权重。大于0的取值可以处理类别不平衡的情况,帮助模型更快收敛)
subsample: 0.8
(用于训练模型的子样本占整个样本集合的比例。如果设置为0.5则意味着XGBoost将随机的冲整个样本集合中随机的抽取出50%的子样本建立树模型,这能够防止过拟合)
colsample_bytree:0.8
(在建立树时对特征随机采样的比例。缺省值为1)取值范围:0-1
nthread:4
(XGBoost运行时的线程数。缺省值是当前系统可以获得的最大线程数如果你希望以最大 速度运行,建议不设置这个参数,模型将自动获得最大线程)
gamma: 0
(模型在默认情况下,对于一个节点的划分只有在其loss function 得到结果大于0的情况下才进行,而gamma 给定了所需的最低loss function的值)
seed:27
(随机数的种子,缺省值为0。可以用于产生可重复的结果(每次取一样的seed即可得到相同的随机划分)
调参的时候一般按照以下顺序来进行:
1、最佳迭代次数:n_estimators
from xgboostimport XGBRegressor
from sklearn.model_selectionimport GridSearchCV
import pandasas pd
# 读取数据
train = pd.read_csv(r"D:\Python\gongxiangdanche\train.csv")
test = pd.read_csv(r"D:\Python\gongxiangdanche\test.csv")
submit = pd.read_csv(r"D:\Python\gongxiangdanche\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,2000,100)
}
gsearch1 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.5,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_)
结果(即我们选择最优树的个数为200)
{'n_estimators': 200} 0.8908950282399466
2、调参 max_depth和min_child_weight
(树的最大深度,缺省值为3,范围是[1, 正无穷),树的深度越大,则对数据的拟合程度越高,但是通常取值为3-10)
(我们先大范围地粗调参数,然后再小范围地微调)
from xgboostimport XGBRegressor
from sklearn.model_selectionimport GridSearchCV
import pandasas pd
# 读取数据
train = pd.read_csv(r"D:\Python\gongxiangdanche\train.csv")
test = pd.read_csv(r"D:\Python\gongxiangdanche\test.csv")
submit = pd.read_csv(r"D:\Python\gongxiangdanche\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_test2 = {
'max_depth':range(3,10,2),
'min_child_weight':range(1,6,2)
}
gsearch2 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1,n_estimators=200),
param_grid=param_test2)
gsearch2.fit(train, y_train)
print(gsearch2.best_params_, gsearch2.best_score_)
得出结果:
{'max_depth': 5, 'min_child_weight': 5} 0.9037286898745251
我们对于数值进行较大跨度的48种不同的排列组合,可以看出理想的max_depth值为5,理想的min_child_weight值为5。
3、Gamma参数调优
Gamma参数取值范围可以很大,我这里把取值范围设置为5,其实我们也可以取更精确的Gamma值。
from xgboost import XGBRegressor
from sklearn.model_selection import GridSearchCV
import pandas as pd
# 读取数据
train = pd.read_csv(r"D:\Python\gongxiangdanche\train.csv")
test = pd.read_csv(r"D:\Python\gongxiangdanche\test.csv")
submit = pd.read_csv(r"D:\Python\gongxiangdanche\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_test4 = {
'gamma': [i / 10.0 for i in range(0, 5)]
}
gsearch4 = GridSearchCV(estimator=XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth=5, min_child_weight=5),
param_grid=param_test4)
gsearch4.fit(train, y_train)
print(gsearch4.best_params_, gsearch4.best_score_)
{'gamma': 0.0} 0.9037286898745251
得出的结果,Gamma最优值为0。
4、调整subsample 和 colsample_bytree 参数
(subsample 用于训练模型的子样本占整个样本集合的比例,如果设置0.5则意味着XGBoost将随机的从整个样本集合中抽取出百分之50的子样本建立模型,这样能防止过拟合,取值范围为(0, 1])
(在建立树的时候对特征采样的比例,缺省值为1,物质范围为(0, 1])
我们分两个阶段来进行这个步骤。这两个步骤都取0.6,0.7,0.8,0.9 作为起始值。
from xgboost import XGBRegressor
from sklearn.model_selection import GridSearchCV
import pandas as pd
# 读取数据
train = pd.read_csv(r"D:\Python\gongxiangdanche\train.csv")
test = pd.read_csv(r"D:\Python\gongxiangdanche\test.csv")
submit = pd.read_csv(r"D:\Python\gongxiangdanche\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_test5 = {
'subsample': [i / 10.0 for i in range(6, 10)],
'colsample_bytree': [i / 10.0 for i in range(6, 10)]
}
gsearch5 = GridSearchCV(
estimator=XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth=5, min_child_weight=5, gamma=0.0),
param_grid=param_test5)
gsearch5.fit(train, y_train)
print(gsearch5.best_params_, gsearch5.best_score_)
{'colsample_bytree': 0.9, 'subsample': 0.6} 0.9037951735474006
结果为最优值:0.9、0.6
5、正则化参数调优
(由于gamma函数提供了一种更加有效的降低过拟合的方法,大部分人很少会用到这个参数,但是我们可以尝试用一下这个参数。)
from xgboost import XGBRegressor
from sklearn.model_selection import GridSearchCV
import pandas as pd
# 读取数据
train = pd.read_csv(r"D:\Python\gongxiangdanche\train.csv")
test = pd.read_csv(r"D:\Python\gongxiangdanche\test.csv")
submit = pd.read_csv(r"D:\Python\gongxiangdanche\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_test6 = {
'reg_alpha': [0, 0.001, 0.005, 0.01, 0.05]
}
gsearch6 = GridSearchCV(
estimator=XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth=5, min_child_weight=5, gamma=0.0,
colsample_bytree=0.9, subsample=0.7),
param_grid=param_test6)
gsearch6.fit(train, y_train)
print(gsearch6.best_params_, gsearch6.best_score_)
{'reg_alpha': 0.005} 0.9030424269369616
结果为0.005
汇总:
from xgboost import XGBRegressor
from sklearn.model_selection import GridSearchCV
import pandas as pd
# 读取数据
train = pd.read_csv(r"D:\Python\gongxiangdanche\train.csv")
test = pd.read_csv(r"D:\Python\gongxiangdanche\test.csv")
submit = pd.read_csv(r"D:\Python\gongxiangdanche\sample_submit.csv")
# 删除id
train.drop('id', axis=1, inplace=True)
test.drop('id', axis=1, inplace=True)
# 取出训练集的y
y_train = train.pop('y')
reg = XGBRegressor(learning_rate=0.1, n_estimators=200, max_depth=5, min_child_weight=5, gamma=0.0,
colsample_bytree=0.9, subsample=0.7, reg_alpha=0.001)
reg.fit(train, y_train)
y_pred = reg.predict(test)
# 输出预测结果至my_XGB_prediction.csv
submit['y'] = y_pred
submit.to_csv('my_XGB_tc2_prediction.csv', index=False)
最终得出的结果:
如果想要继续降低误差值,我们可以通过调整参数:
通过一样的调参顺序,可以进一步得出更低的误差率。
相比模型的18.847下降了3.938.
在这其中,我也曾尝试过进行数据深度处理以及模型优化,但最终的结果都不理想。
有兴趣的同学可以了解一下:
数据分析:https://blog.csdn.net/wong2016/article/details/87865627?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159041095119724845006238%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159041095119724845006238&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v1~rank_blog_v1-2-87865627.pc_v1_rank_blog_v1&utm_term=%E5%85%B1%E4%BA%AB%E5%8D%95%E8%BD%A6
建模篇:https://blog.csdn.net/wong2016/article/details/87916292?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159041095119724845006238%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159041095119724845006238&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v1~rank_blog_v1-1-87916292.pc_v1_rank_blog_v1&utm_term=%E5%85%B1%E4%BA%AB%E5%8D%95%E8%BD%A6