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. 理解数据

我们首先加载数据并做初始的分析。这里的目标主要是:

  1. 对数据有基本的了解
  2. 各个特征是如何分布
  3. 是否有缺失值
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 里对数据的说明,我们可以了解以下几点:

  1. instant 为 id 索引,对预测无帮助
  2. 离散型特征有:season,yr,mnth,hr,holiday,weekday,workingday,weathersit
  3. 数值型特征有:temp,atemp,hum,windspeed,casual,registered,cnt
  4. 数值型特征中temp、atemp,hum,windspeed 均已做标准化处理,casual,registered,cnt未做标准化处理
  5. cnt 是 casual 与 registered 相加之和,可以由这两个属性计算出
  6. dteday为时间特征

按照特征描述分类,可以分为3大类:

  1. 时间相关,包含条目注册时的时间:dteday,season,yr,mnth,hr,holiday,weekday,workingday
  2. 天气相关,包含天气条件:weathersit,temp,atemp,hun以及windspeed
  3. 条目本身相关,包含指定小时内,总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')

从分布图我们可以了解到:

  1. 两者的分布均为正倾斜
  2. 骑行的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')

从这个图可以看到:

  1. registered 用户的骑行次数,基本每天都是要明显超出casual 用户非常多
  2. 冬季骑行数会少下降

但是这个图中,两个时间之间的差比非常大,所以有很高的的抖动(毛刺)。有一个平滑毛刺的方法是:使用滚动平均值与滚动标准差来替换所需要可视化的值,以及它们的期望标准差情况。

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')

从这个图我们可以了解到:

  1. 在工作日,用户骑行时间主要分布在早上8点到下午6点之间,符合我们的预期;
  2. Registered 用户为共享单车的主要使用者
  3. Casual 用户在工作日使用共享单车有限
  4. 在休息日,可以明显看到对于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(一)- 探索数据的更多相关文章

  1. 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 ...

  2. PowerBI开发:用自然语言来探索数据--Q&A

    Power BI报表的用户,肯定会被Q&A的功能惊艳到,在查看报表时,仅仅通过输入文本就可以探索数据,并且结果是可视化的,更令人惊艳的时,结果几乎是实时显示出来的.这使得Q&A Vis ...

  3. 一起学微软Power BI系列-官方文档-入门指南(5)探索数据奥秘

    我们几篇系列文章中,我们介绍了官方入门文档与获取数据等基本知识.今天继续给大家另外一个重点,探索数据奥秘.有了数据源,有了模型,下一步就是如何解析数据了.解析数据的过程需要很多综合技能,不仅仅是需要掌 ...

  4. Power BI 与 Azure Analysis Services 的数据关联:1、建立 Azure Analysis Services服务

    Power BI 与 Azure  Analysis Services 的数据关联:1.建立  Azure  Analysis Services服务

  5. Power BI 与 Azure Analysis Services 的数据关联:2、Azure Analysis Services与 本地版本的 SQL Analysis Services 连接

    Power BI 与 Azure  Analysis Services 的数据关联:2.Azure  Analysis Services与 本地版本的 SQL   Analysis Services ...

  6. Power BI 与 Azure Analysis Services 的数据关联:3、还原备份文件到Azure Analysis Services

    Power BI 与 Azure  Analysis Services 的数据关联:3.还原备份文件到Azure  Analysis Services 配置存储设置 备份前,需要为服务器配置存储设置. ...

  7. Power BI 与 Azure Analysis Services 的数据关联:4、Power BI 连接到Azure Analysis Services 并展示

    Power BI 与 Azure  Analysis Services 的数据关联:4.Power BI 连接到Azure  Analysis Services 过使用服务器名称别名,用户可以使用较短 ...

  8. Kibana探索数据(Discover)

    总结说明: 1.先在Management/Kibana/Index Patterns 界面下添加索引模式(前提是有索引数据) 2.在Discover界面选中响应的索引模式 3.开启Kibana 查询语 ...

  9. Kibana探索数据(Discover)详解

    设置时间过滤器 时间过滤器按照指定的时间段展示搜索结果.设置了 index contains time-based events 和 time-field 的索引模式可以使用时间过滤器. 时间过滤器默 ...

  10. ElasticSearch实践系列(三):探索数据

    前言 经过前两篇文章得实践,我们已经了解了ElasticSearch的基础知识,本篇文章让我来操作一些更真实的数据集.我们可以利用www.json-generator.com/生成如下的文档结构: { ...

随机推荐

  1. LVGL 定时器

    LVGL 8.0 以后好像取消了自定义任务模块,想要使用多线程只能使用系统的线程. 一.定时器结构体 typedef struct _lv_timer_t { uint32_t period; // ...

  2. 使用WebSocket实现实时多人答题对战游戏

    前言 前两章教程,我们使用WebSocket的基础特性打造了一个小小聊天室,并在第二章对其进行了集群化改造. 系列教程回顾: [WebSocket]第一章:手把手搭建WebSocket多人在线聊天室( ...

  3. rpc 和 http的区别

  4. 飞桨PaddleLite架构研读

    一.架构全景图 二.源码详细解读 1. Lite体系下似乎有多种 op_desc/program_desc 的定义,之间的关系是什么?这样设计的背景和好处是什么? model_parser目录下,包含 ...

  5. 关于Java Chassis 3的契约优先(API First)开发

    本文分享自华为云社区<Java Chassis 3技术解密:契约优先(API First)开发>,作者: liubao68. 契约优先(API First)开发是指应用程序开发过程中,将A ...

  6. 当字符遇上 scanf() 要当心

    当字符遇上 scanf() 要当心 看一下程序 char ch1,ch2; printf("请输入ch1,ch2的值:"); scanf("%c %c",&am ...

  7. 5GC 关键技术之 CUPS(控制与用户面分离)

    目录 文章目录 目录 前文列表 CUPS(控制与用户面分离) 前文列表 <简述移动通信网络的演进之路> <5G 第五代移动通信网络> <5GC 关键技术之 SBA(基于服 ...

  8. 计算机网络基础 — Linux 内核网络协议栈

    目录 文章目录 目录 前文列表 前言 数据报文的封装与分用 Linux 内核网络协议栈 协议栈的分层结构 协议栈的数据结构 网络协议栈初始化流程 Socket 创建流程 协议栈收包流程概述 协议栈发包 ...

  9. 预见预判_AIRIOT智慧交通管理解决方案

    随着机动车保有量的逐步增加,城市交通压力日益增大.同时,新能源车辆的快速发展虽然带来了环保效益,但也因不限号政策而进一步加剧了道路拥堵问题.此外,各类赛事和重大活动的交通管制措施也时常导致交通状况复杂 ...

  10. .NET快速实现网页数据抓取

    前言 今天我们来讲讲如何使用.NET开源(MIT License)的轻量.灵活.高性能.跨平台的分布式网络爬虫框架DotnetSpider来快速实现网页数据抓取功能. 注意:为了自身安全请在国家法律允 ...