這篇博客和美國西雅圖人們使用自行車情況分析與預(yù)測(初步)是姊妹篇,是對前一篇博客的延續(xù),更多的背景信息這里不多介紹,可以去以上提到的博客中找到,同樣的所有數(shù)據(jù)和源代碼都是可以重現(xiàn)的。
和上一篇博客不同的是,這篇博客不在建立模型去預(yù)測未來的情況,而是立足于數(shù)據(jù),從數(shù)據(jù)中找出有趣的東西來,換句話說,我們不再像上一篇博客一樣去使用有監(jiān)督的機(jī)器學(xué)習(xí)方法,取而代之,我們使用無監(jiān)督的學(xué)習(xí)方法,類似聚類,把具有相似行為的使用自行車的人們進(jìn)行聚類,挖掘出一些有趣的玩意。
Part 1: 數(shù)據(jù)來源
這篇博客和上篇博客使用的數(shù)據(jù)基本一致,我們可以在github下載,或者我在博客結(jié)尾會給出我本人的聯(lián)系方式,找我要也行。
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn; seaborn.set() # 這是更高級一點(diǎn)的庫,繪圖更酷炫
data = pd.read_csv(r"E:\研究生階段課程作業(yè)\python\好玩的數(shù)據(jù)分析\SeattleBike-master\Fremont_Bridge.csv",index_col = "Date", parse_dates = True)
data.sample(n = 5) #隨機(jī)抽樣5個樣本

data.columns = ["West","East"] #原來的列名太長,蛋疼,改的簡單一些
data.fillna(0,inplace=True) #填充null值,用0填充,同時就地填充:就是直接對data進(jìn)行填充,不用一系列的賦值之類的操作
data['total'] = data.West + data.East #增加一個新列,計算每個時刻的經(jīng)過這座橋的自行車總數(shù)
![Uploading 5_633120.png . . .]
data.resample('w',how = 'sum').plot()

到目前為止,好像和上篇博客沒有什么不同,處理方法也是一致的,好啦,下面開始放大招了
#因為我們想知道人們在不同日期使用自行車的習(xí)慣,我們對數(shù)據(jù)進(jìn)行透視
data_pivoted = data.pivot_table(values = ["West","East"], index = data.index.date,columns = data.index.hour,fill_value = 0)
data_pivoted.sample(n = 10)

經(jīng)過處理后的數(shù)據(jù)列有48維,為了可視化需要,我們對48列進(jìn)行降維
from sklearn.decomposition import PCA #使用自帶的pca進(jìn)行降維
xpca = PCA(n_components = 2).fit_transform(x) #只保留2維
total_trips = data_pivoted.sum(1) #計算每一天的經(jīng)過自行車總數(shù)
plt.scatter(xpca[:, 0], xpca[:, 1], c=total_trips,
cmap='cubehelix')
plt.colorbar(label='total trips');

很明顯,我們可以看出這些數(shù)據(jù)明顯可以分成兩類,下面要做的就很簡單了,聚類開始登場。首先我們使用kmeans
#首先使用kmeans,聚類的數(shù)目為2:
from sklearn.cluster import KMeans
kmeans_model = KMeans(n_clusters=2, random_state=1)
kmeans_model.fit(xpca)
labels = kmeans_model.labels_
#對聚類結(jié)果進(jìn)行可視化
plt.scatter(xpca[:,0],xpca[:,1],c = labels)
plt.colorbar(label='total trips');

果然kmeans表現(xiàn)的還是那么菜,聚類的效果并不完美,下面我們使用高斯混合模型聚類
#使用高斯混合模型,進(jìn)行聚類
from sklearn.mixture import GMM
gmm = GMM(2, covariance_type='full', random_state=0)
gmm.fit(xpca)
cluster_label = gmm.predict(xpca)
plt.scatter(xpca[:, 0], xpca[:, 1], c=cluster_label);

還是高斯混合模型靠譜啊,多試幾種方法,找出最適合你的方法吧
data_pivoted["Cluster"] = cluster_label
data_new = data.join(data_pivoted["Cluster"],on = data.index.date)
data_new.sample(10)

#對兩個聚類按照時間分別作圖
#data_new_0 #包含cluster為0的所有數(shù)據(jù)
#data_new_1 #包含cluser為1的所有數(shù)據(jù)
data_new_0 = data_new[data_new.Cluster == 0]
data_new_1 = data_new[data_new.Cluster == 1]
by_hour_0 = data_new_0.groupby(data_new_0.index.time).mean()
by_hour_1 = data_new_1.groupby(data_new_1.index.time).mean()
by_hour_0[["West","East","total"]].plot()
plt.xlabel("time")
plt.ylabel("mean of bikes")

這個結(jié)果相當(dāng)耐人尋味,我們可以看到,差不多在早上八點(diǎn)左右,自行車數(shù)量到達(dá)第一個巔峰,然后下午五點(diǎn)左右,自行車數(shù)量到達(dá)第二個巔峰。是不是這些日子都是工作日呢,大家騎著自行車去上班,換句話說,第一個聚類難道都是工作日。這個問題有待繼續(xù)解答,我們再看第二個聚類的情況.
by_hour_1[["West","East","total"]].plot()
plt.xlabel("time")
plt.ylabel("mean of bikes")

和第一個聚類相比,這個結(jié)果沒有出現(xiàn)明顯的波峰,大約在下午兩年的時候,自行車數(shù)量最多,好吧,你肯定在猜測,這些日子是不是周末呢。大家吃過中飯,騎車出來浪呢。為了搞清楚這些疑問,我們計算每個日期對應(yīng)的星期幾。
plt.scatter(xpca[:,0],xpca[:,1],c = data_pivoted.index.dayofweek,cmap=plt.cm.get_cmap('jet', 7))
cb = plt.colorbar(ticks=range(7))
cb.set_ticklabels(['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun'])

我們可以得出這樣的結(jié)論,周六和周末,人們對自行車的使用有著很大的相似,而周一到周五人們對自行車的使用也很相似,結(jié)合前面的聚類結(jié)果
但是我們很奇怪的發(fā)現(xiàn)一個現(xiàn)象:有一些工作日的人們表現(xiàn)的和周末很相似,這些特別的日子具體是神馬日子的,是不是節(jié)假日,另外和其他的工作日相比,周五表現(xiàn)的和周末很曖昧不清,這我們需要思考
另外在工作日的聚類中,我們發(fā)現(xiàn)竟然沒有一個非工作日的(至少從圖中沒有發(fā)現(xiàn)特例),結(jié)果真是這樣嗎,我們需要進(jìn)一步的使用數(shù)據(jù)進(jìn)行分析
days = ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun'] #分別對應(yīng)“dayofweek”:[0,1,2,3,4,5,6]
def get_weekday(index):
return days[index.dayofweek]
data_new_0["weekday"] = data_new_0.index.map(get_weekday)
data_new_0_exception = data_new_0[data_new_0.weekday.isin(["Sat","Sun"])]#在第一個聚類中,找特例,換句話說,就是找出這樣的周六周末,人們對自行車的使用像工作日一樣
len(data_new_0_exception) #結(jié)果和我們在上圖可視化的結(jié)果一樣,沒有一個周六周末,人們使用自行車像工作日一樣
out:0
沒有一個周末,人們使用自行車和工作日一樣,這也能從側(cè)面看出,看來美帝真心不加班啊,不像天朝,加班累成狗。
data_new_1['weekday'] = data_new_1.index.map(get_weekday)
data_new_1_exception = data_new_1[data_new_1.weekday.isin(['Mon', 'Tues', 'Wed', 'Thurs', 'Fri'])]#在第2個聚類中,找特例
len(data_new_1_exception):
out:600
倒是有不少天,人們在工作日的時候和周六周末使用自行車的習(xí)慣差不多,我們猜測這些工作日很可能是假期,真的是這樣嗎,我們來驗證一下。
date = set(data_new_1_exception.index.date)
#列出從2012-2016年,美國的所有假期
from pandas.tseries.holiday import USFederalHolidayCalendar
cal = USFederalHolidayCalendar()
holidays = cal.holidays('2012', '2016', return_name=True)
holidays_all = pd.concat([holidays,
"Day Before " + holidays.shift(-1, 'D'),
"Day After " + holidays.shift(1, 'D')])
holidays_all = holidays_all.sort_index()
holidays_all.ix[(date)]

不出意外,這些表現(xiàn)反常的工作日,全部都在假期中。大家都放假了,當(dāng)然開始騎車去浪了
最后一個問題,為什么周五的數(shù)據(jù),可視化的時候,有幾個點(diǎn)表現(xiàn)的特別反常,這幾天究竟發(fā)生了什么
fri_day = (data_pivoted.index.dayofweek == 4) #周5為true,其他為false
plt.scatter(xpca[:, 0], xpca[:, 1], c='gray', alpha=0.2)
plt.scatter(xpca[fri_day, 0], xpca[fri_day, 1], c='yellow');

weird_fridays = pivoted.index[fridays & (Xpca[:, 0] < -600)]weird_fridays
weird_fridays
out: Index([2013-05-17, 2014-05-16, 2015-05-15], dtype='object')
果然是,周五的這幾個奇異點(diǎn),果然有情況,我查閱了一下資料,這三天是一年一度的
自行車日。。。。。果然沒有無緣無故的愛
總結(jié)
關(guān)于西雅圖市人們使用自行車習(xí)慣的數(shù)據(jù)分析到此就結(jié)束了,數(shù)據(jù)蘊(yùn)含著很多信息等待我們?nèi)ネ诰?。英文過得去的話,建議直接看原文章,如果有不懂的話,再結(jié)合這中文譯文進(jìn)行參照,如果你對python和機(jī)器學(xué)習(xí),數(shù)據(jù)挖掘等感興趣,我們也可以一起學(xué)習(xí),一起分享好玩的文章。
QQ 1527927373
EMAIL 1527927373@qq.com