項目數(shù)據(jù)來源于kaggle項目 Bike Share Demand,使用Python對數(shù)據(jù)進(jìn)行了可視化分析:










分析過程代碼如下:
1. 提出問題
影響共享單車租用數(shù)量的因素有哪些?影響程度如何?
2. 理解數(shù)據(jù)
import numpy as np
import pandas as pd
bike_train = pd.read_csv(".../train.csv")
bike_train.head()
| datetime | season | holiday | workingday | weather | temp | atemp | humidity | windspeed | casual | registered | count | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2011/1/1 0:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 81 | 0 | 3 | 13 | 16 |
| 1 | 2011/1/1 1:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0 | 8 | 32 | 40 |
| 2 | 2011/1/1 2:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0 | 5 | 27 | 32 |
| 3 | 2011/1/1 3:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 75 | 0 | 3 | 10 | 13 |
| 4 | 2011/1/1 4:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 75 | 0 | 0 | 1 | 1 |
bike_train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10886 entries, 0 to 10885
Data columns (total 12 columns):
datetime 10886 non-null object
season 10886 non-null int64
holiday 10886 non-null int64
workingday 10886 non-null int64
weather 10886 non-null int64
temp 10886 non-null float64
atemp 10886 non-null float64
humidity 10886 non-null int64
windspeed 10886 non-null float64
casual 10886 non-null int64
registered 10886 non-null int64
count 10886 non-null int64
dtypes: float64(3), int64(8), object(1)
memory usage: 1020.6+ KB
變量說明:
- datatime 日期+時間
- season 1=春 2=夏 3=秋 4=冬
- holiday 1=節(jié)假日 0=非節(jié)假日
- workingday 1=工作日 0=周末
- weather 1=晴天多云 2=霧天陰天 3=小雪小雨 4=大雨大雪大霧
- temp 氣溫攝氏度
- atemp 體感溫度
- humidity 濕度
- windspeed 風(fēng)速
- casual 非注冊用戶個數(shù)
- registered 注冊用戶個數(shù)
- count 給定日期時間(每小時)總租車人數(shù)
3.數(shù)據(jù)清洗
1)數(shù)據(jù)預(yù)處理:數(shù)據(jù)完整無缺失值
2)特征工程:從datetime中提取年、月、日、時、星期等時間信息
import calendar
bike_train['date']=bike_train.datetime.apply(lambda x :x.split()[0])
bike_train['year']=bike_train.date.apply(lambda x:x.split("-")[0])
bike_train['month']=bike_train.date.apply(lambda x:x.split("-")[1])
bike_train['day']=bike_train.date.apply(lambda x:x.split("-")[2])
bike_train['hour']=bike_train.datetime.apply(lambda x: x.split()[1].split(":")[0])
bike_train['weekday'] = bike_train.datetime.apply(lambda x: calendar.day_name[pd.to_datetime(x).weekday()])
#把季節(jié)和天氣轉(zhuǎn)換成文字
bike_train['season']=bike_train.season.map({1: "Spring", 2 : "Summer", 3 : "Fall", 4 :"Winter" })
bike_train[:50:20]
| datetime | season | holiday | workingday | weather | temp | atemp | humidity | windspeed | casual | registered | count | date | year | month | day | hour | weekday | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2011-01-01 00:00:00 | Spring | 0 | 0 | 1 | 9.84 | 14.395 | 81 | 0 | 3 | 13 | 16 | 40544 | 2011 | 1 | 1 | 0 | Saturday |
| 20 | 2011-01-01 20:00:00 | Spring | 0 | 0 | 2 | 16.4 | 20.455 | 87 | 16.9979 | 11 | 25 | 36 | 40544 | 2011 | 1 | 1 | 20 | Saturday |
| 40 | 2011-01-02 17:00:00 | Spring | 0 | 0 | 1 | 13.94 | 16.665 | 57 | 12.998 | 7 | 58 | 65 | 40545 | 2011 | 1 | 2 | 17 | Sunday |
4. 可視化分析
1)單車使用量在天氣維度上的分析(天氣、溫度、濕度和風(fēng)速相關(guān)性)
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
#租車輛與天氣的關(guān)系
fig = plt.subplots(figsize=(5,5))
sns.boxplot(data=bike_train, y='count', x='weather')
<matplotlib.axes._subplots.AxesSubplot at 0x1146cf2b0>

可以看到,整體租車量受天氣影響較為明顯,極端的天氣租車數(shù)量減少。
4級天氣看起來有些異常,于是統(tǒng)計數(shù)據(jù)條目:
#統(tǒng)計各天氣數(shù)據(jù)數(shù)量
weather_count = pd.DataFrame(bike_train.assign(weather_count=0).groupby('weather').weather_count.apply(len).reset_index())
weather_count['weather']=weather_count.weather.map({1:"晴天、多云",2:"霧天、陰天",3:"小學(xué)、小雪",4:"大風(fēng)、大雪、大雨"})
weather_count
| weather | weather_count | |
|---|---|---|
| 0 | 晴天、多云 | 7192 |
| 1 | 霧天、陰天 | 2834 |
| 2 | 小學(xué)、小雪 | 859 |
| 3 | 大風(fēng)、大雪、大雨 | 1 |
可以看到,4級天氣只有1條數(shù)據(jù)記錄,這種極端天氣情況出現(xiàn)的數(shù)據(jù)極少。
#使用量與溫度、濕度、風(fēng)速的關(guān)系
#繪制heatmap
corrMatt = bike_train[["temp","atemp","humidity","windspeed","count"]].corr()
mask = np.array(corrMatt)
mask[np.tril_indices_from(mask)] = False
fig = plt.figure(figsize=(10, 10))
sns.heatmap(corrMatt, mask=mask,square=True,annot=True)

溫度和使用量有正相關(guān)關(guān)系,濕度與使用量有負(fù)相關(guān)關(guān)系,風(fēng)速和使用量幾乎不相關(guān)。
#繪制線性圖像
fig,(ax1,ax2,ax3) = plt.subplots(1,3, figsize=(12,5))
sns.regplot(x="temp", y="count", data=bike_train,ax=ax1)
sns.regplot(x="windspeed", y="count", data=bike_train,ax=ax2)
sns.regplot(x="humidity", y="count", data=bike_train,ax=ax3)

由圖像可看出,使用量與溫度、濕度和風(fēng)速的關(guān)系,相關(guān)性有限。
2)單車使用量在時間維度上的分析(月份、季節(jié)、時間、星期等相關(guān)性)
#租車總量和工作日、節(jié)假日的關(guān)系
fig,(ax1,ax2) = plt.subplots(1,2, figsize=(10,5))
sns.boxplot(data=bike_train, y='count', x='workingday',ax=ax1)
sns.boxplot(data=bike_train, y='count', x='holiday',ax=ax2)
ax1.set(xticklabels=['Not holiday','Holiday'])
ax2.set(xticklabels=['Weekend','Workday'])

總量來看,節(jié)假日和周末/工作日的租車數(shù)量基本相同。
fig,axes = plt.subplots(3,1, figsize=(12,20))
#租車輛按月份、年份統(tǒng)計
month_Aggregated = pd.DataFrame(bike_train.groupby(['year','month'])['count'].mean()).reset_index()
sns.barplot(data=month_Aggregated,x="month",y="count",hue='year',ax=axes[0])
axes[0].set(xlabel='Month', ylabel='Avearage Count',title="Average Count By Month")
#每日租車輛按季節(jié)統(tǒng)計
hour_Aggregated1 = pd.DataFrame(bike_train.groupby(['hour','season'])['count'].mean()).reset_index()
sns.pointplot(data=hour_Aggregated1,x='hour',y='count',hue='season',hue_order=['Spring','Summer','Fall','Winter'],join=True, ax=axes[1])
axes[1].set(xlabel='Hour', ylabel='Avearage Count',title="Average Count By Hour Across Season")
#日租車輛按周統(tǒng)計
hour_Aggregated2 = pd.DataFrame(bike_train.groupby(['hour','weekday'])['count'].mean()).reset_index()
sns.pointplot(data=hour_Aggregated2,x='hour',y='count',hue='weekday',join=True,ax=axes[2])
axes[2].set(xlabel='Hour', ylabel='Avearage Count',title="Average Count By Hour Across weekday")

圖1可以看出2012年共享單車的使用量高于2011年,消費人群增加了1.5~2倍。兩年內(nèi)租車量隨月份變化的趨勢相同,6、7、8月有明顯的高需求。
圖2可以看出租車時間高峰為上午7-8點,下午5-6點,符合上下班通勤的時間范圍。季節(jié)上看,春天的租車輛明顯少于其它三個季節(jié)。
圖3可以看出工作日租車輛主要為上下班時間,周末租車輛主要集中在10am-4pm之間。
3)單車使用量與注冊用戶/非注冊用戶的相關(guān)性
fig,axes=plt.subplots(2,1,figsize=(12,10))
hour_Transform=pd.melt(bike_train[['hour','casual','registered','weekday']],id_vars=['hour','weekday'],value_vars=['casual','registered'])
hour_Aggregated3=pd.DataFrame(hour_Transform.groupby(['hour','variable'])['value'].mean()).reset_index()
sns.pointplot(data=hour_Aggregated3,x='hour',y='value',hue='variable',hue_order=['casual','registered'],join=True,ax=axes[0])
weekday_Aggregated=pd.DataFrame(hour_Transform.groupby(['weekday','variable'])['value'].mean()).reset_index()
sns.barplot(data=weekday_Aggregated,x='weekday',y='value',hue='variable',order=['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],ax=axes[1])

注冊人數(shù)使用量明顯高于非注冊人數(shù),
非會員casual主要是周末出行,為了游玩; 會員registered主要是為了周一到周五上班。
5. 總結(jié)
- 時間:需求量最大的時間為夏、秋季工作日上、下班時間,其次為周末10am-4pm。需求量最小的時間為每年1-3月,時間集中在半夜/凌晨。
- 天氣:除極端情況外(大風(fēng)、高溫、低溫、強(qiáng)降水等),天氣對租車量的影響不明顯。
- 用戶類型:注冊用戶和普通用戶行為特征明顯,前者主要為工作日通勤使用,后者為節(jié)假日出游。