一、数据收集
1.1、项目说明
自行车共享系统是一种租赁自行车的方法,注册会员、租车、还车都将通过城市中的站点网络自动完成,通过这个系统人们可以根据需要从一个地方租赁一辆自行车然后骑到自己的目的地归还。在这次比赛中,参与者需要结合历史天气数据下的使用模式,来预测D.C.华盛顿首都自行车共享项目的自行车租赁需求。
1.2、数据内容及变量说明
比赛提供了跨越两年的每小时租赁数据,包含天气信息和日期信息,训练集由每月前19天的数据组成,测试集是每月第二十天到当月底的数据。
二、数据处理
2.1、导入数据
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='whitegrid' , palette='tab10')
train=pd.read_csv(r'D:\A\Data\ufo\train.csv',encoding='utf-8')
train.info()
test=pd.read_csv(r'D:\A\Data\ufo\test.csv',encoding='utf-8')
print(test.info())
2.2、缺失值处理
#可视化查询缺失值
import missingno as msno
msno.matrix(train,figsize=(12,5))
msno.matrix(test,figsize=(12,5))
本次数据没有缺失值,不需要进行缺失值处理。
2.3、Label数据(即count)异常值处理
#观察训练集数据描述统计
train.describe().T
先从数值型数据入手,可以看出租赁额(count)数值差异大,再观察一下它们的密度分布:
#观察租赁额密度分布
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
fig.set_size_inches(6,5)
sns.distplot(train['count'])
ax.set(xlabel='count',title='Distribution of count',)
发现数据密度分布的偏斜比较严重,且有一个很长的尾,所以希望能把这一列数据的长尾处理一下,先排除掉3个标准差以外的数据试一下能不能满足要求
train_WithoutOutliers = train[np.abs(train['count']-train['count'].mean())<=(3*train['count'].std())]
print(train_WithoutOutliers.shape)
train_WithoutOutliers['count'] .describe()
与处理前对比不是很明显,可视化展示对比看一下:
fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(1, 2, 2)
fig.set_size_inches(12,5)
sns.distplot(train_WithoutOutliers['count'],ax=ax1)
sns.distplot(train['count'],ax=ax2)
ax1.set(xlabel='count',title='Distribution of count without outliers',)
ax2.set(xlabel='registered',title='Distribution of count')
可以看到数据波动依然很大,而我们希望波动相对稳定,否则容易产生过拟合,所以希望对数据进行处理,使得数据相对稳定,此处选择对数变化,来使得数据稳定。
yLabels=train_WithoutOutliers['count']
yLabels_log=np.log(yLabels)
sns.distplot(yLabels_log)
经过对数变换后数据分布更均匀,大小差异也缩小了,使用这样的标签对训练模型是有效果的。接下来对其余的数值型数据进行处理,由于其他数据同时包含在两个数据集中,为方便数据处理先将两个数据集合并。
Bike_data=pd.concat([train_WithoutOutliers,test],ignore_index=True)
#查看数据集大小
Bike_data.shape
2.4、其他数据异常值处理
fig, axes = plt.subplots(2, 2)
fig.set_size_inches(12,10)
sns.distplot(Bike_data['temp'],ax=axes[0,0])
sns.distplot(Bike_data['atemp'],ax=axes[0,1])
sns.distplot(Bike_data['humidity'],ax=axes[1,0])
sns.distplot(Bike_data['windspeed'],ax=axes[1,1])
axes[0,0].set(xlabel='temp',title='Distribution of temp',)
axes[0,1].set(xlabel='atemp',title='Distribution of atemp')
axes[1,0].set(xlabel='humidity',title='Distribution of humidity')
axes[1,1].set(xlabel='windspeed',title='Distribution of windspeed')
通过这个分布可以发现一些问题,比如风速为什么0的数据很多,而观察统计描述发现空缺值在1–6之间,从这里似乎可以推测,数据本身或许是有缺失值的,但是用0来填充了,但这些风速为0的数据会对预测产生干扰,希望使用随机森林根据相同的年份,月份,季节,温度,湿度等几个特征来填充一下风速的缺失值。填充之前看一下非零数据的描述统计。
Bike_data[Bike_data['windspeed']!=0]['windspeed'].describe()
from sklearn.ensemble import RandomForestRegressor
Bike_data["windspeed_rfr"]=Bike_data["windspeed"]
# 将数据分成风速等于0和不等于两部分
dataWind0 = Bike_data[Bike_data["windspeed_rfr"]==0]
dataWindNot0 = Bike_data[Bike_data["windspeed_rfr"]!=0]
#选定模型
rfModel_wind = RandomForestRegressor(n_estimators=1000,random_state=42)
# 选定特征值
windColumns = ["season","weather","humidity","month","temp","year","atemp"]
# 将风速不等于0的数据作为训练集,fit到RandomForestRegressor之中
rfModel_wind.fit(dataWindNot0[windColumns], dataWindNot0["windspeed_rfr"])
# 通过训练好的模型预测风速
wind0Values = rfModel_wind.predict(X= dataWind0[windColumns])
#将预测的风速填充到风速为零的数据中
dataWind0.loc[:,"windspeed_rfr"] = wind0Values
#连接两部分数据
Bike_data = dataWindNot0.append(dataWind0)
Bike_data.reset_index(inplace=True)
Bike_data.drop('index',inplace=True,axis=1)
观察随机森林填充后的密度分布情况
fig, axes = plt.subplots(2, 2)
fig.set_size_inches(12,10)
sns.distplot(Bike_data['temp'],ax=axes[0,0])
sns.distplot(Bike_data['atemp'],ax=axes