1.項目介紹
1.1項目說明
自行車共享系統(tǒng)是租借自行車的一種手段,通過這些系統(tǒng)犀暑,人們可以從任意地點租借一輛自行車,到達目的地后歸還广辰。
自行車共享系統(tǒng)明確記錄了旅行時間择吊,出發(fā)地點,到達地點和時間所森。因此必峰,其可用于研究城市中的移動性吼蚁。
在本項目中,要求將歷史使用模式與天氣數據結合起來旗国,以預測華盛頓特區(qū)的自行車租賃租賃需求能曾。
1.2數據來源
數據來自kaggle:kaggle共享單車數據
數據提供了跨越兩年的每小時租賃數據寿冕,包含天氣信息和日期信息藻茂,
訓練集由每月前19天的數據組成辨赐,測試集是每月第20天到當月底的數據掀序。
2.理解數據
2.1變量說明
datetime(日期) - 年 、月县袱、 日+ 整點時刻
season(季節(jié)) - 1 =春, 2 = 夏, 3 = 秋, 4 = 冬
holiday(是否假日) - 是否是節(jié)假日
workingday(是否工作日) - 是否是工作日
weather(天氣等級) -
1. 清澈式散,少云,多云乖篷。
2. 霧+陰天撕蔼,霧+碎云鲸沮、霧+少云、霧
3. 小雪怒坯、小雨+雷暴+散云剔猿,小雨+云
4. 暴雨+冰雹+雷暴+霧,雪+霧
temp(溫度) - 攝氏溫度
atemp(體感溫度) - 感覺攝氏溫度
humidity(相對濕度) - 相對濕度
windspeed(風速) - 風速
casual(臨時租賃數量) - 非用戶租賃數量
registered(會員租賃數量) - 會員租賃數量
count(總租賃數量) - 租賃總量
2.2導入數據
#導入數據包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime
# 導入數據
data = pd.read_csv(r'C:\Users\ThinkPad\Desktop\bike-share\train.csv')
# 查看數據變量
data.head()
3.數據預處理
先觀察數據
data.info()
data.describe()
3.1 數據變換
首先觀察到datetime包含了從年到小時的信息,這里我們想把他拆開,便于之后的分析慌闭。
data['datetime'] = data['datetime'].astype(str)
data['datetime'] = data['datetime'].apply(lambda x:datetime.strptime(x,'%Y-%m-%d %H:%M:%S'))
# 提取年驴剔、月、日布讹、小時描验、星期日數,并以列的形式添加到data數據中
data['year'] = data['datetime'].apply(lambda x: x.year)
data['month'] = data['datetime'].apply(lambda x: x.month)
data['day'] = data['datetime'].apply(lambda x: x.day)
data['hour'] = data['datetime'].apply(lambda x: x.hour)
data['weekday'] = data['datetime'].apply(lambda x: x.strftime('%a'))
# 調整列標題順序睡扬,方便理解數據
columns = ['datetime', 'year', 'month', 'day', 'hour', 'weekday',
'season', 'holiday', 'workingday',
'weather', 'temp', 'atemp', 'humidity', 'windspeed',
'casual', 'registered', 'count',]
data = data[columns]
data.head()
3.2 數據類型轉換
季節(jié),節(jié)假日马靠,工作日甩鳄,星期日數等列數據目前都是int類型档泽,為了便于進行數據可視化馆匿,可以使用map()和pd.Categorical()將這些列的數據轉換成分類數據。例如季節(jié)數據1代表春天赃蛛,可以將數值型數據1轉換成文本型數據Spring,再轉換成帶順序的分類型數據诵闭,這樣在數據可視化時會自動保留Spring--Summer--Fall--Winter的季節(jié)順序疏尿。
對于一年中任意一天,它只能是工作日或者非工作日敌呈,其中非工作日又分為節(jié)假日和周末磕洪,因此,任意一天的日期類型只能是workingday谷异,或者weekend箩绍,或者holiday材蛛,因此可以用一列由這三者組成的數據替代workingday和holiday兩列的數據。
data1 = data.copy()
#定義day_type()函數,用來判斷日期類型
def day_type(row):
if row['holiday'] == 1:
return 2
elif row['workingday'] == 0 and row['holiday'] == 0:
return 1
else:
return 0
# 添加一列day_type迹淌,值為日期的日期類型
data1['day_type'] = data1.apply(day_type,axis=1)
# 使用map()函數轉換數值為文本型
data1['season'] = data1['season'].map({1:'Spr',2:'Sum',3:'Aut',4:'Win'})
data1['day_type'] = data1['day_type'].map({0:'Workingday',1:'Weekend',2:'Holiday'})
# 將文本型數據轉換成分類數據
data1['season'] = pd.Categorical(values = data1['season'],ordered = True,categories = ['Spr','Sum','Aut','Win'])
data1['day_type'] = pd.Categorical(values = data1['day_type'],ordered = True,categories = ['Workingday','Weekend','Holiday'])
data1['weekday'] = pd.Categorical(values = data1['weekday'],ordered = True,categories = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'])
data1.set_index('datetime',inplace = True)
data1.head()
這里就可以把holiday,workingday刪除掉了纹笼,因為已經歸并到day_type中了
data1 = data1.drop(columns=['holiday','workingday'])
3.3 數據清洗
通過檢查沒有重復值蔓涧,之前查看info的是時候也知道是沒有缺失值的元暴,所以接下來來檢查有沒有數據異常
# 數值型數據分布分析
fig,axes = plt.subplots(3,2,figsize = (16,14))
sns.distplot(data1['temp'],ax=axes[0,0])
sns.distplot(data1['atemp'],ax=axes[0,1])
sns.distplot(data1['humidity'],ax=axes[1,0])
sns.distplot(data1['windspeed'],ax=axes[1,1])
sns.distplot(data1['casual'],ax=axes[2,0])
sns.distplot(data1['registered'],ax=axes[2,1])
風速0-10中存在異常值枢冤,這里使用隨即森林進行填充淹真。
#對風速中的0值進行替換
#了解對產生風速影響的因素
corrDf = data.corr()
heatmap = sns.heatmap(corrDf)
plt.show()
corrDf['windspeed'].sort_values(ascending =False)
from sklearn.ensemble import RandomForestRegressor
# 將數據分成風速等于0和不等于兩部分
wind_0 = data[data['windspeed']==0]
wind_1 = data[data['windspeed']!=0]
#選定模型
Model_wind = RandomForestRegressor(n_estimators=1000,random_state=42)
# 選定特征值
windspeed_X = wind_1[['hour','count','season','month','humidity']]
# 選定標簽值
windspeed_y = wind_1['windspeed']
#選定預測特征值
windspeedpre_X = wind_0[['hour','count','season','month','humidity']]
# 將風速不等于0的數據作為訓練集梅屉,fit到RandomForestRegressor之中
Model_wind.fit(windspeed_X, windspeed_y)
#通過訓練好的模型預測風速
wind_0prevalues = Model_wind.predict(windspeedpre_X)
#將預測的風速填充到風速為零的數據中
wind_0.loc[:,'windspeed'] = wind_0prevalues
wind_0和wind_1分別為:
#連接兩部分數據
data = pd.concat([wind_1,wind_0],join='inner').sort_values('datetime')
data.reset_index(inplace=True)
data.drop('index',inplace=True,axis=1)
data.head()
再看一下現(xiàn)在的風速分布
# 風速分布
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
fig.set_size_inches(6,5)
sns.distplot(data['windspeed'])
ax.set(xlabel='windspeed',title='windspeed_scatter diagram')
#將data的windspeed字段復制給已經整理好的data1
data1['windspeed']=data['windspeed']
4.可視化與分析
#設置作圖風格
plt.style.use('ggplot')
4.1 2011年至2012年的共享單車總租賃量情況
total = data1[['casual','registered','count']].resample('M').sum().reset_index()
total.head()
# 計算注冊用戶租車量比例
total['rate'] = total['registered']/total['count']
# 將月份數據轉換成文本型
total['month'] = total['datetime'].apply(lambda x: x.strftime('%b\n%Y') if x.strftime('%b') == 'Jan' else x.strftime('%b'))
# 設定作圖尺寸
fig, ax1 = plt.subplots(figsize=(15,10))
x = np.arange(24)
y1 = total['casual']
y2 = total['registered']
ax1 = plt.bar(x, y1, label='Casual', bottom=total['registered'],alpha=0.7)
ax2 = plt.bar(x, y2, label='Registered',alpha=0.7)
plt.title('Monthly Bike Rental in 2011-2012')
plt.xlim(-1,24)
plt.ylim(0, 150000)
plt.legend(loc='center left')
plt.xticks(np.arange(24), total['month'], rotation=0)
# 根據注冊用戶租車比例作圖
ax3 = plt.twinx()
y3 = total['rate']
ax3 = plt.plot(np.arange(24), y3, label='2011',color='green')
# 美化圖表
plt.ylim(0,1.1)
plt.yticks([0.5, 0.75, 0.875, 1], ['50%', '75%', '87.5%', '100%'])
plt.grid(b=None)
plt.text(x=20, y=0.96, s='Registered Rental %', color='black', weight='bold', rotation=0, backgroundcolor='#f0f0f0')
# 添加水印
plt.text(x = -1.5, y = -0.2,
s = ' ?Cuijian Data Source: Kaggle',
fontsize = 14, color = 'grey')
# 添加數值標簽
for a,b in zip(x,y3):
plt.text(a, b+0.02, '%.1f%%' %(b*100), ha='center', va= 'bottom', fontsize = 7)
- 2011年至2012年,租車數量總體呈現(xiàn)上升趨勢搓幌,但是受季節(jié)因素影響顯著溉愁,其中,春季最少堂污,夏季秋季最多,冬季租車量要高于春季式镐。(這里回答了開頭提出的第二個問題碟案。)
- 注冊用戶是租車主力,租車比例基本每月都在75%以上鳖目。
- 注冊用戶在夏季和秋季的租車比例(80%)低于春季和冬季(90%)。也就是說非注冊用戶夏秋租車占比高于春冬狸捅,即非注冊用戶更傾向于在天氣情況較為暖和的夏季和秋季租車磁浇。
4.2 工作日置吓,節(jié)假日的租車量有何不同?
# 獲取包含日期數據的每日租車數據
daily_rental = data1.groupby(['year', 'month', 'day','weekday','day_type'])['count'].sum().reset_index()
daily_rental.head()
# 獲取最低和最高的單日租車量值
daily_min = daily_rental['count'].min()
daily_max = daily_rental['count'].max()
print(daily_min,daily_max)
fig,(ax1,ax2) = plt.subplots(1,2,figsize = (15,12))
# 根據星期日數作每日租車量的箱線圖
sns.boxplot(x = 'weekday', y = 'count', data = daily_rental, ax = ax1)
# day_type三個類型的箱線圖
sns.boxplot(x = 'day_type', y = 'count', data = daily_rental, ax = ax2)
# 美化圖表
ax1.set_title('Daily Bike Rental by Weekday', fontsize=18)
ax2.set_title('Daily Bike Rental by day_type', fontsize=18)
ax1.axhline(daily_min, xmin=0, xmax=16, linewidth=1, linestyle='--', alpha=0.7)
ax2.axhline(daily_max, xmin=0, xmax=16, linewidth=1, linestyle='--', alpha=0.7)
- 沒有異常值出現(xiàn),數據相對合理可信。
- 每周各天的平均租車量差距不大,在4500次上下范圍波動男娄,星期六的平均租車量相對最高,最高租車量也是在星期六尸折。星期日的平均租車量相對最低
- 星期五的最低租車量接近1500次,明顯高于其他天數(<=1000)亮航。
- 就日期類型而言,工作日重抖,周末和節(jié)假日的平均租車量較為接近畔规,節(jié)假日的租車量波動范圍較小油讯,節(jié)假日租車量中位數明顯高于工作日和周末⊥米郏可以判斷用戶更傾向在節(jié)假日租車。
然后我們進一步下鉆狞玛,探索注冊用戶和非注冊用戶的在不同天數下的租車情況
daily_casual_rental = data1.groupby(['year', 'month', 'day','weekday','day_type'])['casual'].sum().reset_index()
daily_registered_rental = data1.groupby(['year', 'month', 'day','weekday','day_type'])['registered'].sum().reset_index()
# 合并數據
daily_user_rental = daily_casual_rental
daily_user_rental['registered'] = daily_registered_rental['registered']
daily_user_rental.head()
# 使用pd.melt將casual, registered兩列變成user_type一列
daily_user_rental = daily_user_rental.melt(id_vars=['year', 'month', 'day', 'weekday', 'day_type'],
value_vars=['casual', 'registered'], var_name='user_type',
value_name='rental')
daily_user_rental.head()
# 設定圖表
fig, (ax5, ax6) = plt.subplots(1, 2, figsize = (16,8))
fig.suptitle('Daily Bike Rental by Casual& Registered Users',fontsize = 24)
# 不同星期日數下的每日租車量箱線圖
sns.boxplot(x="weekday", y="rental", hue="user_type", ax=ax5,data=daily_user_rental,
showmeans=True,meanprops=dict(marker='o', markerfacecolor='yellow', markeredgecolor='yellow'))
sns.boxplot(x="day_type", y="rental", hue="user_type", ax=ax6,
data=daily_user_rental, showmeans=True, palette=['pink', 'green'], linewidth=1,
meanprops=dict(marker='o', markerfacecolor='yellow', markeredgecolor='yellow'))
由上圖可見:
- 出現(xiàn)4個異常值软驰,分別分布在周一,周二心肪,周三,數量很少硬鞍,其中三個超過上限的異常值很可能是因為當天是節(jié)假日造成的慧瘤。
- 注冊用戶更傾向在工作日租車,在周末的租車量(約3000/日)明顯低于工作日(約4000/日)固该,在節(jié)假日的租車量總體介于工作日和周末租車量之間锅减。
- 非注冊用戶在工作日租車量少(平均值低于1000/日),所占比例很低伐坏,在周末租車量(約1500/日)明顯提高怔匣,但仍低于注冊用戶租車量。
4.3 每天哪個時段的租車量較高桦沉?
fig,ax7 = plt.subplots(figsize=(16,8))
# 注冊用戶不同時間段和日期類型的租車量作圖
ax7 = data1.groupby(['hour', 'day_type'])['registered'].sum().unstack().plot(ax=ax7,marker='o')
# 非注冊用戶不同時間段和日期類型的租車量作圖
ax8 = data1.groupby(['hour', 'day_type'])['casual'].sum().unstack().plot(ax=ax7,linestyle='--',
color=['green','orange','pink'],marker='o')
#美化
plt.xticks(np.arange(24))
ax7.legend(['Workingday Registered', 'Weekend Registered', 'Holiday Registered',
'Workingday Casual', 'Weekend Casual', 'Holiday Casual'], fontsize=12)
plt.suptitle('registered&casual count in time of day_type ')
從上圖可知:
- 工作日時的早7-8點和晚5-6點是注冊用戶的使用高峰時段每瞒,換一句話說,注冊用戶有很大一部分需求是由于早晚的通勤用車纯露。而非注冊用戶在工作日則沒有明顯的高峰時段独泞,說明非注冊用戶有可能多數是無需上班通勤的大齡人群或者不需要使用自行車的人群。
- 再來看節(jié)假日苔埋,注冊用戶和非注冊用戶的曲線表現(xiàn)相似懦砂,均是從早上8點開始逐漸增多,當中午12點和13點左右時達到一天的最大值,但是注冊用戶的最大值平均能達到37000荞膘,但是非注冊用戶只有20000左右罚随,13點之后使用量逐漸遞減。
- 節(jié)假日用車數非常少羽资,兩條曲線表現(xiàn)相近淘菩,可以看出無論是注冊用戶還是非注冊用戶,都很少子節(jié)假日用車屠升。
4.4 天氣情況對租車量的影響如何潮改?
天氣數據包含weather, temp, atemp, windspeed, humidity,下面逐一作圖分析腹暖。
4.4.1 不同天氣狀況下的租車量分析
weather_rental=data1[['weather','casual','registered','count']]
weather_rental['weather']=weather_rental['weather'].map({1:'Clear,Partly cloudy',2:'Mist + Cloudy',3:'Light Snow, Light Rain',
4:'Heavy Rain汇在,snow'})
weather_rental.head()
weather_rental_gb=weather_rental.groupby('weather').agg({'weather':'count','count':sum}).rename(columns={'weather':'weather_count',
'count':'rental'}).reset_index().sort_values('rental',ascending=False)
weather_rental_gb['average hourly rental']= weather_rental_gb['rental']/weather_rental_gb['weather_count']
weather_rental_gb.head()
fig,ax9 = plt.subplots(figsize=(10,6))
ax9=plt.bar(weather_rental_gb['weather'],weather_rental_gb['rental'],color='sandybrown')
plt.twinx()
ax10=plt.plot(weather_rental_gb['weather'],weather_rental_gb['average hourly rental'],color='gray',marker='o')
# 添加數值標簽
x=weather_rental_gb['weather']
y1=weather_rental_gb['rental']
y2=weather_rental_gb['average hourly rental']
plt.legend()
for a,b in zip(x,y2):
plt.text(a, b+2, '%.1f' %b, ha='center', va= 'bottom', fontsize =12)
由天氣狀況-租車數據圖可見:
天氣狀況好時的租車量高于天氣狀況差的時候。晴天/少云和多云/薄霧天氣下的租車量明顯高于雨雪天氣時脏答。暴雨/大學天氣只出現(xiàn)了一次糕殉,因此平均租車數據不具參考性。
晴天/少云天氣下的總租車量大大超過其他天氣狀況殖告,可以判斷華盛頓特區(qū)氣候宜人阿蝶,天氣多以晴天/少云為主。
4.4.2 不同風速下的租車量分析
data.set_index('datetime',inplace = True)
windspeed_rental=data[['windspeed','casual','registered','count']]
#把風速變?yōu)檎?list_windspeed=windspeed_rental['windspeed']
list_windspeed=round(list_windspeed)
list_windspeed=list_windspeed.astype(int)
windspeed_rental.loc[:,'windspeed']=list_windspeed
#對風速進行groupby
windspeed_rental_gb=windspeed_rental.groupby('windspeed').agg({'windspeed':'count',
'casual':'sum',
'registered':'sum',
'count':'sum'})
windspeed_rental_gb.rename(columns={'windspeed':'wd_count',
'casual':'casual_rental',
'registered':'registered_rental',
'count':'sum_rental'},inplace=True)
windspeed_rental_gb.reset_index()
windspeed_rental_gb['avg_casual_rental']=round(windspeed_rental_gb['casual_rental']/windspeed_rental_gb['wd_count'])
windspeed_rental_gb['avg_registered_rental']=round(windspeed_rental_gb['registered_rental']/windspeed_rental_gb['wd_count'])
windspeed_rental_gb['wd_rate']=windspeed_rental_gb['wd_count']/sum(windspeed_rental_gb['wd_count'])
windspeed_rental_gb['wd_rate_total']=np.cumsum(windspeed_rental_gb['wd_rate'])
windspeed_rental_gb=windspeed_rental_gb.reset_index()
#風度對總租借量的影響
fig,(ax10,ax11)=plt.subplots(1,2,figsize=(20,6))
sns.barplot(x="windspeed",y="sum_rental",data=windspeed_rental_gb,ax=ax10)
sns.lineplot(x="windspeed",y="wd_rate_total",data=windspeed_rental_gb,ax=ax11)
左圖其實并不能夠說明什么問題黄绩,因為有的風速分布是極少的羡洁,所以這一風速所對應的使用量也是極少的,即我們不能夠說某一風速下使用量少爽丹,因為受很有可能這一風速出現(xiàn)的概率很小的影響筑煮。
其實最好能做出上面這個圖,但是這個圖的做法還在探索中习劫。。嚼隘。汗~
#兩種客戶在不同風速下的平均租借量
fig=plt.figure(figsize=(15,6))
sns.lineplot(x="windspeed",y="avg_casual_rental",data=windspeed_rental_gb,label='avg_casual_rental')
sns.lineplot(x="windspeed",y="avg_registered_rental",data=windspeed_rental_gb,label='avg_registered_rental')
fig.legend()
- 超過80%的時間段風速在20以下诽里,另外接近20%的時段風速在20-40區(qū)間,40以上的風速的時間段極少飞蛹。鑒于風速大于30m/s已經屬于颶風級別谤狡,因此推斷風速單位是km/h。40km/h的風速已經相當于6級強風卧檐。
- 從平均租借量來看的話墓懂,35km/h以上的風級開始平均租借量下降明顯。
4.4.3 不同體感溫度下的租車量分析
atemp_rental=data[['atemp','casual','registered','count']]
atemp_rental.head()
list_atemp=atemp_rental['atemp']
list_atemp=round(list_atemp)
list_atemp=list_atemp.astype(int)
atemp_rental.loc[:,'atemp']=list_atemp
atemp_rental_gb=atemp_rental.groupby('atemp').agg({'atemp':'count',
'casual':'sum',
'registered':'sum',
'count':'sum'})
atemp_rental_gb.rename(columns={'atemp':'atemp_count',
'casual':'casual_rental',
'registered':'registered_rental',
'count':'sum_rental'},inplace=True)
atemp_rental_gb.reset_index()
atemp_rental_gb['avg_casual_rental']=round(atemp_rental_gb['casual_rental']/atemp_rental_gb['atemp_count'])
atemp_rental_gb['avg_registered_rental']=round(atemp_rental_gb['registered_rental']/atemp_rental_gb['atemp_count'])
atemp_rental_gb['atemp_rate']=atemp_rental_gb['atemp_count']/sum(atemp_rental_gb['atemp_count'])
atemp_rental_gb['atemp_rate_total']=np.cumsum(atemp_rental_gb['atemp_rate'])
atemp_rental_gb=atemp_rental_gb.reset_index()
#體感溫度對總租借量的影響
fig,(ax12,ax13)=plt.subplots(1,2,figsize=(20,6))
sns.barplot(x="atemp",y="sum_rental",data=atemp_rental_gb,ax=ax12)
sns.lineplot(x="atemp",y="atemp_rate_total",data=atemp_rental_gb,ax=ax13)
#兩種客戶在不同atemp下的平均租借量
fig=plt.figure(figsize=(15,6))
sns.lineplot(x="atemp",y="avg_casual_rental",data=atemp_rental_gb,label='avg_casual_rental')
sns.lineplot(x="atemp",y="avg_registered_rental",data=atemp_rental_gb,label='avg_registered_rental')
fig.legend()
- 體感溫度主要分布在5到40攝氏度霉囚,分布相對平均捕仔。
- 5到40攝氏度的區(qū)間,無論是注冊用戶還是非注冊用戶,平均租車量基本都隨著溫度的上升而明顯提高榜跌。
4.4.3 不同濕度下的租車量分析
思路和4.4.2是一樣的闪唆,這里就直接分析結論:
- 濕度主要集中在20至100區(qū)間,分布相對平均钓葫。
- 濕度20-100的時候悄蕾,注冊用戶和非注冊用戶的平均租車量都隨著濕度的升高而顯著下降。濕度20的時候租車量最高础浮。
5.隨機森林預測
5.1 數據準備
train=data.reset_index()
#訓練集數據
train = train[['datetime','season','holiday','workingday','weather','temp','atemp','humidity','windspeed','count']] #風速是用隨機森林模擬過的
#測試數據集
test = pd.read_csv(r'C:\Users\ThinkPad\Desktop\bike-share\test.csv')
#了解數據集總數
print ('訓練數據集:',train.shape,'測試數據集:',test.shape)
#訓練集去除3倍方差以外數據
train_std = train[np.abs(train['count']-
train['count'].mean())<=(3*train['count'].std())]
train_std.shape
5.2 數據預處理
先將訓練集和測試集進行合并
train_std_y=np.log(train_std.pop('count'))
#將train_std帆调、test 合并,便于修改
full = train_std.append( test , ignore_index = True )
print ('合并后的數據集:',full.shape)
full.info()
選定特征year,month,weekday,hour,season,holiday, weather, temp, humidity, windspeed
full['datetime'] = full['datetime'].astype(str)
full['datetime'] = full['datetime'].apply(lambda x:datetime.strptime(x,'%Y-%m-%d %H:%M:%S'))
# 提取年豆同、月番刊、小時、星期日數诱告,并以列的形式添加到數據中
full['year'] = full['datetime'].apply(lambda x: x.year)
full['month'] = full['datetime'].apply(lambda x: x.month)
full['hour'] = full['datetime'].apply(lambda x: x.hour)
full['weekday'] = full['datetime'].apply(lambda x: x.strftime('%a'))
#選擇需要的特征
columns = ['year','month','weekday','hour',
'season','holiday', 'weather', 'temp', 'humidity', 'windspeed']
full_feature = full[columns]
full_feature.head()
#將多類別型數據使用one-hot轉化成多個二分型類別
dummies_year = pd.get_dummies(full_feature['year'],prefix='year')
dummies_month = pd.get_dummies(full_feature['month'], prefix= 'month')
dummies_weekday = pd.get_dummies(full_feature['weekday'],prefix='weekday')
dummies_hour = pd.get_dummies(full_feature['hour'],prefix='hour')
dummies_season = pd.get_dummies(full_feature['season'],prefix='season')
dummies_holiday = pd.get_dummies(full_feature['holiday'],prefix='holiday')
dummies_weather = pd.get_dummies(full_feature['weather'],prefix='weather')
full_feature=pd.concat([full_feature,dummies_year,dummies_month,dummies_weekday,
dummies_hour,dummies_season,dummies_holiday,dummies_weather],axis=1)
#刪除原有列
dropFeatures = ['season','weather','year','month','weekday','hour','holiday']
full_feature = full_feature.drop(dropFeatures ,axis = 1)
full_feature.head()
5.3 建模
5.3.1 設置訓練集和預測集
train_df=full_feature.loc[train_std.index]
test_df=full_feature.loc[test.index]
#原始數據集有多少行
print('原始數據集有多少行:',train_df.shape[0])
#預測數據集大小
print('預測數據集有多少行:',test_df.shape[0])
train_x=train_df
train_y=train_std_y
test_x=test_df
5.3.2 隨機森林算法調參
導入相關函數庫撵枢,分別對幾個重要參數進行調參
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import GridSearchCV,cross_val_score
###粗調n_estimators參數
ScoreAll = []
for i in range(1,200,10):
DT = RandomForestRegressor(n_estimators = i,random_state = 42)
score = cross_val_score(DT,train_x,train_y,cv=10,scoring='neg_mean_squared_error').mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##這句話看似很長的,其實就是找出最高得分對應的索引
print("最優(yōu)參數以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
###粗調max_depth參數
ScoreAll = []
for i in range(1,60,10):
DT = RandomForestRegressor(n_estimators = 181,random_state = 42,max_depth =i)
score = cross_val_score(DT,train_x,train_y,cv=10,scoring='neg_mean_squared_error').mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##這句話看似很長的精居,其實就是找出最高得分對應的索引
print("最優(yōu)參數以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
###調min_samples_split參數
ScoreAll = []
for i in range(4,14):
RF = RandomForestRegressor(n_estimators = 100,random_state = 42,max_depth =21,min_samples_split = i )
score = cross_val_score(RF,train_x,train_y,cv=10).mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##這句話看似很長的锄禽,其實就是找出最高得分對應的索引
print("最優(yōu)參數以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
###調min_samples_leaf參數
ScoreAll = []
for i in range(10,30,2):
DT = RandomForestRegressor(n_estimators = 100,random_state = 42,max_depth =21,min_samples_leaf = i,min_samples_split = 11 )
score = cross_val_score(DT,train_x,train_y,cv=10).mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##這句話看似很長的靴姿,其實就是找出最高得分對應的索引
print("最優(yōu)參數以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
#調max_features參數
param_grid = {
'max_features':np.arange(0.1, 1)}
rfc = RandomForestRegressor(random_state=42,n_estimators = 100,max_depth = 21,min_samples_leaf =16 ,min_samples_split =11 )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(train_x,train_y)
print(GS.best_params_)
print(GS.best_score_)
5.3.3 應用模型
Model = RandomForestRegressor(random_state=42,n_estimators = 100,max_depth = 21,min_samples_leaf =16 ,min_samples_split =11 )
Model.fit(train_x , train_y)
pred_value = Model.predict(test_x)
pred_value = np.exp(pred_value)
submission = pd.DataFrame({'count':pred_value},columns=['count'])
submission['count'] = submission['count'].astype(int)
result=pd.concat([test,submission],axis=1)
result=result[['datetime','count']]
result.to_csv(r'C:\Users\ThinkPad\Desktop\bike-share\bike_predictions.csv',index = False)
提交~~~
結果貌似并不盡如人意沃但,文章先寫到這里,后續(xù)會持續(xù)考慮如何優(yōu)化改進~