项目背景
项目背景:2017年biendata举办了摩拜杯算法挑战赛,利用机器学习去预测每个用户可能的骑行目的地,以更好地调配和管理大量摩拜单车。
数据下载地址:项目官网 https://biendata.com/competition/mobike/
本文将使用项目中给出的训练集数据train.csv进行数据的探索性分析,利用python工具来探索用户骑行规律。暂不涉及建模。
分析的目的:获取用户出行的规律,主要分析维度是时间,日期,骑行距离等
文中Geohash脚本 下载链接: https://pan.baidu.com/s/17J-22GdN4F2jEOxWPvQ-Eg 提取码: vhbz
工具:Jupyter notebook Python 3
数据概况
import pandas as pd
import datetime
import geohash
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
from math import radians, cos, sin, asin, sqrt
# 导入train.csv数据文件,将starttime转换为日期列,避免后续字符串和datetime的转换
df = pd.read_csv("train.csv",sep=",",parse_dates=["starttime"])
# 查看数据集df
df.head()
orderid | userid | bikeid | biketype | starttime | geohashed_start_loc | geohashed_end_loc | |
---|---|---|---|---|---|---|---|
0 | 1893973 | 451147 | 210617 | 2 | 2017-05-14 22:16:50 | wx4snhx | wx4snhj |
1 | 4657992 | 1061133 | 465394 | 1 | 2017-05-14 22:16:52 | wx4dr59 | wx4dquz |
2 | 2965085 | 549189 | 310572 | 1 | 2017-05-14 22:16:51 | wx4fgur | wx4fu5n |
3 | 4548579 | 489720 | 456688 | 1 | 2017-05-14 22:16:51 | wx4d5r5 | wx4d5r4 |
4 | 3936364 | 467449 | 403224 | 1 | 2017-05-14 22:16:50 | wx4g27p | wx4g266 |
数据字段说明
- orderid 订单号
- userid 用户ID
- bikeid 车辆ID
- biketype 车辆类型
- starttime 骑行起始日期时间
- geohashed_start_loc 骑行起始区块位置
- geohashed_end_loc 骑行目的地区块位置
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3214096 entries, 0 to 3214095
Data columns (total 7 columns):
orderid int64
userid int64
bikeid int64
biketype int64
starttime datetime64[ns]
geohashed_start_loc object
geohashed_end_loc object
dtypes: datetime64[ns](1), int64(4), object(2)
memory usage: 171.7+ MB
# 数据集大小 3214096 * 7
df.shape
(3214096, 7)
# 数据涵盖了48万+的单车
df.bikeid.unique().size
485465
# 数据涵盖了近35W的骑行用户
df.userid.unique().size
349693
# 涵盖2种车型
df.biketype.unique().size
2
# 查看geohashed_start_loc 字段长度
df["geohashed_start_loc"].apply(lambda s: len(s)).value_counts()
7 3214096
Name: geohashed_start_loc, dtype: int64
# 查看geohashed_end_loc 字段长度
df["geohashed_end_loc"].apply(lambda s: len(s)).value_counts()
7 3214096
Name: geohashed_end_loc, dtype: int64
查看整个数据情况,可了解到数据集大小为3214096 * 7,涵盖48W+单车、近35W骑行用户、2种单车车型。
骑行出发点、目的地经过Geohash编码加密,且全部为7位编码。
选取数据分析样本
考虑到数据集大小以及电脑的性能,同比例随机挑选50%的数据进行用户行为分析
df = df.sample(frac=0.5)
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1607048 entries, 120096 to 241942
Data columns (total 7 columns):
orderid 1607048 non-null int64
userid 1607048 non-null int64
bikeid 1607048 non-null int64
biketype 1607048 non-null int64
starttime 1607048 non-null datetime64[ns]
geohashed_start_loc 1607048 non-null object
geohashed_end_loc 1607048 non-null object
dtypes: datetime64[ns](1), int64(4), object(2)
memory usage: 98.1+ MB
数据处理
时间处理
当前数据中只有骑行出发时间starttime,格式同 2017-05-14 22:16:50
时间进行处理,提取出周几weekday,小时hour,日期day数据,以便后续分析不同时间出行数据的分布
# 使用weekday函数提取周几信息,周一为0,周日为6
df["weekday"] = df["starttime"].apply(lambda s: s.weekday())
# 提取小时数,hour属性
df["hour"] = df["starttime"].apply(lambda s: s.hour)
# 提取时间中的日期
df["day"] = df["starttime"].apply(lambda s:str(s)[:10])
# 打印日志
print("时间信息处理完毕!")
时间信息处理完毕!
空间信息处理
数据集中,地理位置通过Geohash加密,算法比赛的官网上告知可以通过开源的方法获得经纬度数据。
本文是直接导入Geohash脚本进行处理经纬度的处理
关于Geohash编码的原理,强烈推荐阅读此文:https://www.cnblogs.com/LBSer/p/3310455.html
Geohash感性认识:
- GeoHash将二维的经纬度转换成字符串,比如下图展示了北京9个区域的GeoHash字符串,分别是WX4ER,WX4G2、WX4G3等等,每一个字符串代表了某一矩形区域。这个矩形区域内所有的点(经纬度坐标)都共享相同的GeoHash字符串,这样既可以保护隐私(只表示大概区域位置而不是具体的点),又比较容易做缓存,比如左上角这个区域内的用户不断发送位置信息请求附近餐馆数据,由于这些用户的GeoHash字符串都是WX4ER,所以可以把WX4ER当作key,把该区域的餐馆信息当作value来进行缓存,而如果不使用GeoHash的话,由于区域内的用户传来的经纬度是各不相同的,很难做缓存。
- Geohash能够提供任意经度的分段级别,一般分为1-12级。Geohash编码字符串越长,表示的区域范围越精确。
前面已经验证过,数据集中Geohash区块位置信息全部为7位Geohash编码。按照对应的精度级别,每个区块在153米*153米范围内。G7位编码对应的区块范围很小,单车随意骑行,一般都能离开当前区域。
构建区块对应的6位Geohash编码,每个区块面积在1.22km*0.61km范围内,比较符合短途摩拜骑行的特点。
当然,我们还可以从7位Geohash编码中不断提取更短的编码进行研究分析,但建议到4位即可。
如果编码更短,比如3位,区块面积太大,就会变得没意义。
def geo_data_process(df):
# 通过导入Geohash脚本中的decode函数,获取经纬度
df["start_lat_lng"] = df["geohashed_start_loc"].apply(lambda s: geohash.decode(s))
df["end_lat_lng"] = df["geohashed_end_loc"].apply(lambda s: geohash.decode(s))
#获取出发地点所在区块周围的8个相邻区块编码
df["start_neighbors"] = df["geohashed_start_loc"].apply