????項目來源:Bike Sharing Demand | Kaggle
?一凉泄、提出問題?
????在本項目中蒋搜,參與者被要求將歷史使用模式與天氣數據相結合,以便預測華盛頓特區(qū)的自行車租賃計劃中的自行車租賃需求莉撇。?
?二骆膝、理解數據?
2.1 收集數據?
????一般而言,數據由甲方提供嚼摩。若甲方不提供數據钦讳,則需要根據相關問題從網絡爬取矿瘦,或者以問卷調查形式收集。本次共享單車數據分析項目數據源于Kaggle蜂厅。獲取數據后需要對數據整體進行分析匪凡,從而提煉問題膊畴,為后續(xù)建模奠定基礎掘猿。?
?????首先查看Kaggle所提供的數據描述:?
(1)??? 日期時間:年/月/日/時間,例:2011/1/1 0:00?
(2)??? 季節(jié):1=春唇跨,2=夏稠通,3=秋天,4=冬天?
(3)??? 假日:是否是節(jié)假日(0=否买猖,1=是)?
(4)??? 工作日:是否是工作日(0=否改橘,1=是)?
(5)??? 天氣:1=晴天、多云等(良好)玉控,2=陰天薄霧等(普通)飞主,3=小雪、小雨等(稍差)高诺,4=大雨碌识、冰雹等(極差)?
?(6)??? 實際溫度(℃)?
?(7)??? 感覺溫度(℃)?
?(8)??? 濕度?
?(9)??? 風速?
?(10)未注冊用戶租借數量?
?(11)注冊用戶租借數量?
?(12)總租借數量?
????根據官方數據描述,特征為前9項虱而,分別為日期時間(1)筏餐、季節(jié)(2)烹植、工作日/節(jié)假日(3-4)龙优、天氣(5-9)四類;標簽為后3項:注冊/未注冊用戶租借數量以及租借總數秦陋。因為官方規(guī)定的提交文件中要求預測的只有租借總數惠呼,因此本項目中只關注租借總數的預測导俘。?
2.2導入并理解數據?
????首先導入并查看訓練數據和測試數據:
?import pandas as pd?
#導入并查看訓練數據和測試數據?
train_data = pd.read_csv('data/train.csv')?
test_data = pd.read_csv('data/test.csv')
print(train_data.shape)?
print(train_data.info())?
print(test_data.shape)?
print(test_data.info())?
????訓練數據共12列,10886行剔蹋,測試數據共9列趟畏,6493行,且所有數據完整滩租,沒有缺失赋秀。相比于訓練數據,測試數據缺少注冊/未注冊用戶租借數量以及租借總數3個標簽律想,需要我們通過建模進行預測猎莲。
?三、數據處理與分析?
3.1 數據預處理
????在數據處理過程中技即,最好將訓練數據與測試數據合并在一起處理著洼,方便特征的轉換。通過查看數據,訓練和測試數據均無缺失身笤、不一致和非法等問題豹悬。值得注意的是,日期時間特征由年液荸、月瞻佛、日和具體小時組成,還可以根據日期計算其星期娇钱,因此可以將日期時間拆分成年伤柄、月、日文搂、時和星期5個特征适刀。
#第二步:數據預處理?
#合并兩種數據,使之共同進行數據規(guī)范化?
data = train_data.append(test_data)
?#拆分年煤蹭、月笔喉、日、時
data['year'] = data.datetime.apply(lambda x: x.split()[0].split('-')[0])
data['year'] = data['year'].apply(lambda x: int(x))?
data['month'] = data.datetime.apply(lambda x: x.split()[0].split('-')[1])
data['month'] = data['month'].apply(lambda x: int(x))?
data['day'] = data.datetime.apply(lambda x: x.split()[0].split('-')[2])
data['day'] = data['day'].apply(lambda x: int(x))?
data['hour'] = data.datetime.apply(lambda x: x.split()[1].split(':')[0])
data['hour'] = data['hour'].apply(lambda x: int(x))?
data['date'] = data.datetime.apply(lambda x: x.split()[0])?
data['weekday'] = pd.to_datetime(data['date']).dt.weekday_name
data['weekday']=data['weekday'].map({'Monday':1,'Tuesday':2,'Wednesday':3, 'Thursday':4,'Friday':5,'Saturday':6,'Sunday':7})?
data = data.drop('datetime',axis=1)?
#重新安排整體數據的特征?
cols =['year','month','day','weekday','hour','season','holiday','workingday','weather','temp','atemp','humidity','windspeed','casual','registered','count']data = data.ix[:,cols]?
#分離訓練數據與測試數據
train = data.iloc[:10886]?
test = data.iloc[10886:]?
3.2 數據分析?
規(guī)范數據后硝皂,快速查看各影響因素對租借數的影響:?
#第三步:特征工程?
#1常挚、計算相關系數,并快速查看?
correlation = train.corr()
?influence_order = correlation['count'].sort_values(ascending=False)
influence_order_abs = abs(correlation['count']).sort_values(ascending=False)
print(influence_order)?
print(influence_order_abs)?
????從相關系數可以看出吧彪,天氣(包括溫度待侵、濕度)對租借數存在明顯影響,其中temp和atemp的意義及其與count的相關系數十分接近姨裸,因此可以只取atemp作為溫度特征秧倾。此外,year傀缩、month那先、season等時間因素對count也存在明顯影響,而holiday和weekday與count的相關系數極小赡艰。?
????為了更加直觀地展現所有特征之間的影響售淡,作相關系數熱力圖:
?#2、作相關性分析的熱力圖?
import matplotlib.pyplot as plt?
import seaborn as sn?
f,ax = plt.subplots(figsize=(16,16))?
cmap = sn.cubehelix_palette(light=1,as_cmap=True)
sn.heatmap(correlation,annot=True,center=1,cmap=cmap,linewidths=1,ax=ax)
sn.heatmap(correlation,vmax=1,square=True,annot=True,linewidths=1)
plt.show()?
?接下來慷垮,深入分析各特征對租借數的影響規(guī)律揖闸,對每個特征進行可視化:?
#3、每個特征對租借量的影響?
#(1) 時間維度——年份?
sn.boxplot(train['year'],train['count'])?
plt.title("The influence of year")?
plt.show()?
#(2) 時間維度——月份?
sn.pointplot(train['month'],train['count'])?
plt.title("The influence of month")?
plt.show()?
#(3) 時間維度——季節(jié)?
sn.boxplot(train['season'],train['count'])?
plt.title("The influence of season")?
plt.show()?
#(4) 時間維度——時間(小時)?
sn.barplot(train['hour'],train['count'])?
plt.title("The influence of hour")?
plt.show()?
(1)年份對租借數的影響?
????2012年的租借數明顯比2011年高料身,說明隨著時間的推移汤纸,共享單車逐漸被更多的人熟悉和認可,使用者越來越多芹血。?
?(2)月份對租借數的影響?
?????月份對租借數影響顯著贮泞,從1月份開始每月的租借數快速增加楞慈,到6月份達到頂峰,隨后至10月緩慢降低啃擦,10月后急劇減少囊蓝。這明顯與季節(jié)有關。?
(3)季節(jié)對租借數的影響?
?????通過各季度箱型圖可以看出季節(jié)對租借數的影響符合預期:春季天氣仍然寒冷令蛉,騎車人少聚霜;隨著天氣轉暖,騎車人逐漸增多言询,并在秋季(天氣最適宜時)達到頂峰俯萎;隨后進入冬季傲宜,天氣變冷运杭,騎車人減少。因為月份和季節(jié)對租借數的影響重合函卒,且月份更加詳細辆憔,因此在隨后的建模過程中選取月份特征,刪除季節(jié)特征报嵌。?
?(4)時間(小時)對租借數的影響?
????從時間的分布上來看虱咧,每天有兩個高峰期,分別是早上8點左右和下午17點左右锚国,正好是工作日的上下班高峰期腕巡。而介于兩者之間的白天時間變化規(guī)律不明顯,可能與節(jié)假日有關血筑,因此以此為基礎需要考慮節(jié)假日和星期的影響绘沉。?
#星期、節(jié)假日和工作日的影響?
fig, axes = plt.subplots(2,1,figsize=(16, 10))?
ax1 = plt.subplot(2,1,1)
sn.pointplot(train['hour'],train['count'],hue=train['weekday'],ax=ax1)
ax1.set_title("The influence of hour (weekday)")?
ax2 = plt.subplot(2,2,3)
sn.pointplot(train['hour'],train['count'],hue=train['workingday'],ax=ax2)
ax2.set_title("The influence of hour (workingday)")
ax3 = plt.subplot(2,2,4)
sn.pointplot(train['hour'],train['count'],hue=train['holiday'],ax=ax3)
ax3.set_title("The influence of hour (holiday)")?
plt.show()?
????可以看出豺总,工作日早晚上班高峰期租借量高车伞,其余時間租借量低;節(jié)假日中午及午后租借量較高喻喳,符合節(jié)假日人們出行用車的規(guī)律另玖。?
(5)天氣對租借數的影響?
#(5) 天氣的影響?
sn.boxplot(train['weather'],train['count'])?
plt.title("The influence of weather")?
plt.show()?
(6)具體天氣因素(溫度、濕度和風速)的影響?
#(6) 溫度表伦、濕度谦去、風速的影響?
cols = ['temp', 'atemp', 'humidity', 'windspeed', 'count']sn.pairplot(train[cols])?
plt.show()?
????作出多個連續(xù)變量之間的相關圖,可以比較任意兩個連續(xù)變量之間的關系蹦哼。圖中可以明顯看出temp和atemp大致成線性關系鳄哭,但也存在一組數據顯著偏離線性相關趨勢,可能與濕度和風速有關翔怎。因此窃诉,可以認為temp杨耙、humidity和windspeed三者共同決定了atemp,因此在后續(xù)建模過程中可以刪除atemp特征飘痛。?
?進一步研究溫度珊膜、濕度和風速對租借數的影響:?
?fig, axes = plt.subplots(1,3,figsize=(24,8))?
ax1 = plt.subplot(1,3,1)?
ax2 = plt.subplot(1,3,2)?
ax3 = plt.subplot(1,3,3)?
sn.regplot(train['temp'],train['count'],ax=ax1)
sn.regplot(train['humidity'],train['count'],ax=ax2)
sn.regplot(train['windspeed'],train['count'],ax=ax3)?
ax1.set_title("The influence of temperature")?
ax2.set_title("The influence of humidity")?
ax3.set_title("The influence of windspeed")?
plt.show()?
?雖然三種天氣因素對租借數的影響比較分散,但可以明顯看出溫度和風速與租借數成正相關宣脉,濕度與租借數成負相關车柠。
?3.3 特征工程?
????綜上所述,本項目提取特征year塑猖、month竹祷、hour、workingday羊苟、holiday塑陵、weather、temp蜡励、humidity和windspeed共9個特征預測租借總數令花。其中year、month凉倚、hour兼都、workingday、holiday和weather為離散量稽寒,且由于workingday和holiday已經是二元屬性扮碧,因此其余四個需要進行獨熱編碼(one-hot)方式進行轉換。?
#特征工程
?#所選取的特征:year杏糙、month慎王、hour、workingday搔啊、holiday柬祠、weather、temp负芋、humidity和windspeed?
#(1) 刪除不要的變量
?data = data.drop(['day','weekday','season','atemp','casual','registered'],axis=1)?
#(2) 離散型變量(year漫蛔、month、hour旧蛾、weather)轉換?
column_trans = ['year','month','hour','weather']?
data = pd.get_dummies(data, columns=column_trans)?
四莽龟、構建模型?
????接下來,需要對數據進行建模預測锨天,分別采用三種典型集成學習模型(普通隨機森林毯盈、極端隨機森林模型和梯度提升樹模型)、XGBoost模型和人工神經網絡模型病袄。此處均采用模型的默認參數或簡單參數搂赋,如人工神經網絡選用三層神經網絡赘阀,每層包含神經元數量相同,且均為特征個數脑奠。
?#機器學習?
#1基公、特征向量化
?col_trans = ['holiday', 'workingday', 'temp', 'humidity', 'windspeed', 'year_2011', 'year_2012', 'month_1', 'month_2', 'month_3', 'month_4', 'month_5', 'month_6', 'month_7', 'month_8', 'month_9', 'month_10', 'month_11', 'month_12', 'hour_0', 'hour_1', 'hour_2', 'hour_3', 'hour_4', 'hour_5', 'hour_6', 'hour_7', 'hour_8', 'hour_9', 'hour_10', 'hour_11', 'hour_12', 'hour_13', 'hour_14', 'hour_15', 'hour_16', 'hour_17', 'hour_18', 'hour_19', 'hour_20', 'hour_21', 'hour_22', 'hour_23', 'weather_1', 'weather_2', 'weather_3', 'weather_4']?
X_train = data[col_trans].iloc[:10886]?
X_test = data[col_trans].iloc[10886:]
Y_train = data['count'].iloc[:10886]
from sklearn.feature_extraction import DictVectorizer?
vec = DictVectorizer(sparse=False)?
X_train = vec.fit_transform(X_train.to_dict(orient='record'))?
X_test = vec.fit_transform(X_test.to_dict(orient='record'))?
?#分割訓練數據?
from sklearn.model_selection import train_test_splitx_train, x_test, y_train, y_test = train_test_split(X_train, Y_train, test_size=0.25, random_state=40)
?#2、建模預測宋欺,分別采用常規(guī)集成學習方法轰豆、XGBoost和神經網絡三大類模型from sklearn.ensemble import RandomForestRegressor
?from sklearn.ensemble import ExtraTreesRegressor
?from sklearn.ensemble import GradientBoostingRegressor
?from xgboost import XGBRegressor?
from sklearn.neural_network import MLPRegressor
?from sklearn.metrics import r2_score
?#(1)集成學習方法——普通隨機森林?
rfr = RandomForestRegressor()?
rfr.fit(x_train,y_train)?
#print(rfr.fit(x_train,y_train))
?rfr_y_predict = rfr.predict(x_test)?
print("集成學習方法——普通隨機森林回歸模型的R方得分為:",r2_score(y_test,rfr_y_predict))?
?#(2)集成學習方法——極端隨機森林?
etr = ExtraTreesRegressor()?
etr.fit(x_train,y_train)?
#print(etr.fit(x_train,y_train))?
etr_y_predict = etr.predict(x_test)?
print("集成學習方法——極端隨機森林回歸模型的R方得分為:",r2_score(y_test,etr_y_predict))?
?#(3)集成學習方法——梯度提升樹?
gbr = GradientBoostingRegressor()?
gbr.fit(x_train,y_train)?
#print(gbr.fit(x_train,y_train))?
gbr_y_predict = gbr.predict(x_test)?
print("集成學習方法——梯度提升樹回歸模型的R方得分為:",r2_score(y_test,gbr_y_predict))?
?#(4) XGBoost回歸模型?
xgbr = XGBRegressor()?
xgbr.fit(x_train,y_train)?
#print(xgbr.fit(x_train,y_train))?
xgbr_y_predict = xgbr.predict(x_test)?
print("XGBoost回歸模型的R方得分為:",r2_score(y_test,xgbr_y_predict)) #(5) 神經網絡回歸模型?
mlp = MLPRegressor(hidden_layer_sizes=(47,47,47),max_iter=500)mlp.fit(x_train,y_train)?
mlp_y_predict = mlp.predict(x_test)?
print("神經網絡回歸模型的R方得分為:",r2_score(y_test,mlp_y_predict))?