如何使用Python对Citi Bike 990万次的骑行数据分析

网友投稿 535 2022-05-29

Citi Bike是纽约市在2013年5月27日启动的一项自行车共享计划,由“花旗银行”(Citi Bank)赞助并取名为“花旗单车”(Citi Bike)。在曼哈顿,布鲁克林,皇后区和泽西市有8,000辆自行车和500个车站。为纽约的居民和游客提供一种方便快捷,并且省钱的出行方式。

人们随处都能借到Citi Bank,并在他们的目的地归还。使用Citi Bank的方法很简单,购买会员资格,然后在附近查找可以使用的Citi Bank,使用会员key解锁,在有效时间内(30或45分钟)归还并锁定Citi Bank。由于每个Citi Bank的租赁站点都有GPS位置信息,因此可以记录到用户租赁和骑行过程中的数据。“Citi Bank”官网提供了用户每一次骑行的数据,包括租赁开始及结束的位置及时间,整个骑行过程的时间,自行车ID,以及用户的性别和出生日期等数据。我们将使用python对“Citi Bank”2015年的数据进行分析,以了解纽约自行车共享计划的情况。并回答诸如谁在使用Citi Bike?他们什么时间开始骑行?每次骑行的时间和距离,以及哪些骑行线路最受欢迎等问题。

开始前的准备工作

首先我们将需要使用的库文件导入到python中,这里包括numpy、pandas、datetime和用于数据可视化的pyplot,后面根据不同的分析方向我们还会陆续导入其他的库文件。

import numpy as npimport pandas as pdimport time,datetimeimport matplotlib.pyplot as plt #读取Citi Bike的数据并创建数据表 cb1=pd.DataFrame(pd.read_csv('201501-citibike-tripdata.csv'))

Citi Bike的数据是按月存储的,因此我们需要逐月读取并将各个月份的数据进行拼接。

#对导入的数据表进行拼接,汇总后的数据表名为cbcb=cb1.append(cb2,ignore_index=False)#查看数据表维度cb.shape (9937969, 15)

2015年Citi Bike数据共包含993万行,15列数据。其中每一行数据都代表一次“Citi Bank”的租借和骑行记录。

惊人的990万次骑行

我们首先对2015年“Citi Bank”的数据中的几个关键指标进行统计,在一年***有497个租赁点,也就是车站,8477辆自行车被使用。自行车的使用次数更是高达993万次,平均算下来每辆自行车每天被租借3.21次。可见人们对“Citi Bank”的热情。而每次的骑行时间平均为16.13分钟。

以下为每个关键指标的统计代码和结果。

#唯一租赁点数量计数len(cb['start station name'].unique())497#唯一自行车ID计数len(cb['bikeid'].unique())8477#骑行次数计数cb['starttime'].count()9937969#每辆自行车租借频率cb['bikeid'].count()/len(cb['bikeid'].unique())1172.3450513153239#每辆自行车每日租借频率cb['bikeid'].count()/len(cb['bikeid'].unique())/3653.2119042501789696#每次租借平均时长(分钟)cb['tripduration'].sum()/cb['bikeid'].count()/6016.134794237132358

2015年的Citi Bike的使用量整体趋势由低到高,2月Citi Bike的使用量最低,然后使用量逐月增长,直到9月出现使用量最高值。11月使用量开始下降。这可能是由于季节和气温因素导致的。我们下面按季度对骑行数据进行汇总并进行对比。

以下是按月汇总骑行数据并汇总折线图的代码。

#对starttime设置日期格式cb['starttime']=pd.to_datetime(cb['starttime'])#将starttime设置为数据表索引cb = cb.set_index('starttime')#按月对骑行数据进行计数cb_month=cb.resample('M',how=len)#提取汇总后的bikeid字段group_cb_month=cb_month['bikeid']#汇总按月汇总的骑行次数折线图plt.rc('font', family='STXihei', size=15) a=np.array([1,2,3,4,5,6,7,8,9,10,11,12]) plt.plot(group_cb_month,'g8',group_cb_month,'g-',color='#39A2E1',linewidth=3,markeredgewidth=3,markeredgecolor='#39A2E1',alpha=0.8) plt.xlabel('月份') plt.ylabel('租赁骑行次数') plt.title('2015年Citi Bike每月骑行次数') plt.grid( color='#95a5a6',linestyle='--', linewidth=1 ,axis='y',alpha=0.4) plt.xticks(a, ('1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月') ) plt.show()

从2015年四个季度的数据来看,用户对Citi Bike的使用受季节因素的影响,第一季度气温最低,Citi Bike的使用量也较低。第二季度第三季度为夏秋交替,使用量最高。

#按季度对骑行数据进行计数cb_quarterly=cb.resample('Q',how=len)#提取按季度汇总后的bikeid字段group_cb_quarterly=cb_quarterly['bikeid']#绘制按季度汇总的骑行次数柱状图plt.rc('font', family='STXihei', size=15)a=np.array([1,2,3,4]) plt.bar([1,2,3,4],group_cb_quarterly,color='#39A2E1',alpha=0.8,align='center',edgecolor='white') plt.xlabel('季度') plt.ylabel('租赁骑行次数') plt.title('2015年Citi Bike每季度骑行次数') plt.legend(['次数'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.xticks(a,('一季度','二季度','三季度','四季度')) plt.show()

哪些人在使用Citi Bike ?

我们很好奇993万次骑行这个庞大的数据后面是哪些人在使用Citi Bike。由于获得的数据中只有用户性别,出生日期和会员类别的数据,因此我们仅从这三个维度对Citi Bike的用户进行简单的描述。

66%的男性用户使用Citi Bike

2015年使用Citi Bike服务的用户中,66%为男性用户,女性用户的占比为20%,另外还有13%的用户性别未知。这让我想起了北京自重25公斤的共享单车。

以下是计算用户性别占比和绘制饼图的代码。

#按用户性别进行汇总并计算不同性别的占比 user_gender=cb.groupby('gender')['bikeid'].agg(len)/cb["bikeid"].count()*100#汇总用户性别占比饼图 plt.rc('font', family='STXihei', size=15) colors = ["#052B6C","#39A2E1","#EA1F29"]name=['未知', '男性', '女性'] plt.pie(user_gender,labels=name,colors=colors,explode=(0, 0, 0),startangle=60,autopct='%1.1f%%') plt.title('Citi Bike用户性别占比') plt.legend(['未知', '男性', '女性'], loc='upper left') plt.show()

30~50岁用户热衷于骑行

我们将Citi Bike的用户年龄分为四组,0~18岁为少年组,18~30岁为青年组,30~50岁为中年组,50岁以上为老年组。其中少年组的租借和骑行次数最少,中年组的租借和骑行次数最高,其次为青年组。50岁以上的老年组也有相当数量的记录。

以下是对用户年龄分组和汇总柱状图的代码,用户年龄由出生日期和当前年份计算得出,其中包含部分极端值。

#查看出生日期的范围cb['birth year'].min(),cb['birth year'].max() (1885.0, 1999.0)

这里1885年很怪异,按照这个出生日期,2016年时用户的年龄已经达到了131岁。我们不知道其中的具体原因,但由于Citi Bike整体的数据较为规范不需要清洗,因此我们选择保留这个值。

#使用2015年与用户出生日期计算年龄 cb['age']=2015-cb['birth year'] #用户最小年龄17岁,最大年龄131岁 cb['age'].min(),cb['age'].max() (17.0, 131.0) #对用户年龄进行分组 bins = [0, 18, 30, 50, 131] group_age = ['少年', '青年', '中年', '老年']  cb['group_age'] = pd.cut(cb['age'], bins, labels=group_age) #按年龄分组对数据进行汇总 user_age=cb.groupby('group_age')['group_age'].agg(len) #生成用户年龄分布柱状图 plt.rc('font', family='STXihei', size=15) a=np.array([1,2,3,4]) plt.bar([1,2,3,4],user_age,color='#052B6C',alpha=0.8,align='center',edgecolor='white') plt.xlabel('年龄分组') plt.ylabel('租赁次数') plt.title('Citi Bike用户年龄分布') plt.legend(['次数'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.xticks(a,('少年','青年','中年','老年')) plt.show()

86%的用户为年费会员

Ctii Bike对纽约本地居民,短期停留和游客提供了三种会员期限选择,按Citi Bike官网的推荐,年度会员适合于本地居民,也是最划算的一种租赁方式。3天的会员适合于短期停留或居住的用户,1天的会员适合于游客。因此我们也可以按不同的会员期限反向推断用户的身份。

在2015年的数据表中,1天和3天的会员统称为Customer,年度会有成为Subscriber。从下面的占比数据中可以看出,绝大部分Citi Bike的用户为年度会员,占比高达86%。反向推测绝大部分用户为纽约本地常住居民。

以下为计算用户会员类别和汇总饼图的代码。

#按用户的会员类别进行汇总并计算占比 user_type=cb.groupby('usertype')['bikeid'].agg(len)/cb["bikeid"].count()*100#汇总用户会员类别饼图 plt.rc('font', family='STXihei', size=15) colors = ["#EA1F29","#39A2E1"]name=['Customer', 'Subscriber'] plt.pie(user_type,labels=name,colors=colors,explode=(0,0),startangle=43,autopct='%1.1f%%') plt.title('Citi Bike用户类别占比') plt.legend(['Customer', 'Subscriber'], loc='upper left') plt.show()

用户的骑行时间及速度

在993万次骑行的数据背后,是否存在一些规律?我们选择了5月(春季)的数据对用户使用Citi Bike的行为进行了统计和分析,这里既包括使用Citi Bike的时间,也包括骑行速度,热门租赁站点和骑行线路。

每日早晚是使用高峰

Citi Bike的使用者大部分为城市居民,少部分为游客。在一天中的上午7点—8点和下午的5点~6点是Citi Bike的使用高峰。这两个时间正好是上下班的高峰时间。除此之外中午12点~下午4点也有较高的使用量。

以下是24小时使用趋势和绘制折线图的代码。

#读取5月数据并创建数据表cb5=pd.DataFrame(pd.read_csv('201505-citibike-tripdata.csv'))#对starttime字段进行分列time_split = pd.DataFrame((x.split(' ') for x in cb5.starttime),index=cb5.index,columns=['start_date','star_time'])#对分列后的表与原数据表进行拼接cb5=pd.merge(cb5,time_split,right_index=True, left_index=True)#更改star_time字段为日期格式cb5['star_time']=pd.to_datetime(cb5['star_time'])#设置star_time为表索引cb5 = cb5.set_index('star_time')#按小时对数据进行汇总star_hour=cb5.resample('H',how=len)#提取按小时汇总的bikeid数据ride_hour=star_hour["bikeid"]#绘制24小时折线图plt.rc('font', family='STXihei', size=15) a=np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]) plt.plot(ride_hour,'8',ride_hour,'g-',color='#052B6C',linewidth=3,markeredgewidth=3,markeredgecolor='#052B6C',alpha=0.8) plt.xlabel('24小时') plt.ylabel('租赁次数') plt.title('Citi Bike用户24小时租赁次数') plt.grid( color='#95a5a6',linestyle='--', linewidth=1 ,axis='y',alpha=0.4) plt.xticks(a, ('0','','','','','5','','','','','10','','','','','15','','','','','20','','','') ) plt.show()

骑行时间多在20分钟以内

在骑行时间方面,按照不同的会员类别Citi Bike对时间有不同的限制,1天和3天会员每次骑行的限制时间为30分钟,超过30分钟每增加15分钟收费4美金。年度会有每次骑行限制时间为45分钟,超出10分钟收费2.5美金,再次超出逐级收费。Citi Bike鼓励用户短途使用并且在接近限制时间时重新租赁新的自行车,避免产生超时费用,并且提高自行车的周转率。

我们对5月份用户的骑行时间进行处理和分组,通过下面的图表可以看出大部分用户的使用时间为10~20分钟。其次为30分钟和5分钟以内。超过30分钟的使用次数较少。即使在86%的用户为年度会员的情况下,使用时间在30-45分钟的情况也较少。由此推测大部分的骑行为短途。

以下为骑行时间分组和绘制柱状图的代码。

#对骑行时间进行分组bins = [0, 300, 600, 1200, 1800, 2700, 2825827]#为每个分组命名group_tripduration = ['5分钟', '10分钟', '20分钟', '30分钟', '45分钟', '更长时间']  #在原数据表中增加时间分组字段cb5['group_tripduration'] = pd.cut(cb5['tripduration'], bins, labels=group_tripduration)#按分组对数据进行汇总计数group_minute=cb5.groupby('group_tripduration')['group_tripduration'].agg(len)#汇总骑行时间分组柱状图plt.rc('font', family='STXihei', size=15) a=np.array([1,2,3,4,5,6]) plt.bar([1,2,3,4,5,6],group_minute,color='#9F713F',alpha=0.8,align='center',edgecolor='white') plt.xlabel('时间分组') plt.ylabel('骑行次数') plt.title('Citi Bike骑行时间分布') plt.legend(['时间'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.xticks(a,('5分钟','10分钟','20分钟','30分钟', '45分钟','更长时间')) plt.show()

平均骑行速度6.3公里/小时

在Citi Bike的数据表中并没有直接提供每次骑行的速度数据,但包含了每个开始和结束站点的经纬度坐标。我们通过这些坐标计算出了两个站点间的距离,并匹配到对应的骑行中。在经过与本次骑行所耗费的时间计算出这次骑行的平均速度。通过对5月的数据进行处理,用户的平均骑行速度为6.3公里/小时。

以下是计算骑行速度的代码。

#导入库文件from math import radians, cos, sin, asin, sqrt   import numpy as npimport pandas as pd#通过经纬度计算距离的函数def haversine(lon1, lat1, lon2, lat2): # 经度1,纬度1,经度2,纬度2 (十进制度数)       """      Calculate the great circle distance between two points       on the earth (specified in decimal degrees)      """       # 将十进制度数转化为弧度       lon1= map(radians, np.array(lon1))       lat1= map(radians, np.array(lat1))    lon2= map(radians, np.array(lon2))    lat2= map(radians, np.array(lat2))    lon1 = np.array(list(lon1)).reshape(-1,1)    lon2 = np.array(list(lon2)).reshape(-1,1)    lat1 = np.array(list(lat1)).reshape(-1,1)    lat2 = np.array(list(lat2)).reshape(-1,1)    # haversine公式       dlon = lon2 - lon1    dlat = lat2 - lat1      a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2       c = 2 * np.arcsin(np.sqrt(a))        r = 6371 # 地球平均半径,单位为公里       return c * r * 1000  #计算每次骑行的米数并增加骑行距离字段cb5["meter"]=haversine(cb5["start station longitude"],cb5["start station latitude"],cb5["end station longitude"],cb5["end station latitude"])#将原数据表中的骑行时间由秒转化为小时cb5["duration_hour"]=cb5["tripduration"]/3600#将米转化为公里并与小时计算出速度cb5["speed"]=cb5["meter"]/1000/cb5["duration_hour"] 现在我们有了每次骑行的速度,还需要计算出用户平均的骑行速度。#将每次骑行的米数求和并转化为公里km=cb5["meter"].sum()/1000#将每次骑行的秒数求和并转化为小时hour=cb5["tripduration"].sum()/3600#计算平均速度speed=km/hour#平均速度为6.31公里/小时speed6.3101247093495

骑行与气温是否存在关联?

在990万次骑行中,第一季度用户对Citi Bike的使用量最低,第三季度使用量最高。有明显的季节因素。下面我们导入纽约市2015年的气象数据,来看下天气因素与Citi Bike间是否存在关联,并试着用天气的变化来预测Citi Bike的使用量。

绘制每日最高气温与Citi Bike使用量的散点图,从图中可以发现Citi Bike的使用量与日最高气温间呈正相关,随着日最高气温的增长Citi Bike的使用量也在逐渐增长。接下来我们通过回归分析发现最高气温与Citi Bike间的R平方值为0.6,两者存在正向关联。换句话说日最高气温可以解释Citi Bike租赁和骑行数量60%的变化原因。因此,我们通过这种关联分布对不同气温下的Citi Bike的租赁数量进行了预测。

以下是绘制散点图和进行回归分析的代码。

#读取2015年纽约市的气象数据weather=pd.DataFrame(pd.read_csv('823248.csv'))#提取每日最高气温数据group_weather_day=weather['TMAX']#对2015年骑行时间按天汇总计算cb_day=cb.resample('D',how=len)#提起每日骑行数量group_cb_day=cb_day['bikeid']#对每日最高气温和骑行量数据进行标准化处理from sklearn import preprocessing scaler = preprocessing.StandardScaler().fit(group_weather_day) X_Standard=scaler.transform(group_weather_day) scaler = preprocessing.StandardScaler().fit(group_cb_day) Y_Standard=scaler.transform(group_cb_day)#绘制最高气温和骑行数据散点图plt.rc('font', family='STXihei', size=15) plt.scatter(X_Standard,Y_Standard,60,color='#052B6C',marker='+',alpha=0.8,linewidth=1.5) plt.xlabel('日最高气温') plt.ylabel('Citi Bike租赁次数') plt.title('最高气温与Citi Bike之间的关系') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='both',alpha=0.4) plt.show()#设置每日最高气温为自变量XX = np.array(weather[['TMAX']])#设置每日骑行数量为因变量YY = np.array(cb_day[['bikeid']])#导入线性回归库from sklearn import linear_model clf = linear_model.LinearRegression() clf.fit (X,Y)#计算相关度clf.score(X,Y)0.60841860048565455#斜率clf.coef_ array([[ 536.64465091]])#截距clf.intercept_ array([-7282.61437278])

回归方程:

#分布对19,39和97华氏度的Citi Bike租赁量进行预测 clf.predict(19) array([[ 2913.63399443]]) clf.predict(39) array([[ 13646.52701255]]) clf.predict(97) array([[ 44771.9167651]])

骑行速度与年龄是否存在关联?

通过前面的计算我们已经知道了每次骑行用户的年龄和骑行速度信息,那么这两者之间是否存在关联呢?换句话说是否随着年龄的增长骑行速度会逐渐减慢呢?我们通过简单的一元回归来分析下两者间的联系。这里我们只使用2015年5月的数据进行分析。

#计算并增加年龄字段cb5['age']=2015-cb5['birth year']#提取年龄和骑行速度字段age_speed=cb5[['speed','age']]#去除骑行速度为0的数据age_speed=age_speed.dropna()#年龄设置为自变量XX = np.array(age_speed[['age']])#速度设置为因变量YY = np.array(age_speed[['speed']])#导入线性回归库from sklearn import linear_model#将数据导入模型clf = linear_model.LinearRegression() clf.fit (X,Y)#斜率clf.coef_ array([[-0.02899706]])#截距clf.intercept_ array([ 10.05513438])#R方clf.score(X,Y)0.011272777068773165

从R方来看年龄与骑行速度间并没有关联,骑行速度并不会随着年龄的增长而增长。这里主要的原因我想有两个。第一Citi Bike的使用场所主要在城市里,并且多为短途。第二使用者除了城市居民上下班通勤外,还有一部分的游客,他们的目的是欣赏沿途美丽的风景因此骑行速度也会较慢。

#20岁的骑行速度预测为9.4公里 clf.predict(20)array([[ 9.47519327]]) #50岁的骑行速度预测为8.6公里 clf.predict(50)array([[ 8.60528161]])

哪些骑行线路最受欢迎?

在Citi Bike的官网上有一个频道叫Explore NYC ,里面提供了最热门的骑行线路和沿途的著名景观。我们对5月的数据进行统计,找出最受欢迎的骑行开始地点。以及受欢迎的骑行线路。

Top10受欢迎的租赁点

对5月骑行数据进行统计,找出前10个最受欢迎的骑行开始地点及经纬度数据。将经纬度数据输入到plotly工具中,绘制出Citi Bike 2015年5月在纽约最受欢迎的前10个租赁地点。

以下是前10个最受欢迎租赁点的统计代码及结果。

#使用数据透视找出前5个最受欢迎地点的经纬度数据 start_station=pd.pivot_table(cb5,index=["start station name","start station latitude","start station longitude"],values=['bikeid'],aggfunc=[len],fill_value=0,margins=True).head(10)

热门骑行线路追踪

继续前面的操作,在数据透视表的字段中增加结束地点和经纬度数据就可以看到一条完整的骑行线路数据,这里以1 Ave & E 15 St为骑行开始地点,使用plotly工具描绘出一条用户的骑行线路。上面的图中是从Google街景中截图的图片,也是骑行线路开始的地点。下面是plotly工具显示出的本次骑行开始和结束的位置。由于我们只有开始和结束两个经纬度数据,因此显示为一条直线。

借助Google地图的骑行路线我们模拟出了用户这两点之间可能的骑行路线,这并非用户的真实骑行路线。但可以帮助我们更加详细的了解用户使用Citi Bike的情况。

以下是通过数据透视获得骑行位置和经纬度的代码。

#获得骑行开始和结束地点及经纬度数据 end_station=pd.pivot_table(cb5,index=["start station name","start station latitude","start station longitude","end station latitude","end station longitude","end station name"],values=['bikeid'],aggfunc=[len],fill_value=0,margins=True).head(10)

小结

我们使用Python对纽约自行车共享系统Citi Bike 990万次骑行数据的简单分析,在惊叹于用户对自行车共享系统的热爱和使用频率的同时,也学习到很多用户骑行的信息。通过本次分析可以得到以下结论,使用Citi Bike的用户以纽约市的中年男性为主,在每天的早晨的8点和傍晚6点是Citi Bike的使用高峰。由于Citi Bike对超时单独收取费用,用户的骑行时间多数在20分钟以内。用户对Citi Bike的使用受季节和气温的影响,相关度达到0.6,夏秋两季租赁量最大,冬季最低。用户的年龄与骑行速度关联并不紧密,平均骑行速度为6.3公里/小时。

本文节选自《从Excel到Python——数据分析进阶指南》

内容简介

本书通过Python与Excel的功能对比介绍如何使用Python通过函数式编程完成Excel中的数据处理及分析工作。

在Python中pandas库用于数据处理,本书从1787页的pandas官网文档中总结出最常用的36个函数,通过这些函数介绍如何通过Python完成数据生成和导入、数据清洗、预处理,以及最常见的数据分类,数据筛选,分类汇总,透视等最常见的操作。

如何使用Python对Citi Bike 990万次的骑行数据分析

王彦平 (蓝鲸),Google分析个人资格认证,专注于网站数据分析实践及Google Analytics应用研究。创建“蓝鲸的网站分析笔记”博客分享网站分析经验与技巧,被Avinash Kaushia先生推荐为探索Google Analytics必读的中文博客。同时王彦平还是艾瑞网专家,艾瑞商学院讲师,Digital Analytics Association会员和互联网著名开放式分类目录(Open Directory Project)DMOZ网站的志愿编辑。

电子邮件:cliff1980@gmail.com

新浪微博:@蓝鲸碎碎念

灵活优惠的购书

欢迎注册成为异步社区(www.epubit.com.cn)用户,即可享受下单购买图书、下载随书附赠的资源以及与作译者互动。

特别优惠

购买本电子书的读者专享异步社区优惠券。 使用方法:注册成为社区用户,在下单购书时输入“57AWG”,然后点击“使用优惠码”,即可享受电子书8折优惠(本优惠券只可使用一次)。

本文转载自异步社区

数据挖掘 Python

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:沙拉翻译网页双语显示,程序员必备,是神器没错了
下一篇:华为云与阿里云使用心得
相关文章