Bike Sharing Analysis(一)- 探索数据
1. Bike Sharing Analysis
在这章主要介绍如何分析共享单车服务数据,以及如何基于时间、天气状态特征来识别单车的使用模式。除此之外,我们还会引入可视化分析,假设检验、以及时间序列分析的概念与方法。
共享单车是城市里较为快速的通勤方式,了解用户使用共享单车所考虑的因素,对于公司和用户来说都是必须的。
从公司的角度来看,了解某一个时间段某一区域里,用户对共享单车的需求,可以显著地提升业绩以及用户满意度。同时也可以优化未来的运营成本。从用户的角度来看,可能最重要的因素是:在最短的时间内满足对单车的需求。这点与公司的利益是一致的。
在这篇文章中,我们会分析来自于华盛顿Capital Bikeshare 的单车共享数据,时间跨度从2011年1月1日,到2012年12月31日,数据以小时级别进行了聚合。也就是说, 数据中不包含单次骑行的起始与终止的位置,而是仅仅每小时的骑行次数。除此之外,数据集中还有额外的天气信息,可作为一个影响因素,影响在某个特定时间点对骑行的需求总数(天气比较差的时候可能会对骑行需求有较大的影响)。
1.1. Note
源数据获取地址:https://archive.ics.uci.edu/ml/datasets/Bike+Sharing+Dataset#
若是对此topic 比较感兴趣,可以进一步阅读论文:Fanaee-T, Hadi, and Gama, Joao, 'Event labeling combining ensemble detectors and background knowledge', Progress in Artificial Intelligence (2013): pp. 1-15, Springer Berlin Heidelberg.
虽然这个主题仅是对共享单车进行分析,但是提供的技术可以很容易应用到其他不同的共享商业模型,例如共享汽车或是共享摩托车等。
2. 理解数据
我们首先加载数据并做初始的分析。这里的目标主要是:
- 对数据有基本的了解
- 各个特征是如何分布
- 是否有缺失值
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import s3fs %matplotlib inline # load hourly data
hourly_data = pd.read_csv('s3://tang-sagemaker/workshop/bike_sharing/hour.csv')
print(f"Shape of data: {hourly_data.shape}")
print(f"Number of missing values in the data: {hourly_data.isnull().sum().sum()}") Res:
Shape of data: (17379, 17)
Number of missing values in the data: 0
查看一下统计数据:
结合Readme.txt 里对数据的说明,我们可以了解以下几点:
- instant 为 id 索引,对预测无帮助
- 离散型特征有:season,yr,mnth,hr,holiday,weekday,workingday,weathersit
- 数值型特征有:temp,atemp,hum,windspeed,casual,registered,cnt
- 数值型特征中temp、atemp,hum,windspeed 均已做标准化处理,casual,registered,cnt未做标准化处理
- cnt 是 casual 与 registered 相加之和,可以由这两个属性计算出
- dteday为时间特征
按照特征描述分类,可以分为3大类:
- 时间相关,包含条目注册时的时间:dteday,season,yr,mnth,hr,holiday,weekday,workingday
- 天气相关,包含天气条件:weathersit,temp,atemp,hun以及windspeed
- 条目本身相关,包含指定小时内,总records数:casual,registered以及cnt
3. 数据预处理
为了适应机器学习算法的需求,使预测结果更为准去,我们需要对数据做预处理。偶尔也会为了可视化的目的进行预处理展示。
3.1. 处理时间与天气特征
这里对时间与天气特征进行处理,主要不是为了方便机器学习训练,而是为了方便人可读。在数据集中,有部分特征已经被编码过,我们再次将这些特征进行编码,方便人可读:
- season 特征,它的值为1到4,分别对应的是 Spring、Summer、Fall和 Winter;
- yr特征,它的值为 0和1,分别对应2011 和 2012;
- weekday特征,值为0到6,分别对应一周的每天(0: Sunday,6: Saturday)
- weathersit特征,值为1到4,分别对应的是clear, cloudy, light_rain_snow, heavy_rain_snow
- hum特征,被缩放到了0到1区间内,原始应为0到100区间内
- windspeed特征,被缩放到了0到1区间内,原始应为0到67区间内
首先处理 season、yr以及weekday 特征:
preprocessed_data = hourly_data.copy() # temperal features
seasons_map = {1:"Spring", 2:"Summer", 3:"Fall", 4:"Winter"}
yr_map = {0:2011, 1:2012}
weekday_mapping = {0:'Sunday', 1:'Monday', 2:'Tuesday', 3:'Wednesday', 4:'Thursday', 5:'Friday', 6:'Saturday'} preprocessed_data['season'] = preprocessed_data['season'].apply(lambda x: seasons_map[x])
preprocessed_data['yr'] = preprocessed_data['yr'].apply(lambda x: yr_map[x])
preprocessed_data['weekday'] = preprocessed_data['weekday'].apply(lambda x: weekday_mapping[x])
继续处理weathersit、hum以及windspeed特征。其中hum以及wind的原始范围分别为 [0, 100] 以及[0, 67],已经被缩放为[0, 1]:
# weather features
weather_mapping = {1: 'clear', 2: 'cloudy', \
3: 'light_rain_snow', 4: 'heavy_rain_snow'} preprocessed_data['weathersit'] = preprocessed_data['weathersit'].apply(lambda x: weekday_mapping[x])
preprocessed_data['hum'] = preprocessed_data['hum'] * 100
preprocessed_data['windspeed'] = preprocessed_data['windspeed'] * 67
验证转换效果:
# validate
cols = ['season', 'yr', 'weekday', 'weathersit', 'hum', 'windspeed']
preprocessed_data[cols].sample(10, random_state=42)
3.2. Registered versus Casual分析
根据数据说明,registered + casual = cnt,我们可以验证一下:
assert (preprocessed_data['registered'] + preprocessed_data['casual'] == preprocessed_data['cnt']).all(), 'not all are equal'
首先对这2个特征进行分析的话,可以看一下它们的分布,这里会使用到seaborn,它是基于标准matplotlib构建的可视化库,为不同的统计图提供了更高级的接口。下面我们看一下registered 与 casual 骑行的分布:
# plot distribution of registered and casual
sns.distplot(preprocessed_data['registered'], label='registered')
sns.distplot(preprocessed_data['casual'], label='casual') plt.legend()
plt.xlabel('rides')
plt.title("Rides Distribution")
plt.savefig('figs/rides_distributions.png', format='png')
从分布图我们可以了解到:
- 两者的分布均为正倾斜
- 骑行的registered 用户远多于casual 用户
下面我们探索一下随时间变化的骑行数,以天为单位:
# plot evolotion of ride over time
plot_data = preprocessed_data[['registered', 'casual', 'dteday']] ax = plot_data.groupby('dteday').sum().plot(figsize=(10, 6))
ax.set_xlabel("time")
ax.set_ylabel("number of rides per day")
plt.savefig('figs/rides_daily.png', format='png')
从这个图可以看到:
- registered 用户的骑行次数,基本每天都是要明显超出casual 用户非常多
- 冬季骑行数会少下降
但是这个图中,两个时间之间的差比非常大,所以有很高的的抖动(毛刺)。有一个平滑毛刺的方法是:使用滚动平均值与滚动标准差来替换所需要可视化的值,以及它们的期望标准差情况。
plot_data = preprocessed_data[['registered', 'casual', 'dteday']]
plot_data = plot_data.groupby('dteday').sum() # define window for computing the rolling mean and standard deviation
window = 7
rolling_means = plot_data.rolling(window).mean()
rolling_deviation = plot_data.rolling(window).std() ax = rolling_means.plot(figsize=(10, 6))
ax.fill_between(rolling_means.index,
rolling_means['registered'] + 2*rolling_deviation['registered'],
rolling_means['registered'] - 2*rolling_deviation['registered'],
alpha=0.2)
ax.fill_between(rolling_means.index,
rolling_means['casual'] + 2*rolling_deviation['casual'],
rolling_means['casual'] - 2*rolling_deviation['casual'],
alpha=0.2) ax.set_xlabel("time")
ax.set_ylabel("number of rides per day")
plt.savefig('figs/rides_aggregated.png', format='png')
下面我们继续关注一下骑行请求随一天中不同小时、以及一周中不同天的分布情况。我们预期是会有随时间变化的骑行请求数,因为直觉来看,骑行的请求数应该在一天中某几个特定小时,以及一周中的特定天是有关的。
# select relevant columns
plot_data = preprocessed_data[['hr', 'weekday', 'registered', 'casual']]
plot_data = plot_data.melt(id_vars=['hr', 'weekday'], var_name='type', value_name='count') grid = sns.FacetGrid(plot_data, row='weekday', col='type', height=2.5, aspect=2.5,
row_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']) grid.map(sns.barplot, 'hr', 'count', alpha=0.5)
grid.savefig('figs/weekday_hour_distributions.png', format='png')
从这个图我们可以了解到:
- 在工作日,用户骑行时间主要分布在早上8点到下午6点之间,符合我们的预期;
- Registered 用户为共享单车的主要使用者
- Casual 用户在工作日使用共享单车有限
- 在休息日,可以明显看到对于registered 与 casual 用户骑行的分布有变化,但registered 用户仍占主要使用者大部分;两者的分布基本一致,在早上11点AM 到 6点PM的分布类似于均匀分布
总的来说,我们可以得出结论:大部分的单车使用在工作日,一般为工作时间内(如早9晚5)。
3. 天气对骑行影响分析
下面我们继续探索天气对骑行的影响。
plot_data = plot_data.melt(id_vars=['hr', 'season'], var_name='type', value_name='count')
grid = sns.FacetGrid(plot_data, row='season', col='type', height=2.5, aspect=2.5,
row_order = ['Spring', 'Summer', 'Fall', 'Winter']) grid.map(sns.barplot, 'hr', 'count', alpha=0.5)
从四个季度来看,分布基本一致,其中春季的骑行需求稍低。
再从weekday方面进一步探索:
plot_data = preprocessed_data[['weekday', 'season', 'registered', 'casual']]
plot_data = plot_data.melt(id_vars=['weekday', 'season'], var_name='type', value_name='count') grid = sns.FacetGrid(plot_data, row='season', col='type', height=2.5, aspect=2.5,
row_order = ['Spring', 'Summer', 'Fall', 'Winter']) grid.map(sns.barplot, 'weekday', 'count', alpha=0.5,
order=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'])
从这个图我们可以看到:对于registered 用户来说,工作日使用量高于休息日使用量;对于casual 用户来说,休息日使用量高于工作日使用量。
据此,我们可能会提出初始的假设:registered 用户用共享单车主要是为了通勤,而casual用户主要在周末偶尔使用共享单车。
当然,这个假设结论不能仅基于可视化图像观察,还需要有背后的统计测试进行支持。也就是我们下一节要讨论的问题。
Bike Sharing Analysis(一)- 探索数据的更多相关文章
- Kaggle Bike Sharing Demand Prediction – How I got in top 5 percentile of participants?
Kaggle Bike Sharing Demand Prediction – How I got in top 5 percentile of participants? Introduction ...
- PowerBI开发:用自然语言来探索数据--Q&A
Power BI报表的用户,肯定会被Q&A的功能惊艳到,在查看报表时,仅仅通过输入文本就可以探索数据,并且结果是可视化的,更令人惊艳的时,结果几乎是实时显示出来的.这使得Q&A Vis ...
- 一起学微软Power BI系列-官方文档-入门指南(5)探索数据奥秘
我们几篇系列文章中,我们介绍了官方入门文档与获取数据等基本知识.今天继续给大家另外一个重点,探索数据奥秘.有了数据源,有了模型,下一步就是如何解析数据了.解析数据的过程需要很多综合技能,不仅仅是需要掌 ...
- Power BI 与 Azure Analysis Services 的数据关联:1、建立 Azure Analysis Services服务
Power BI 与 Azure Analysis Services 的数据关联:1.建立 Azure Analysis Services服务
- Power BI 与 Azure Analysis Services 的数据关联:2、Azure Analysis Services与 本地版本的 SQL Analysis Services 连接
Power BI 与 Azure Analysis Services 的数据关联:2.Azure Analysis Services与 本地版本的 SQL Analysis Services ...
- Power BI 与 Azure Analysis Services 的数据关联:3、还原备份文件到Azure Analysis Services
Power BI 与 Azure Analysis Services 的数据关联:3.还原备份文件到Azure Analysis Services 配置存储设置 备份前,需要为服务器配置存储设置. ...
- Power BI 与 Azure Analysis Services 的数据关联:4、Power BI 连接到Azure Analysis Services 并展示
Power BI 与 Azure Analysis Services 的数据关联:4.Power BI 连接到Azure Analysis Services 过使用服务器名称别名,用户可以使用较短 ...
- Kibana探索数据(Discover)
总结说明: 1.先在Management/Kibana/Index Patterns 界面下添加索引模式(前提是有索引数据) 2.在Discover界面选中响应的索引模式 3.开启Kibana 查询语 ...
- Kibana探索数据(Discover)详解
设置时间过滤器 时间过滤器按照指定的时间段展示搜索结果.设置了 index contains time-based events 和 time-field 的索引模式可以使用时间过滤器. 时间过滤器默 ...
- ElasticSearch实践系列(三):探索数据
前言 经过前两篇文章得实践,我们已经了解了ElasticSearch的基础知识,本篇文章让我来操作一些更真实的数据集.我们可以利用www.json-generator.com/生成如下的文档结构: { ...
随机推荐
- LVGL 定时器
LVGL 8.0 以后好像取消了自定义任务模块,想要使用多线程只能使用系统的线程. 一.定时器结构体 typedef struct _lv_timer_t { uint32_t period; // ...
- 使用WebSocket实现实时多人答题对战游戏
前言 前两章教程,我们使用WebSocket的基础特性打造了一个小小聊天室,并在第二章对其进行了集群化改造. 系列教程回顾: [WebSocket]第一章:手把手搭建WebSocket多人在线聊天室( ...
- rpc 和 http的区别
- 飞桨PaddleLite架构研读
一.架构全景图 二.源码详细解读 1. Lite体系下似乎有多种 op_desc/program_desc 的定义,之间的关系是什么?这样设计的背景和好处是什么? model_parser目录下,包含 ...
- 关于Java Chassis 3的契约优先(API First)开发
本文分享自华为云社区<Java Chassis 3技术解密:契约优先(API First)开发>,作者: liubao68. 契约优先(API First)开发是指应用程序开发过程中,将A ...
- 当字符遇上 scanf() 要当心
当字符遇上 scanf() 要当心 看一下程序 char ch1,ch2; printf("请输入ch1,ch2的值:"); scanf("%c %c",&am ...
- 5GC 关键技术之 CUPS(控制与用户面分离)
目录 文章目录 目录 前文列表 CUPS(控制与用户面分离) 前文列表 <简述移动通信网络的演进之路> <5G 第五代移动通信网络> <5GC 关键技术之 SBA(基于服 ...
- 计算机网络基础 — Linux 内核网络协议栈
目录 文章目录 目录 前文列表 前言 数据报文的封装与分用 Linux 内核网络协议栈 协议栈的分层结构 协议栈的数据结构 网络协议栈初始化流程 Socket 创建流程 协议栈收包流程概述 协议栈发包 ...
- 预见预判_AIRIOT智慧交通管理解决方案
随着机动车保有量的逐步增加,城市交通压力日益增大.同时,新能源车辆的快速发展虽然带来了环保效益,但也因不限号政策而进一步加剧了道路拥堵问题.此外,各类赛事和重大活动的交通管制措施也时常导致交通状况复杂 ...
- .NET快速实现网页数据抓取
前言 今天我们来讲讲如何使用.NET开源(MIT License)的轻量.灵活.高性能.跨平台的分布式网络爬虫框架DotnetSpider来快速实现网页数据抓取功能. 注意:为了自身安全请在国家法律允 ...