sofa竞赛:公共自行车使用量预测

一、简介

背景介绍:

公共自行车低碳、环保、健康,并且解决了交通中“最后一公里”的痛点,在全国各个城市越来越受欢迎。本练习赛的数据取自于两个城市某街道上的几处公共自行车停车桩。我们希望根据时间、天气等信息,预测出该街区在一小时内的被借取的公共自行车的数量。

数据下载:

数据文件(三个):
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库自己的建模流程

或者,我们也可以选择第二种方法,使用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

你可能感兴趣的:(sofa竞赛:公共自行车使用量预测)