轨迹处理
行程切分
原始的GPS数据包含了一辆车的多次出行,我们需要对车辆的出行进行划分。那么如何理解主行程和子行程?
- 主行程举例:一辆车从家出发到达公司,将车辆停在车库,熄火后,车辆不再产生GPS数据,下班后再次启动,GPS数据重新产生,早上到达公司的最后一个定位点和下班后启动车辆的第一个定位点,其时间差超过
group_gap_threshold,则在此处切分主行程 - 子行程举例:一辆车从家出发到达公司,在到达公司之前,在加油站加油,GPS点持续产生,但是定位点集中在加油站附近,产生了停留,那么从家-加油站就是一段子行程
- 每一个段主行程、子行程,均拥有一个全局唯一的
agent_id
gotrackit提供了GpsPreProcess类,其包含的trip_segmentations函数可以对GPS数据进行行程切分,输入的轨迹数据需要满足GPS定位数据的要求,示例代码如下
import pandas as pd
from gotrackit.gps.GpsTrip import GpsPreProcess
if __name__ == '__main__':
# 读取GPS数据
gps_gdf = pd.read_csv(r'data/output/gps/example/origin_gps.cssv')
# 新建一个GpsPreProcess示例
grp = GpsPreProcess(gps_df=gps_gdf, use_multi_core=False)
# 调用trip_segmentations方法进行行程切分
# 切分后的数据会更新agent_id字段用以区分不同的出行旅程,原GPS表的agent_id会存储在origin_agent_id字段中
gps_trip = grp.trip_segmentations(group_gap_threshold=1800, plain_crs='EPSG:32650', min_distance_threshold=10.0)
gps_trip.to_csv(r'./data/output/gps/example/gps_trip.csv', encoding='utf_8_sig', index=False)
提取带途径点的OD数据
如果你的GPS数据已经完成了行程切分,且已经按照agent_id、time两个字段升序排列,那么你可以直接使用GpsPreProcess类提供的sampling_waypoints_od函数,来提取带途径点的OD数据,示例代码如下:
import pandas as pd
from gotrackit.gps.GpsTrip import GpsPreProcess
if __name__ == '__main__':
# 读取GPS数据
gps_gdf = pd.read_csv(r'data/output/gps/example/gps_trip.cssv')
# 新建一个GpsPreProcess示例
grp = GpsPreProcess(gps_df=gps_gdf, use_multi_core=False)
# 返回的第一个数据是OD表(pd.DataFrame),第二个数据是OD线(gpd.GeoDataFrame)
gps_od, od_line = grp.sampling_waypoints_od(way_points_num=2)
gps_od.to_csv(r'./data/output/gps_od.csv', encoding='utf_8_sig', index=False)
od_line.to_file(r'./data/output/gps_od.shp')
Note
如果某agent的轨迹点数量=1,那么在sampling_waypoints_od函数返回的od结果里面不会有该agent的记录
轨迹数据清洗
确保输入的GPS数据满足GPS定位数据的要求,gotrackit的TrajectoryPoints类提供了对轨迹数据进行各种清洗的函数:
- 停留点删除 - del_dwell_points
- 轨迹点增密 - dense
- 轨迹点降频 - lower_frequency
- 滑动窗口平均 - rolling_average
- 卡尔曼滤波平滑 - kf_smooth
- 轨迹点简化 - simplify_trajectory
对于以上清洗函数,gotrackit允许用户使用链式操作的方式,对轨迹数据执行一个或者多个清洗操作,在清洗结束后,支持使用export_html进行可视化文件的输出、使用trajectory_data函数获取清洗后的定位数据表,示例代码如下:
import os
import pandas as pd
from gotrackit.gps.Trajectory import TrajectoryPoints
if __name__ == '__main__':
gps_df = pd.read_csv(r'gps.csv')
# 去除同一出行中的相同定位时间点数据
gps_df.drop_duplicates(subset=['agent_id', 'time'], keep='first', inplace=True)
gps_df.reset_index(inplace=True, drop=True)
# 构建TrajectoryPoints类, 并且指定一个plain_crs
tp = TrajectoryPoints(gps_points_df=gps_df, time_unit='ms', plain_crs='EPSG:32649')
# 间隔3个点采样一个点
# tp.lower_frequency(lower_n=3)
# 卡尔曼滤波平滑
tp.kf_smooth()
# 使用链式操作自定义预处理的先后顺序, 只要保证kf_smooth()操作后没有执行 - 滑动窗口平滑、增密,处理后的轨迹数据即可得到分项速度数据
# tp.simplify_trajectory().del_dwell_points()
# tp.kf_smooth().del_dwell_points()
# 获取清洗后的结果
# _type参数可以取值为 df 或者 gdf
process_df = tp.trajectory_data(_type='df')
out_fldr = r'./data/output/'
# 存储结果
process_df.to_csv(os.path.join(out_fldr, r'after_reprocess_gps.csv'), encoding='utf_8_sig', index=False)
# 输出为html进行动态可视化
tp.export_html(out_fldr=out_fldr, file_name='sample', radius=9.0)
Note
尽量避免在增密(dense)操作后执行滤波(kf_smooth)操作
Note
使用链式操作自定义预处理的先后顺序, 只要保证kf_smooth()操作后没有执行: 滑动窗口平滑,处理后的轨迹数据即可得到分项速度数据
输出的html文件,支持对清洗前后的轨迹点进行动态可视化: