一、简介
背景介绍:
公共自行车低碳、环保、健康,并且解决了交通中“最后一公里”的痛点,在全国各个城市越来越受欢迎。本练习赛的数据取自于两个城市某街道上的几处公共自行车停车桩。我们希望根据时间、天气等信息,预测出该街区在一小时内的被借取的公共自行车的数量。
数据下载:
数据文件(三个):
train.csv 训练集,文件大小 273kb
test.csv 预测集, 文件大小 179kb
sample_submit.csv 提交示例 文件大小 97kb
训练集中共有10000条样本,预测集中有7000条样本。
数据下载地址:http://sofasofa.io/competition.php?id=1
变量说明:
变量名 | 解释 |
---|---|
id | 行编号,没有实际意义。 |
y | 一小时内自行车被借取的数量。在test.csv中,这是需要被预测的数值。 |
city | 表示该行记录所发生的城市,一共两个城市。 |
hour | 当时的时间,精确到小时,24小时计时法 |
is_workday | 1表示工作日,0表示节假日或者周末 |
temp_1 | 当时的气温,单位为摄氏度 |
temp_2 | 当时的体感温度,单位为摄氏度 |
weather | 当时的天气状况,1为晴朗,2为多云、阴天,3为轻度降水天气,4为强降水天气 |
wind | 当时的风速,数值越大表示风速越大 |
评价方法
二、xgboost回归模型
在这个竞赛里面,官方提供了三个算法,分别是简单线性回归模型、决策树回归模型和xgboost回归模型,都是通过python代码实现的。前面两个模型比较简单,预测结果也较差,所以我们重点来看xgboost回归模型。
官方提供的xgboost回归模型(Python):
该模型预测结果的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)
上面的代码都比较简单,没有过多的设置,能清晰看到官方提供的思路。那么,什么是xgboost?我们怎么使用xgboost库来构建回归模型?
XGBoost全名叫(eXtreme Gradient Boosting)极端梯度提升,经常被用在一些比赛中,其效果显著。它是大规模并行boosted tree的工具,它是目前最快最好的开源boosted tree工具包。
我们有两种方式可以来使用我们的xgboost库来构建回归模型。
第一种方式,是直接用xgboost库自己的建模流程。流程如下图所示:
或者,我们也可以选择第二种方法,使用xgboost库中的sklearn的API。这是说,我们调用sklearnAPI中的类XGBRegressor,并用我们sklearn当中惯例的实例化,fit和predict的流程来运行XGB,并且也可以调用属性比如coef_等等。该方法也是官方提供的代码中所使用的。
下面是这个类的方法的示例参数(并非优化调参):
class xgboost.XGBRegressor(max_depth=3,learning_rate=0.1,n_estimators=100,silent=True,objective='reg:linear',booster='gbtree',
n_jobs=1,nthread=None,gamma=0,min_child_weight=1,max_delta_step=0,subsample=1,colsample_bytree=1,colsample_bylevel=1,
reg_alpha=0,reg_lambda=1,scale=_pos_weight=1,base_score=0.5,random_state=0,seed=None,missing=None,importance_type='gain',
**kwargs)
三、数据处理
查看数据:
我们大概了解了xgboos回归模型的XGBRegressor,我们就要开始处理数据了。因为数据量较多,我们可以通过python来查看部分的数据了解一下。
print(train.shape) //数据矩阵大小
输出:
(10000, 9)
print(train.head(2)) //取头两行数据查看
输出:
print(train.dtypes) //查看各列数据类型
输出:
数据预处理:
我们大致了解数据之后,就可以开始对数据进行预处理。首先是检查缺失值并可视化处理(使用missingno):
import missingno as msno
import matplotlib.pyplot as plt
#display white color in missingness
msno.matrix(train,figsize=(20,10))
plt.show()
输出:
从图中我们可以看出,该数据是没有存在缺失值的。
接下来我们画出特征的箱线图来分析是否存在离群点:
import seaborn as sn
fig, axes = plt.subplots(nrows=2,ncols=2)
fig.set_size_inches(12, 10)
sn.boxplot(data=train,y="y",orient="v",ax=axes[0][0])
sn.boxplot(data=train,y="y",x="weather",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])
axes[0][0].set(ylabel='Count',title="Box Plot On Count")
axes[0][1].set(xlabel='Weather', ylabel='Count',title="Box Plot On Count Across Season")
axes[1][0].set(xlabel='Hour', ylabel='Count',title="Box Plot On Count Across Hour Of The Day")
axes[1][1].set(xlabel='Working Day', ylabel='Count',title="Box Plot On Count Across Working Day")
plt.show()
输出:
图1是全体的离群点,可以看到有很多超过上警戒线的离群点,因此继续做以下分析:
图2可以从中位数线看出,强降水天气频数较低;
图3的中位数在早7点-8点,晚5点-6点较高。这两个时间段正值学校放学、下班高峰期;
图4可以看出,大多数离群点来自"工作日"而非"节假日或者周末"。
所以我们可以得出,人们更明显愿意在天气较好的时候使用共享单车,平时的使用高峰在早7-8点、晚5-6点。
什么是离群点?概括地说,离群点是由于系统受外部干扰而造成的。从获得信息来看,离群点提供了很重要的信息,它不仅提示我们认真检查采样中是否存在差错,在进行时间序列分析前,认真确认序列,而且,当确认离群点是由于系统受外部突发因素刺激而引起的时候,他会提供相关的系统稳定性,灵敏性等重要信息。但从造成分析的困难来看,统计分析人员说不希望序列中出现离群点,离群点会直接影响模型的拟合精度,甚至会得到一些虚伪的信息。
所以,我们接下来可以删除离群点:
TrainWithoutOutliers = train[np.abs(train["y"]-train["y"].mean())<=(3*train["y"].std())]
print("Shape Of The Before Ouliers: ",train.shape)
print("Shape Of The After Ouliers: ",TrainWithoutOutliers.shape)
输出:
单纯删除离群点之后的RMSE为:16.746,对比原来的18.947提高了2.201。
四、调参优化
选择较高的学习速率(learning rate)。一般情况下,学习速率的值为0.1。但是,对于不同的问题,理想的学习速率有时候会在0.05到0.3之间波动。选择对应于此学习速率的理想决策树数量。
调参代码(以调 n_estimators为例):
from xgboost import XGBRegressor
from sklearn.model_selection import GridSearchCV
import pandas as pd
# 读取数据
train = pd.read_csv(r"D:\PythonWenjian\sofasofa\bike_pre\data\train.csv")
test = pd.read_csv(r"D:\PythonWenjian\sofasofa\bike_pre\data\test.csv")
submit = pd.read_csv(r"D:\PythonWenjian\sofasofa\bike_pre\data\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,100)
}
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
其他参数的调整也是类似这样的过程,采用gridSearchCV(网格搜索)调参。
经过多次对XGBRegressor()的参数进行设置,得到最好的一次RMSE结果为:15.13 ,排名127
代码如下:
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(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_prediction.csv', index=False)
五、总结
调参也是讲究方法的,并不是每个参数都去乱试,这样的效率十分低。我们可以采用模型调参利器 gridSearchCV(网格搜索)来降低我们人工的工作量(虽然运行时间有点长)。还有xgboost自身的建模里的回归参数和调用sklearnAPI中的类XGBRegressor的参数设置其实差不多的,只是写法不同,功能是相同的。
参考资源:
(1)【机器学习】菜菜的sklearn课堂11 -XGBoost:
https://www.bilibili.com/video/BV1Bb411S73w?p=1
(2)缺失值可视化处理--missingno:
https://blog.csdn.net/Andy_shenzl/article/details/81633356
(3)Python实现箱形图的绘制:
https://blog.csdn.net/qq_41080850/article/details/83829045
(4)机器学习(四)——模型调参利器gridSearchCV(网格搜索):
https://blog.csdn.net/weixin_41988628/article/details/83098130