用Python与MovingPandas分析出租车GPS轨迹数据

用Python与MovingPandas分析出租车GPS轨迹数据

Published on

目录:


7 月 2 日,《新京报》记者发布了一则关于国内油罐车混装煤制油与植物油的问题报道,两辆刚卸完煤制油的罐车,在未清洗罐体的情况下,又装上了食用油。

这件事又让经历过“三聚氰胺、地沟油、鼠头鸭脖”等食品安全事件的中国人感叹:活到现在真不容易。

7 月 9 日 国务院食安办回应了‘罐车运输食用油乱象问题’”,并表示已成立联合调查组彻查,同日,B 站博主@高剑犁 利用「卡车轨迹 APP(发货帮 APP)」和《新京报》的报道细节,成功追踪到了两辆油罐车的轨迹。由于大货车装载了 GPS,这些位置信息实际上是公开的。

我不再详细描述货车具体经过的地点。

物联网(Internet of Things, IoT)技术使得货车定位功能和轨迹分析成为可能,能够全程记录油罐车的行驶路径。一方面货物的买卖双方能知晓货物的动向,保障透明度和知情权。另一方面,监管方也能有效监管。

这种现象并非个案,而是在全国范围内普遍存在,涉及的企业类型多样,包括大型企业、小型作坊、外资企业、国有企业和私营企业等。

然而,这场食品安全事件的处理最终演变成了‘解决提出问题的人’。

7 月 11 号,高剑犁的视频的观看权限被官方设置为“仅自己可见”,变相下架,他人无法查看。

在高剑犁发布视频的当日,发货帮 App 开始紧急限制查询需求,对数据源、数据用途以及授权做要求。

7 月 10 日,发货帮 App 的货车轨迹被“404”,客服回应“货车定位功能升级维护中,后台暂时无法使用及查询,请您理解!如页面有恢复您再使用”。


作为一名用 Python 进行数据分析的人来说,数据源往往是最让人头痛的。

直接屏蔽问题来源的做法,这些年见过很过,大多数人也无能为例。

不过今天我还是想介绍一下如何将 GPS 数据转换为行驶轨迹,推断某个时间点或时段车辆所在的位置,并判断车辆是否经过指定区域。

希望人人都是 B 站博主@高剑犁

学会提取轨迹数据,人人都是“高剑犁”

前文说过,货车轨迹用到的是 LoT 技术,指的是通过互联网或其他通信网络将物体有关的数据采集、传输到网关,并进行数据分析和处理,最终展示出来。发货帮 App 的货车轨迹功能就是一个完整 LoT 应用。

既然油罐车轨迹获取不到,我就拿公开的数据集做演示。

(1)数据源

本次示例数据来源: 由Desheng Zhang, Rutgers University发布,名为 Urban Data Release V2,选取其中的深圳是出租车 GPS 数据。

(2)工具包

用到的工具是 pandas 和GitHub - movingpandas/movingpandas: Movement trajectory clas..., pandas 是一个非常常用的数据分析库,而 MovingPandas 则是基于 pandas 和 GeoPandas 构建的专门用于处理运动数据的库。

  • MovingPandas 是一个基于 pandas 和 GeoPandas 的 Python 库,专门用于运动数据的探索和分析。它提供了轨迹数据结构和相应的函数,用于处理和分析运动数据。
  • MovingPandas 利用 pandas 的时间序列处理功能和 GeoPandas 的空间数据处理功能,能够处理包含时间戳和几何信息的轨迹数据。
  • 主要功能包括轨迹创建、停留点检测、轨迹分割、轨迹清洗与平滑、轨迹聚合、运动特征计算(如速度、方向、加速度)以及静态和交互式可视化。

通过结合 pandas 和 MovingPandas,用户可以高效地处理和分析复杂的运动数据,进行深入的数据探索和可视化。

(3)Python 环境配置

movingpandas 环境比较复杂,这里只列出一种方法:使用Anaconda通过environment.yml安装和配置 Python 环境。

# 下载environment.yml
# wget https://github.com/movingpandas/movingpandas/blob/main/environment.yml

# 安装环境
conda env create --file environment.yml

# 激活环境
conda activate movingpandas-dev

# 安装movingpandas
conda install -c conda-forge movingpandas

(4)读取数据

之前在文章《从零开始:用 Python 和 Pandas 精准提取出租车 GPS 数据中的 OD 行程信息 - Renhai 实验室》中已经讲过如何读取和清洗数据了,数据清洗之后类似于:

VehicleNum Time Lng Lat OccupancyStatus Speed 0 22223 11:14:18 114.137871 22.575317 0 0 1 22223 01:18:28 114.137131 22.575983 0 0 2 22223 13:11:42 114.136269 22.545851 1 18 3 22223 02:05:47 114.135948 22.578917 0 29 4 22223 02:05:24 114.135834 22.577433 0 20

因为要我们追踪某一辆车,于是随机取得了一辆深圳出租车在 2013 年 10 月 22 日的 2582 条 GPS 数据:

(5)转为轨迹数据

一行代码就搞定了:

tc = mpd.TrajectoryCollection(df_sample,
                              'VehicleNum',
                              t='DateTime',
                              x='Lng',
                              y='Lat')
tc

输出:TrajectoryCollection with 1 trajectories

我们已经将车辆编号为 22223 的轨迹从“点”数据变为“线”(这里实际为一个 TrajectoryCollection 类),接下来可视化:

hvplot_defaults = {'tiles':'CartoLight', 'frame_height':400, 'frame_width':700, 'cmap':'Viridis', 'colorbar':True}
tc.hvplot(title=str(tc), line_width=5, **hvplot_defaults)

(6)追踪轨迹

有了轨迹可以追踪车辆,方法一就是手动寻找:

视频封面

如果你需要通过时间点找寻车辆在哪个位置:

获取某个时间点的近似位置

some_time = datetime(2013, 10, 22, 12, 6, 0)
estimated_position = my_traj.get_position_at(some_time, method="nearest")
estimated_position

输出:POINT (114.116417 22.546417)

如果你需要寻找车辆是否经过某一位置:

(7)保存轨迹为 html 文件

可以使用 folium 绘制并保存为 html,通过浏览器打开。

import pprint
import folium
from datetime import datetime
import geopandas as gpd

# 获取开始和结束点

start_point = my_traj.get_start_location()
end_point = my_traj.get_end_location()

# 获取某个时间点的近似位置

some_time = datetime(2013, 10, 22, 12, 6, 0)
estimated_position = my_traj.get_position_at(some_time, method="nearest")
print(estimated_position)

# 创建地图对象

m = folium.Map(location=[22.543096, 114.057865], zoom_start=12)

# 将轨迹数据转换为GeoDataFrame并处理时间戳

traj_gdf = my_traj.to_traj_gdf()
traj_gdf['start_t'] = traj_gdf['start_t'].astype(str)  # 将时间戳转换为字符串
traj_gdf['end_t'] = traj_gdf['end_t'].astype(str)

pprint.pp(traj_gdf.to_json())

# 将轨迹数据添加到地图上

folium.GeoJson(traj_gdf.to_json()).add_to(m)

# 添加开始点标记

folium.Marker(
    location=[start_point.y, start_point.x],
    popup=folium.Popup("Start Point", parse_html=True),
    icon=folium.Icon(color='red')
).add_to(m)

# 添加结束点标记

folium.Marker(
    location=[end_point.y, end_point.x],
    popup=folium.Popup("End Point", parse_html=True),
    icon=folium.Icon(color='green')
).add_to(m)

# 添加估计位置标记

folium.Marker(
    location=[estimated_position.y, estimated_position.x],
    popup=folium.Popup(f"Estimated Position\n {some_time.strftime('%H:%M')}", parse_html=True),
    icon=folium.Icon(color='blue')
).add_to(m)

# 保存地图到HTML文件

m.save("map.html")

# 显示地图

m

导出轨迹

有时候如果你需要在别的地理可视化软件比如ArcGISPro中处理,可以将轨迹导出,有三种类型的数据可以导出:

通常选择最后一种,兼容wkt格式。


本文的源代码、示例数据和 html 文件在:Urban-Spatial-Data-Analysis-Notebook/4-空间数据分析/4.1-交通大数据分析/【专...可以获取。

本文的后续将在播客文章中持续更新,微信用户点击阅读原文即可跳转。

欢迎留言!