TransBigData为交通时空大数据而生

主要功能
TransBigData是一个为交通时空大数据处理和分析而开发的Python包。TransBigData为处理常见的交通时空大数据(如出租车GPS数据、共享单车数据和公交车GPS数据)提供了快速而简洁的方法。它包括栅格化、数据质量分析、数据预处理、数据集计数、轨迹分析、GIS处理、地图底图加载、坐标和距离计算以及数据可视化等通用方法。
技术特点
为交通时空大数据分析的不同阶段提供不同的处理方法。
TransBigData的代码简洁、高效、灵活、易用,可以用简洁的代码实现复杂的数据任务。
简介
快速启动
pip install -U transbigdata
以下示例展示了如何使用 TransBigData 从出租车 GPS 数据中快速提取行程 OD
import transbigdata as tbd
import pandas as pd
data = pd.read_csv('TaxiData-Sample.csv',header = None)
data.columns = ['VehicleNum','time','slon','slat','OpenStatus','Speed']
data

使用`tbd.taxigps_to_od`方法并传入相应的列名以提取行程 OD:
#Extract OD from GPS data
oddata = tbd.taxigps_to_od(data,col = ['VehicleNum','time','slon','slat','OpenStatus'])
oddata

将 OD 聚合到网格中:
#define bounds
bounds = [113.6,22.4,114.8,22.9]
#obtain the gridding parameters
params = tbd.grid_params(bounds = bounds,accuracy = 1500)
#gridding OD data and aggregate
od_gdf = tbd.odagg_grid(oddata,params)
od_gdf.plot(column = 'count')

安装
安装
安装
TransBigData 支持 Python >= 3.6。
TransBigData依赖于geopandas,在安装TransBigData之前,您需要根据 `此链接<https://geopandas.org/en/stable/getting_started.html#installation>`_ 安装geopandas,如果您已经安装了geopandas,请直接从命令提示符运行以下代码进行安装:
pip install -U transbigdata
你也可以通过conda-forge安装TransBigData,这将自动解决依赖问题,它可以安装:
conda install -c conda-forge transbigdata
要导入 TransBigData,请在 Python 中运行以下代码:
import transbigdata as tbd
依赖
TransBigData依赖以下包
示例
示例
核心功能示例
1 出租车GPS数据处理与可视化
出租车GPS数据处理
[1]:
import transbigdata as tbd
import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt
# Read data
data = pd.read_csv('data/TaxiData-Sample.csv', header=None)
data.columns = ['VehicleNum', 'Time', 'Lng', 'Lat', 'OpenStatus', 'Speed']
data.head()
[1]:
VehicleNum | Time | Lng | Lat | OpenStatus | Speed | |
---|---|---|---|---|---|---|
0 | 34745 | 20:27:43 | 113.806847 | 22.623249 | 1 | 27 |
1 | 34745 | 20:24:07 | 113.809898 | 22.627399 | 0 | 0 |
2 | 34745 | 20:24:27 | 113.809898 | 22.627399 | 0 | 0 |
3 | 34745 | 20:22:07 | 113.811348 | 22.628067 | 0 | 0 |
4 | 34745 | 20:10:06 | 113.819885 | 22.647800 | 0 | 54 |
[2]:
# Read the GeoDataFrame of the study area
sz = gpd.read_file(r'data/sz.json')
sz.crs = None
sz.head()
[2]:
centroid_x | centroid_y | qh | geometry | |
---|---|---|---|---|
0 | 114.143157 | 22.577605 | 罗湖 | POLYGON ((114.10006 22.53431, 114.10083 22.534... |
1 | 114.041535 | 22.546180 | 福田 | POLYGON ((113.98578 22.51348, 114.00553 22.513... |
2 | 114.270206 | 22.596432 | 盐田 | POLYGON ((114.19799 22.55673, 114.19817 22.556... |
3 | 113.851387 | 22.679120 | 宝安 | MULTIPOLYGON (((113.81831 22.54676, 113.81948 ... |
4 | 113.926290 | 22.766157 | 光明 | POLYGON ((113.99768 22.76643, 113.99704 22.766... |
[3]:
fig = plt.figure(1, (8, 3), dpi=150)
ax1 = plt.subplot(111)
sz.plot(ax=ax1)
plt.xticks([], fontsize=10)
plt.yticks([], fontsize=10);

数据预处理
TransBigData集成了几种常见的数据预处理方法。使用“tbd.clean_outofshape”方法,给定研究区域的数据和地理数据帧,可以删除研究区域之外的数据。“tbd.clean_taxi_status”方法可以过滤掉乘客状态瞬时变化的数据(OpenStatus)。使用预处理方法时,需要将相应的列名作为参数传入:
[4]:
# Data Preprocessing
# Delete the data outside of the study area
data = tbd.clean_outofshape(data, sz, col=['Lng', 'Lat'], accuracy=500)
# Delete the data with instantaneous changes in passenger status
data = tbd.clean_taxi_status(data, col=['VehicleNum', 'Time', 'OpenStatus'])
数据网格化
表示数据分布的最基本方法是以地理网格的形式;数据网格化后,每个GPS数据点映射到相应的网格。对于数据网格化,首先需要确定格网参数(可以解释为定义格网坐标系):
[5]:
# Data gridding
# Define the bounds and generate gridding parameters
bounds = [113.6, 22.4, 114.8, 22.9]
params = tbd.area_to_params(bounds, accuracy=500)
print(params)
{'slon': 113.6, 'slat': 22.4, 'deltalon': 0.004872390756896538, 'deltalat': 0.004496605206422906, 'theta': 0, 'method': 'rect', 'gridsize': 500}
获得网格参数后,下一步是将GPS映射到其对应的网格。使用“待定”。GPS_to_grids“,它将生成”LONCOL“列和”LATCOL“列。这两列一起可以指定一个网格:
[6]:
# Mapping GPS data to grids
data['LONCOL'], data['LATCOL'] = tbd.GPS_to_grid(data['Lng'], data['Lat'], params)
data.head()
[6]:
VehicleNum | Time | Lng | Lat | OpenStatus | Speed | LONCOL | LATCOL | |
---|---|---|---|---|---|---|---|---|
0 | 34745 | 20:27:43 | 113.806847 | 22.623249 | 1 | 27 | 42 | 50 |
1 | 27368 | 09:08:53 | 113.805893 | 22.624996 | 0 | 49 | 42 | 50 |
2 | 22998 | 10:51:10 | 113.806931 | 22.624166 | 1 | 54 | 42 | 50 |
3 | 22998 | 10:11:50 | 113.805946 | 22.625433 | 0 | 43 | 42 | 50 |
4 | 22998 | 10:12:05 | 113.806381 | 22.623833 | 0 | 60 | 42 | 50 |
统计每个格子的数据量:
[7]:
# Aggregate data into grids
datatest = data.groupby(['LONCOL', 'LATCOL'])['VehicleNum'].count().reset_index()
datatest.head()
[7]:
LONCOL | LATCOL | VehicleNum | |
---|---|---|---|
0 | 36 | 63 | 2 |
1 | 36 | 66 | 1 |
2 | 36 | 67 | 8 |
3 | 37 | 62 | 9 |
4 | 37 | 63 | 8 |
生成网格的几何图形并将其转换为 GeoDataFrame:
[8]:
# Generate the geometry for grids
datatest['geometry'] = tbd.grid_to_polygon([datatest['LONCOL'], datatest['LATCOL']], params)
# Change it into GeoDataFrame
# import geopandas as gpd
datatest = gpd.GeoDataFrame(datatest)
datatest.head()
[8]:
LONCOL | LATCOL | VehicleNum | geometry | |
---|---|---|---|---|
0 | 36 | 63 | 2 | POLYGON ((113.77297 22.68104, 113.77784 22.681... |
1 | 36 | 66 | 1 | POLYGON ((113.77297 22.69453, 113.77784 22.694... |
2 | 36 | 67 | 8 | POLYGON ((113.77297 22.69902, 113.77784 22.699... |
3 | 37 | 62 | 9 | POLYGON ((113.77784 22.67654, 113.78271 22.676... |
4 | 37 | 63 | 8 | POLYGON ((113.77784 22.68104, 113.78271 22.681... |
绘制生成的网格:
[9]:
# Plot the grids
fig = plt.figure(1, (16, 6), dpi=300)
ax1 = plt.subplot(111)
# tbd.plot_map(plt, bounds, zoom=10, style=4)
datatest.plot(ax=ax1, column='VehicleNum', legend=True)
plt.xticks([], fontsize=10)
plt.yticks([], fontsize=10)
plt.title('Counting of Taxi GPS Trajectory Points', fontsize=12);

[10]:
# Plot the grids
fig = plt.figure(1, (16, 6), dpi=300) # 确定图形高为6,宽为8;图形清晰度
ax1 = plt.subplot(111)
datatest.plot(ax=ax1, column='VehicleNum', legend=True, scheme='quantiles')
# plt.legend(fontsize=10)
plt.xticks([], fontsize=10)
plt.yticks([], fontsize=10)
plt.title('Counting of Taxi GPS Trajectory Points', fontsize=12);

[11]:
# Plot the grids
fig = plt.figure(1, (16, 6), dpi=150) # 确定图形高为6,宽为8;图形清晰度
ax1 = plt.subplot(111)
datatest.plot(ax=ax1, column='VehicleNum', legend=True, cmap='OrRd', scheme='quantiles')
# plt.legend(fontsize=10)
plt.xticks([], fontsize=10)
plt.yticks([], fontsize=10)
plt.title('Counting of Taxi GPS Trajectory Points', fontsize=12);

Origin-destination(OD) 提取和聚合出租车行程
使用“tbd.taxigps_to_od”方法并传入相应的列名以提取出租车行程 OD:
[12]:
# Extract taxi OD from GPS data
oddata = tbd.taxigps_to_od(data,col = ['VehicleNum', 'Time', 'Lng', 'Lat', 'OpenStatus'])
oddata
[12]:
VehicleNum | stime | slon | slat | etime | elon | elat | ID | |
---|---|---|---|---|---|---|---|---|
427075 | 22396 | 00:19:41 | 114.013016 | 22.664818 | 00:23:01 | 114.021400 | 22.663918 | 0 |
131301 | 22396 | 00:41:51 | 114.021767 | 22.640200 | 00:43:44 | 114.026070 | 22.640266 | 1 |
417417 | 22396 | 00:45:44 | 114.028099 | 22.645082 | 00:47:44 | 114.030380 | 22.650017 | 2 |
376160 | 22396 | 01:08:26 | 114.034897 | 22.616301 | 01:16:34 | 114.035614 | 22.646717 | 3 |
21768 | 22396 | 01:26:06 | 114.046021 | 22.641251 | 01:34:48 | 114.066048 | 22.636183 | 4 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
57666 | 36805 | 22:37:42 | 114.113403 | 22.534767 | 22:48:01 | 114.114365 | 22.550632 | 5332 |
175519 | 36805 | 22:49:12 | 114.114365 | 22.550632 | 22:50:40 | 114.115501 | 22.557983 | 5333 |
212092 | 36805 | 22:52:07 | 114.115402 | 22.558083 | 23:03:27 | 114.118484 | 22.547867 | 5334 |
119041 | 36805 | 23:03:45 | 114.118484 | 22.547867 | 23:20:09 | 114.133286 | 22.617750 | 5335 |
224103 | 36805 | 23:36:19 | 114.112968 | 22.549601 | 23:43:12 | 114.089485 | 22.538918 | 5336 |
5337 rows × 8 columns
聚合提取的OD,生成LineString GeoDataFrame
[13]:
# Gridding and aggragate data
od_gdf = tbd.odagg_grid(oddata, params)
od_gdf.head()
/opt/anaconda3/lib/python3.8/site-packages/pandas/core/dtypes/cast.py:91: ShapelyDeprecationWarning: The array interface is deprecated and will no longer work in Shapely 2.0. Convert the '.coords' to a numpy array instead.
values = construct_1d_object_array_from_listlike(values)
[13]:
SLONCOL | SLATCOL | ELONCOL | ELATCOL | count | SHBLON | SHBLAT | EHBLON | EHBLAT | geometry | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 40 | 62 | 45 | 68 | 1 | 113.794896 | 22.678790 | 113.819258 | 22.705769 | LINESTRING (113.79490 22.67879, 113.81926 22.7... |
3331 | 101 | 36 | 86 | 29 | 1 | 114.092111 | 22.561878 | 114.019026 | 22.530402 | LINESTRING (114.09211 22.56188, 114.01903 22.5... |
3330 | 101 | 35 | 105 | 30 | 1 | 114.092111 | 22.557381 | 114.111601 | 22.534898 | LINESTRING (114.09211 22.55738, 114.11160 22.5... |
3329 | 101 | 34 | 109 | 34 | 1 | 114.092111 | 22.552885 | 114.131091 | 22.552885 | LINESTRING (114.09211 22.55288, 114.13109 22.5... |
3328 | 101 | 34 | 103 | 34 | 1 | 114.092111 | 22.552885 | 114.101856 | 22.552885 | LINESTRING (114.09211 22.55288, 114.10186 22.5... |
[14]:
# Plot the grids
fig = plt.figure(1, (16, 6), dpi=150) # 确定图形高为6,宽为8;图形清晰度
ax1 = plt.subplot(111)
# data_grid_count.plot(ax=ax1, column='VehicleNum', legend=True, cmap='OrRd', scheme='quantiles')
od_gdf.plot(ax=ax1, column='count', legend=True, scheme='quantiles')
plt.xticks([], fontsize=10)
plt.yticks([], fontsize=10)
plt.title('OD Trips', fontsize=12);
/opt/anaconda3/lib/python3.8/site-packages/mapclassify/classifiers.py:238: UserWarning: Warning: Not enough unique values in array to form k classes
Warn(
/opt/anaconda3/lib/python3.8/site-packages/mapclassify/classifiers.py:241: UserWarning: Warning: setting k to 2
Warn("Warning: setting k to %d" % k_q, UserWarning)

将OD聚合成多边形
``TransBigData``也提供了OD聚合成多边形的方法
[15]:
# Aggragate OD data to polygons
# without passing gridding parameters, the algorithm will map the data
# to polygons directly using their coordinates
od_gdf = tbd.odagg_shape(oddata, sz, round_accuracy=6)
fig = plt.figure(1, (16, 6), dpi=150) # 确定图形高为6,宽为8;图形清晰度
ax1 = plt.subplot(111)
od_gdf.plot(ax=ax1, column='count')
plt.xticks([], fontsize=10)
plt.yticks([], fontsize=10)
plt.title('OD Trips', fontsize=12);
/opt/anaconda3/lib/python3.8/site-packages/pandas/core/dtypes/cast.py:91: ShapelyDeprecationWarning: The array interface is deprecated and will no longer work in Shapely 2.0. Convert the '.coords' to a numpy array instead.
values = construct_1d_object_array_from_listlike(values)

基于Matplotlib的地图绘制
“TransBigData”还在 matplotlib 中提供底图加载。在使用此方法之前,您需要设置底图的mapboxtoken和存储位置,请参阅:“此链接<https://transbigdata.readthedocs.io/en/latest/plot_map.html>”__。“tbd.plot_map”添加底图,tbd.plotscale 添加比例和指南针:
[16]:
# Create figure
fig = plt.figure(1, (10, 10), dpi=300)
ax = plt.subplot(111)
plt.sca(ax)
# Load basemap
tbd.plot_map(plt, bounds, zoom=12, style=4)
# Define an ax for colorbar
cax = plt.axes([0.05, 0.33, 0.02, 0.3])
plt.title('OD\nMatrix')
plt.sca(ax)
# Plot the OD
od_gdf.plot(ax=ax, vmax=100, column='count', cax=cax, legend=True)
# Plot the polygons
sz.plot(ax=ax, edgecolor=(0, 0, 0, 1), facecolor=(0, 0, 0, 0.2), linewidths=0.5)
# Add compass and scale
tbd.plotscale(ax, bounds=bounds, textsize=10, compasssize=1, accuracy=2000, rect=[0.06, 0.03], zorder=10)
plt.axis('off')
plt.xlim(bounds[0], bounds[2])
plt.ylim(bounds[1], bounds[3])
plt.show()

提取出租车轨迹
采用“tbd.taxigps_traj_point”法,输入GPS数据和OD数据,可提取轨迹点
[17]:
data_deliver, data_idle = tbd.taxigps_traj_point(data,oddata,col=['VehicleNum',
'Time',
'Lng',
'Lat',
'OpenStatus'])
[18]:
data_deliver.head()
[18]:
VehicleNum | Time | Lng | Lat | OpenStatus | Speed | LONCOL | LATCOL | ID | flag | |
---|---|---|---|---|---|---|---|---|---|---|
427075 | 22396 | 00:19:41 | 114.013016 | 22.664818 | 1 | 63.0 | 85.0 | 59.0 | 0.0 | 1.0 |
427085 | 22396 | 00:19:49 | 114.014030 | 22.665483 | 1 | 55.0 | 85.0 | 59.0 | 0.0 | 1.0 |
416622 | 22396 | 00:21:01 | 114.018898 | 22.662500 | 1 | 1.0 | 86.0 | 58.0 | 0.0 | 1.0 |
427480 | 22396 | 00:21:41 | 114.019348 | 22.662300 | 1 | 7.0 | 86.0 | 58.0 | 0.0 | 1.0 |
416623 | 22396 | 00:22:21 | 114.020615 | 22.663366 | 1 | 0.0 | 86.0 | 59.0 | 0.0 | 1.0 |
[19]:
data_idle.head()
[19]:
VehicleNum | Time | Lng | Lat | OpenStatus | Speed | LONCOL | LATCOL | ID | flag | |
---|---|---|---|---|---|---|---|---|---|---|
416628 | 22396 | 00:23:01 | 114.021400 | 22.663918 | 0 | 25.0 | 86.0 | 59.0 | 0.0 | 0.0 |
401744 | 22396 | 00:25:01 | 114.027115 | 22.662100 | 0 | 25.0 | 88.0 | 58.0 | 0.0 | 0.0 |
394630 | 22396 | 00:25:41 | 114.024551 | 22.659834 | 0 | 21.0 | 87.0 | 58.0 | 0.0 | 0.0 |
394671 | 22396 | 00:26:21 | 114.022797 | 22.658367 | 0 | 0.0 | 87.0 | 57.0 | 0.0 | 0.0 |
394672 | 22396 | 00:26:29 | 114.022797 | 22.658367 | 0 | 0.0 | 87.0 | 57.0 | 0.0 | 0.0 |
从轨迹点生成投放和空闲轨迹
[20]:
traj_deliver = tbd.points_to_traj(data_deliver)
traj_deliver.plot();

[21]:
traj_idle = tbd.points_to_traj(data_idle[data_idle['OpenStatus'] == 0])
traj_idle.plot()
[21]:
<AxesSubplot:>

轨迹可视化
“TransBigData”的内置可视化功能利用可视化包“keplergl”,使用简单的代码以交互方式可视化Jupyter笔记本上的数据。要使用此方法,请为 python 安装 ‘’keplergl’ 包:
pip 安装 keplergl
详细信息请参阅“此链接<https://transbigdata.readthedocs.io/en/latest/visualization.html>”__
轨迹数据可视化:
[22]:
tbd.visualization_trip(data_deliver)
Processing trajectory data...
Generate visualization...
User Guide: https://docs.kepler.gl/docs/keplergl-jupyter
2 基于栅格的处理框架
本笔记本将介绍Transbigdata软件包中嵌入的核心功能
[1]:
import transbigdata as tbd
import geopandas as gpd
import pandas as pd
import matplotlib.pyplot as plt
import pprint
import random
[2]:
# this is a shp file, the sample area is part of Jiading district, Shanghai, China
jiading_polygon = gpd.read_file(r'data/jiading_polygon/jiading_polygon.shp')
jiading_polygon.head()
[2]:
id | geometry | |
---|---|---|
0 | 1 | POLYGON ((121.22538 31.35142, 121.22566 31.350... |
[3]:
jiading_rec_bound = [121.1318, 31.2484, 121.2553, 31.3535]
fig = plt.figure(1, (6, 6), dpi=100)
ax = plt.subplot(111)
plt.sca(ax)
tbd.plot_map(plt, bounds=jiading_rec_bound, zoom=13, style=2)
jiading_polygon.plot(ax=ax, alpha=0.5)
plt.axis('off');

transbigdata.area_to_grid
(location, accuracy=500, method=’rect’, params=’auto’)
[4]:
# generate the default grid
grid_rec, params_rec = tbd.area_to_grid(jiading_polygon)
pprint.pprint(params_rec)
grid_rec.head()
{'deltalat': 0.004496605206422906,
'deltalon': 0.005262604989003139,
'gridsize': 500,
'method': 'rect',
'slat': 31.25168182840957,
'slon': 121.13797109957756,
'theta': 0}
[4]:
LONCOL | LATCOL | geometry | |
---|---|---|---|
171 | 9 | 0 | POLYGON ((121.18270 31.24943, 121.18797 31.249... |
174 | 10 | 0 | POLYGON ((121.18797 31.24943, 121.19323 31.249... |
177 | 11 | 0 | POLYGON ((121.19323 31.24943, 121.19849 31.249... |
180 | 12 | 0 | POLYGON ((121.19849 31.24943, 121.20375 31.249... |
183 | 13 | 0 | POLYGON ((121.20375 31.24943, 121.20902 31.249... |
[5]:
# generate triangle grid
grid_tri, params_tri = tbd.area_to_grid(jiading_polygon, method='tri') # to do: bug need to be fixed here
pprint.pprint(params_tri)
grid_tri.head()
{'deltalat': 0.004496605206422906,
'deltalon': 0.005262604989003139,
'gridsize': 500,
'method': 'tri',
'slat': 31.25168182840957,
'slon': 121.13797109957756,
'theta': 0}
[5]:
loncol_1 | loncol_2 | loncol_3 | geometry | |
---|---|---|---|---|
22 | 6 | 2 | -5 | POLYGON ((121.17481 31.25947, 121.16955 31.256... |
24 | 7 | 2 | -5 | POLYGON ((121.17481 31.25428, 121.18007 31.256... |
27 | 8 | 3 | -5 | POLYGON ((121.18007 31.25168, 121.18533 31.254... |
28 | 8 | 3 | -6 | POLYGON ((121.18533 31.25947, 121.18007 31.256... |
30 | 9 | 3 | -6 | POLYGON ((121.18533 31.25428, 121.19060 31.256... |
[6]:
# Visualization
fig = plt.figure(1, (12, 8), dpi=200)
ax1 = plt.subplot(121)
plt.sca(ax1)
tbd.plot_map(plt, bounds=jiading_rec_bound, zoom=13, style=2)
grid_rec.plot(ax=ax1, lw=0.2, edgecolor='blue', facecolor="None")
plt.axis('off');
ax2 = plt.subplot(122)
plt.sca(ax2)
tbd.plot_map(plt, bounds=jiading_rec_bound, zoom=13, style=2)
grid_tri.plot(ax=ax2, lw=0.2, edgecolor='blue', facecolor="None")
plt.axis('off');

transbigdata.area_to_params
(location, accuracy=500, method=’rect’)
有时,由于数据稀疏,我们不需要生成所有栅格。在这种情况下,我们可以使用“transbigdata.area_to_params”。
此方法仅为栅格创建字典文件,因此速度要快得多。
[7]:
params = tbd.area_to_params(jiading_polygon)
pprint.pprint(params)
{'deltalat': 0.004496605206422906,
'deltalon': 0.005262604989003139,
'gridsize': 500,
'method': 'rect',
'slat': 31.25168182840957,
'slon': 121.13797109957756,
'theta': 0}
transbigdata.GPS_to_grid
(lon, lat, params)
下一个常见步骤是知道每个轨迹点属于哪个栅格。
[8]:
# First, we generate some random GPS points (20 points in this case)
lon_list, lat_list = [], []
for i in range(20):
gps_lon = random.uniform(jiading_rec_bound[0], jiading_rec_bound[2])
gps_lat = random.uniform(jiading_rec_bound[1], jiading_rec_bound[3])
lon_list.append(gps_lon)
lat_list.append(gps_lat)
gps_random = pd.DataFrame({'veh_id': range(20),
'lon': lon_list,
'lat': lat_list,
})
gps_random.head()
[8]:
veh_id | lon | lat | |
---|---|---|---|
0 | 0 | 121.204726 | 31.266296 |
1 | 1 | 121.168077 | 31.326952 |
2 | 2 | 121.142706 | 31.315498 |
3 | 3 | 121.215899 | 31.339561 |
4 | 4 | 121.217937 | 31.269540 |
[9]:
# match each point to the rect grid
gps_random['LonCol'], gps_random['LatCol'] = tbd.GPS_to_grid(gps_random['lon'], gps_random['lat'], params_rec)
gps_random.head()
[9]:
veh_id | lon | lat | LonCol | LatCol | |
---|---|---|---|---|---|
0 | 0 | 121.204726 | 31.266296 | 13 | 3 |
1 | 1 | 121.168077 | 31.326952 | 6 | 17 |
2 | 2 | 121.142706 | 31.315498 | 1 | 14 |
3 | 3 | 121.215899 | 31.339561 | 15 | 20 |
4 | 4 | 121.217937 | 31.269540 | 15 | 4 |
transbigdata.grid_to_centre
(gridid, params)
每个栅格的中心位置可以使用“transbigdata.grid_to_centre”获取
[10]:
# Use the matched grid as example
gps_random['LonGridCenter'], gps_random['LatGridCenter'] = \
tbd.grid_to_centre([gps_random['LonCol'], gps_random['LatCol']], params_rec)
# check the matched results
gps_random.head()
[10]:
veh_id | lon | lat | LonCol | LatCol | LonGridCenter | LatGridCenter | |
---|---|---|---|---|---|---|---|
0 | 0 | 121.204726 | 31.266296 | 13 | 3 | 121.206385 | 31.265172 |
1 | 1 | 121.168077 | 31.326952 | 6 | 17 | 121.169547 | 31.328124 |
2 | 2 | 121.142706 | 31.315498 | 1 | 14 | 121.143234 | 31.314634 |
3 | 3 | 121.215899 | 31.339561 | 15 | 20 | 121.216910 | 31.341614 |
4 | 4 | 121.217937 | 31.269540 | 15 | 4 | 121.216910 | 31.269668 |
transbigdata.grid_to_polygon
(gridid, params)
为了方便可视化,栅格参数可以转换为“几何”格式
[11]:
# Use the matched grid as example again
gps_random['grid_geo_polygon'] = tbd.grid_to_polygon([gps_random['LonCol'], gps_random['LatCol']], params_rec)
# check the matched results
gps_random.head()
[11]:
veh_id | lon | lat | LonCol | LatCol | LonGridCenter | LatGridCenter | grid_geo_polygon | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 121.204726 | 31.266296 | 13 | 3 | 121.206385 | 31.265172 | POLYGON ((121.2037536619401 31.262923341425626... |
1 | 1 | 121.168077 | 31.326952 | 6 | 17 | 121.169547 | 31.328124 | POLYGON ((121.16691542701707 31.32587581431555... |
2 | 2 | 121.142706 | 31.315498 | 1 | 14 | 121.143234 | 31.314634 | POLYGON ((121.14060240207206 31.31238599869628... |
3 | 3 | 121.215899 | 31.339561 | 15 | 20 | 121.216910 | 31.341614 | POLYGON ((121.2142788719181 31.339365629934818... |
4 | 4 | 121.217937 | 31.269540 | 15 | 4 | 121.216910 | 31.269668 | POLYGON ((121.2142788719181 31.26741994663205,... |
transbigdata.grid_to_area
(data, shape, params, col=[‘LONCOL’, ‘LATCOL’])
除了栅格之外,可能还有几个地区。“transbigdata.grid_to_area”可用于匹配信息。
在这种情况下,“jiading_polygon”中只有一个地区,匹配的列是“id”。
[12]:
gps_matched = tbd.grid_to_area(gps_random, jiading_polygon, params_rec, col=['LonCol', 'LatCol'])
# check the matched results
gps_matched.head()
/Applications/anaconda3/envs/tbd/lib/python3.9/site-packages/transbigdata/grids.py:421: UserWarning: CRS mismatch between the CRS of left geometries and the CRS of right geometries.
Use `to_crs()` to reproject one of the input geometries to match the CRS of the other.
Left CRS: None
Right CRS: EPSG:4326
data1 = gpd.sjoin(data1, shape)
[12]:
veh_id | lon | lat | LonCol | LatCol | LonGridCenter | LatGridCenter | grid_geo_polygon | geometry | index_right | id | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 121.204726 | 31.266296 | 13 | 3 | 121.206385 | 31.265172 | POLYGON ((121.2037536619401 31.262923341425626... | POINT (121.20638 31.26517) | 0 | 1 |
1 | 1 | 121.168077 | 31.326952 | 6 | 17 | 121.169547 | 31.328124 | POLYGON ((121.16691542701707 31.32587581431555... | POINT (121.16955 31.32812) | 0 | 1 |
2 | 2 | 121.142706 | 31.315498 | 1 | 14 | 121.143234 | 31.314634 | POLYGON ((121.14060240207206 31.31238599869628... | POINT (121.14323 31.31463) | 0 | 1 |
3 | 3 | 121.215899 | 31.339561 | 15 | 20 | 121.216910 | 31.341614 | POLYGON ((121.2142788719181 31.339365629934818... | POINT (121.21691 31.34161) | 0 | 1 |
4 | 4 | 121.217937 | 31.269540 | 15 | 4 | 121.216910 | 31.269668 | POLYGON ((121.2142788719181 31.26741994663205,... | POINT (121.21691 31.26967) | 0 | 1 |
transbigdata.grid_to_params
(grid)
从栅格几何体中获取栅格参数的有用工具
[13]:
# this is the formal grid geometry
grid_rec.head()
[13]:
LONCOL | LATCOL | geometry | |
---|---|---|---|
171 | 9 | 0 | POLYGON ((121.18270 31.24943, 121.18797 31.249... |
174 | 10 | 0 | POLYGON ((121.18797 31.24943, 121.19323 31.249... |
177 | 11 | 0 | POLYGON ((121.19323 31.24943, 121.19849 31.249... |
180 | 12 | 0 | POLYGON ((121.19849 31.24943, 121.20375 31.249... |
183 | 13 | 0 | POLYGON ((121.20375 31.24943, 121.20902 31.249... |
[14]:
tbd.grid_to_params(grid_rec)
[14]:
{'slon': 121.13797109957761,
'slat': 31.25168182840957,
'deltalon': 0.005262604988999442,
'deltalat': 0.0044966052064197015,
'theta': 0,
'method': 'rect'}
transbigdata.grid_params_optimize
(data, initialparams, col=[‘uid’, ‘lon’, ‘lat’], optmethod=’centerdist’, printlog=False, sample=0)
提供了几种优化栅格的方法
此方法依赖于“scikit-opt”包。为此,请在cmd中运行以下代码:
pip install scikit-opt
有关此方法的更多详细信息,请参阅此“notebook <https://github.com/ni1o1/transbigdata/blob/main/example/Example%206-Optimize%20grid%20params.ipynb>”__。
[15]:
# we use the random generated data again
gps_random.head()
[15]:
veh_id | lon | lat | LonCol | LatCol | LonGridCenter | LatGridCenter | grid_geo_polygon | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 121.204726 | 31.266296 | 13 | 3 | 121.206385 | 31.265172 | POLYGON ((121.2037536619401 31.262923341425626... |
1 | 1 | 121.168077 | 31.326952 | 6 | 17 | 121.169547 | 31.328124 | POLYGON ((121.16691542701707 31.32587581431555... |
2 | 2 | 121.142706 | 31.315498 | 1 | 14 | 121.143234 | 31.314634 | POLYGON ((121.14060240207206 31.31238599869628... |
3 | 3 | 121.215899 | 31.339561 | 15 | 20 | 121.216910 | 31.341614 | POLYGON ((121.2142788719181 31.339365629934818... |
4 | 4 | 121.217937 | 31.269540 | 15 | 4 | 121.216910 | 31.269668 | POLYGON ((121.2142788719181 31.26741994663205,... |
[16]:
tbd.grid_params_optimize(gps_random, params_rec, col=['veh_id', 'lon', 'lat'],printlog=True)
Optimized index centerdist: 116.11243965546235
Optimized gridding params: {'slon': 121.14169760115118, 'slat': 31.252579076220087, 'deltalon': 0.005262604989003139, 'deltalat': 0.004496605206422906, 'theta': 50.91831009508256, 'method': 'rect'}
Optimizing cost:

Result:

[16]:
{'slon': 121.14169760115118,
'slat': 31.252579076220087,
'deltalon': 0.005262604989003139,
'deltalat': 0.004496605206422906,
'theta': 50.91831009508256,
'method': 'rect'}
3 车辆轨迹数据处理
对于车辆轨迹数据,TransBigData 库 0.5.0 及以上版本提供了一套轨迹数据处理方法。这些方法包括轨迹数据的预处理和漂移校正、停靠点和行程的分割、基于格网的表示、可视化等。本文将介绍如何使用TransBigData库来处理轨迹数据。
[1]:
import pandas as pd
import geopandas as gpd
import transbigdata as tbd
# ensure tbd version is above 0.5.0
tbd.__version__
[1]:
'0.5.0'
轨迹数据质量
首先,我们读取数据并观察基本信息以检查是否有任何缺失值。使用DataFrame的内置方法,我们可以轻松查看数据的基本信息,包括数据类型,字段数,行数以及是否存在缺失值。代码如下:
[2]:
# Read the data
data = pd.read_csv('data/TaxiData-Sample.csv', header=None)
data.columns = ['id', 'time', 'lon', 'lat', 'OpenStatus', 'speed']
# Convert the time format
data['time'] = pd.to_datetime(data['time'])
data
[2]:
id | time | lon | lat | OpenStatus | speed | |
---|---|---|---|---|---|---|
0 | 34745 | 2023-05-29 20:27:43 | 113.806847 | 22.623249 | 1 | 27 |
1 | 34745 | 2023-05-29 20:24:07 | 113.809898 | 22.627399 | 0 | 0 |
2 | 34745 | 2023-05-29 20:24:27 | 113.809898 | 22.627399 | 0 | 0 |
3 | 34745 | 2023-05-29 20:22:07 | 113.811348 | 22.628067 | 0 | 0 |
4 | 34745 | 2023-05-29 20:10:06 | 113.819885 | 22.647800 | 0 | 54 |
... | ... | ... | ... | ... | ... | ... |
544994 | 28265 | 2023-05-29 21:35:13 | 114.321503 | 22.709499 | 0 | 18 |
544995 | 28265 | 2023-05-29 09:08:02 | 114.322701 | 22.681700 | 0 | 0 |
544996 | 28265 | 2023-05-29 09:14:31 | 114.336700 | 22.690100 | 0 | 0 |
544997 | 28265 | 2023-05-29 21:19:12 | 114.352600 | 22.728399 | 0 | 0 |
544998 | 28265 | 2023-05-29 19:08:06 | 114.137703 | 22.621700 | 0 | 0 |
544999 rows × 6 columns
[3]:
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 544999 entries, 0 to 544998
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 544999 non-null int64
1 time 544999 non-null datetime64[ns]
2 lon 544999 non-null float64
3 lat 544999 non-null float64
4 OpenStatus 544999 non-null int64
5 speed 544999 non-null int64
dtypes: datetime64[ns](1), float64(2), int64(3)
memory usage: 24.9 MB
其中列出了数据字段的数据类型、非空值的数量和内存使用情况。在“非空”列中,列出了每个字段的非空值的数量。如果字段的非空值数小于总行数,则表示该字段中存在缺失值。
接下来,我们将使用 TransBigData 生成数据质量报告,并观察数据中的车辆数量、观察时间段和采样间隔:
[4]:
# Generate data quality report
tbd.data_summary(data,col=['id', 'time'],show_sample_duration=True)
Amount of data
-----------------
Total number of data items: 544999
Total number of individuals: 180
Data volume of individuals(Mean): 3027.7722
Data volume of individuals(Upper quartile): 4056.25
Data volume of individuals(Median): 2600.5
Data volume of individuals(Lower quartile): 1595.75
Data time period
-----------------
Start time: 2023-05-29 00:00:00
End time: 2023-05-29 23:59:59
Sampling interval
-----------------
Mean: 27.995 s
Upper quartile: 30.0 s
Median: 20.0 s
Lower quartile: 15.0 s

冗余消除
消除冗余是清理轨迹数据的重要步骤。它减少了数据量,提高了数据处理效率,而不会影响数据中包含的信息。在实际的轨迹数据处理中,您可能会遇到以下两种类型的冗余:
同一时刻重复数据的冗余:
在轨迹数据集中,同一车辆在同一时刻可能有多个轨迹数据条目。当采样间隔与数据集中时间字段的精度相比太短时,可能会发生这种情况。例如,如果采样间隔为 1 秒,但数据集中的时间字段的精度为 1 分钟,则可能导致同一车辆在同一分钟内出现多个轨迹数据条目。不删除这些冗余数据可能会导致后续处理困难。消除这种冗余的方法很简单:在同一时刻只保留同一车辆的一个轨迹数据条目。
车辆停止的冗余:
在车辆轨迹数据中,采样间隔通常很短,例如每隔几秒钟收集一次数据。这意味着无论车辆是移动还是静止,都会持续生成数据。在实际应用中,重点通常是车辆在行驶期间的轨迹,而不是在停车期间。对于车辆停止的每个实例,我们只需要知道停止的开始和结束时间。在停靠点中间部分(位于同一位置)生成的数据是冗余的,可以将其删除以减小整体数据大小。对于具有相同位置的连续 n 个数据条目序列 (n>=3),我们只需要保留第一个和最后一个条目,因为中间数据是多余的。在代码中,将每个数据条目的车辆 ID 和经纬度与上一个和下一个轨迹条目进行比较就足够了。如果它们相同,则可以删除数据。
但是,上述车辆停靠点的冗余消除方法不考虑车辆ID,时间和经纬度以外的字段所携带的信息。例如,对于出租车车辆,乘客可以在停车期间登上出租车,将状态从“空置”更改为“占用”。在这种情况下,需要保留此信息。
TransBigData提供了一个功能“tbd.traj_clean_redundant()”,用于轨迹数据冗余消除。它可以处理上述冗余情况,还可以检测车辆ID和经纬度以外的字段中的冗余。代码如下:
[5]:
# data volume before Redundancy Elimination
len(data)
[5]:
544999
[6]:
# Data redundancy removal to reduce data size and improve computational efficiency in subsequent steps
#
data = tbd.traj_clean_redundant(
data,
col=['id', 'time', 'lon', 'lat', 'speed'] # Apart from vehicle ID, time, longitude, and latitude, consider whether the speed field has redundancy
)
len(data)
[6]:
421099
代码片段执行数据冗余删除,以减小数据大小并提高计算效率。“tbd”模块中的“traj_clean_redundant”函数用于此目的。该函数将“data”变量作为输入,并指定要考虑删除冗余的列(“col”),包括车辆ID,时间,经度,纬度和可选的速度字段。结果被存储回“data”变量中,并输出更新数据的长度。
漂移清理
在车辆轨迹数据中,由于数据采集设备错误、环境干扰、设备故障、GPS信号不稳定、卫星覆盖不足、信号障碍等因素,采集的车辆轨迹数据与实际情况之间可能会出现偏差和误差。这会导致轨迹数据的实际位置与收集的位置之间存在差异,这在车辆轨迹数据中称为数据漂移。在数据中,数据漂移表现为轨迹数据点与实际位置之间的距离很大,通常伴随着突然的跳跃。这种漂移会影响后续的空间分析和空间统计,需要清理车辆轨迹数据以确保数据的准确性和可用性。
要清除车辆轨迹数据以查找漂移,一种方法是移除定义研究区域之外的轨迹数据点。可以通过两种方式定义研究区域:通过指定左下角和右上角坐标来确定边界范围(边界),或者使用表示研究区域的地理信息文件(geojson 或 shapefile)。
要使用 geojson 或 shapefile 删除漂移数据,首先需要在 GeoPandas 中将 geojson 或 shapefile 读取为“GeoDataFrame”类型。然后,您可以使用 GeoPandas 提供的“intersects()”方法来确定轨迹数据是否在研究区域内。但是,此方法需要对每个轨迹数据点执行空间几何匹配,这对于大型数据集可能非常耗时。TransBigData 包中提供的“tbd.clean_outofshape()”方法提供了一种更有效的方法。它首先使用内置的栅格分区方法将轨迹数据映射到相应的栅格,然后基于栅格进行空间匹配,显着提高清理效率。
下面是一个使用TransBigData的“clean_outofshape()”方法进行数据偏移清理的示例代码片段:
[7]:
# Read the research area range
sz = gpd.read_file('Data/sz.json')
sz.plot()
[7]:
<AxesSubplot:>

[8]:
# Data drift removal
# Removing data outside the study area
data = tbd.clean_outofshape(data, sz, col=['lon', 'lat'], accuracy=500)
len(data)
[8]:
419448
要清理研究区域内的轨迹漂移,需要根据轨迹的连续变化进行评估和清理。有三种常见的清洁方法:
速度阈值法:如果当前轨迹数据与之前和后续轨迹之间的速度超过阈值,则视为漂移。
距离阈值法:如果当前轨迹数据与上一个和后续轨迹之间的距离超过阈值,则视为漂移。
角度阈值法:如果前一个、当前和后续轨迹形成的角度小于阈值,则视为漂移。
在TransBigData中,提供了“tbd.traj_clean_drift()”方法来清理多个车辆的轨迹数据。此方法将距离、速度和角度阈值集成到单个函数中。
下面是使用TransBigData的“traj_clean_drift()”方法的示例代码片段:
[9]:
# Drift cleaning within the study area using speed, distance, and angle as criteria
data = tbd.traj_clean_drift(
data, # Trajectory data, can include data for multiple vehicles, distinguished by ID
col=['id', 'time', 'lon', 'lat'], # Column names of the trajectory data
speedlimit=80, # Speed threshold in km/h, set to None to skip speed-based filtering
dislimit=4000, # Distance threshold in meters, set to None to skip distance-based filtering
anglelimit=30) # Angle threshold in degrees, set to None to skip angle-based filtering
len(data)
[9]:
405286
停止和行程提取
在车辆轨迹数据的长期连续观测中,常见的要求是从轨迹数据中提取停靠点和行程。可以分析停靠点以确定车辆停车的持续时间和位置,同时可以进一步分析行程以提取信息,例如每次行程的起点和目的地、行驶路径、行驶持续时间、行驶距离和行驶速度。在本节中,我们将解释如何从车辆轨迹中识别停靠点和行程,提取每个行程的轨迹信息,并生成轨迹线。
在车辆轨迹数据中,通常使用时间阈值方法标识停靠点和行程。方法如下:为了避免轨迹数据的波动,我们需要在地理空间中预定义一个栅格。如果两个连续数据点之间的持续时间超过我们设定的阈值(通常为 30 分钟),我们将其视为止损。两个停靠点之间的时间段被视为一个行程,如下图所示。
清理轨迹数据后,我们需要定义一个格网坐标系,并将轨迹数据转换为基于格网的表示,以识别停靠点和行程。
[11]:
# Define the grid parameters
bounds = [113.75, 22.4, 114.62, 22.86]
params = tbd.area_to_params(bounds,accuracy = 100)
params
[11]:
{'slon': 113.75,
'slat': 22.4,
'deltalon': 0.0009743362892898221,
'deltalat': 0.0008993210412845813,
'theta': 0,
'method': 'rect',
'gridsize': 100}
TransBigData包中通过“tbd.traj_stay_move()”功能提供了停靠点和行程的标识。这是代码:
[12]:
# Identify stay and move
stay, move = tbd.traj_stay_move(data, params, col=['id', 'time', 'lon', 'lat'], activitytime=1800)
len(stay), len(move)
[12]:
(545, 725)
在代码中,“data”表示清理后的轨迹数据。“traj_stay_move()”函数用于根据指定的停靠点阈值识别停靠点和行程。它返回两个输出:“停止”和“行程”,分别包含标识的停靠点和行程。您可以利用这些数据进行进一步分析。
注意:“tbd.traj_stay_move()”函数不会删除持续时间为 0 的行程。这是因为某些轨迹数据可能具有较长的采样间隔,可能无法捕获两个停靠点之间的行驶过程。因此,这些行程的计算持续时间将为 0。
[13]:
stay
[13]:
id | stime | LONCOL | LATCOL | etime | lon | lat | duration | stayid | |
---|---|---|---|---|---|---|---|---|---|
23320 | 22396 | 2023-05-29 06:10:09 | 262 | 284 | 2023-05-29 07:56:32 | 114.005547 | 22.655800 | 6383.0 | 0 |
51327 | 22396 | 2023-05-29 12:51:23 | 50 | 429 | 2023-05-29 16:44:57 | 113.798630 | 22.786167 | 14014.0 | 1 |
54670 | 22413 | 2023-05-29 00:00:09 | 145 | 431 | 2023-05-29 01:22:41 | 113.891403 | 22.787300 | 4952.0 | 2 |
54722 | 22413 | 2023-05-29 01:25:13 | 145 | 431 | 2023-05-29 02:01:44 | 113.891701 | 22.787399 | 2191.0 | 3 |
54741 | 22413 | 2023-05-29 02:18:13 | 145 | 431 | 2023-05-29 02:48:46 | 113.891502 | 22.787300 | 1833.0 | 4 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
151140 | 36686 | 2023-05-29 01:04:37 | 323 | 172 | 2023-05-29 02:33:37 | 114.065193 | 22.554672 | 5340.0 | 540 |
154762 | 36686 | 2023-05-29 03:03:07 | 307 | 185 | 2023-05-29 03:51:07 | 114.048721 | 22.566692 | 2880.0 | 541 |
154924 | 36686 | 2023-05-29 04:21:07 | 307 | 185 | 2023-05-29 05:06:07 | 114.048676 | 22.566605 | 2700.0 | 542 |
307421 | 36805 | 2023-05-29 03:15:54 | 324 | 168 | 2023-05-29 04:14:40 | 114.065552 | 22.551100 | 3526.0 | 543 |
337431 | 36805 | 2023-05-29 04:23:40 | 325 | 132 | 2023-05-29 05:13:33 | 114.066521 | 22.519133 | 2993.0 | 544 |
545 rows × 9 columns
[14]:
move
[14]:
id | SLONCOL | SLATCOL | stime | slon | slat | etime | elon | elat | ELONCOL | ELATCOL | duration | moveid | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 22396 | 253 | 326 | 2023-05-29 00:00:29 | 113.996719 | 22.693333 | 2023-05-29 06:10:09 | 114.005547 | 22.655800 | 262.0 | 284.0 | 22180.0 | 0 |
23320 | 22396 | 262 | 284 | 2023-05-29 07:56:32 | 114.005547 | 22.655800 | 2023-05-29 12:51:23 | 113.798630 | 22.786167 | 50.0 | 429.0 | 17691.0 | 1 |
51327 | 22396 | 50 | 429 | 2023-05-29 16:44:57 | 113.798630 | 22.786167 | 2023-05-29 23:59:55 | 114.025253 | 22.654900 | 283.0 | 283.0 | 26098.0 | 2 |
54670 | 22413 | 145 | 431 | 2023-05-29 00:00:09 | 113.891403 | 22.787300 | 2023-05-29 00:00:09 | 113.891403 | 22.787300 | 145.0 | 431.0 | 0.0 | 3 |
54670 | 22413 | 145 | 431 | 2023-05-29 01:22:41 | 113.891403 | 22.787300 | 2023-05-29 01:25:13 | 113.891701 | 22.787399 | 145.0 | 431.0 | 152.0 | 4 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
154762 | 36686 | 307 | 185 | 2023-05-29 03:51:07 | 114.048721 | 22.566692 | 2023-05-29 04:21:07 | 114.048676 | 22.566605 | 307.0 | 185.0 | 1800.0 | 720 |
154924 | 36686 | 307 | 185 | 2023-05-29 05:06:07 | 114.048676 | 22.566605 | 2023-05-29 23:53:46 | 114.124580 | 22.571978 | 384.0 | 191.0 | 67659.0 | 721 |
135725 | 36805 | 328 | 147 | 2023-05-29 00:00:03 | 114.070030 | 22.531967 | 2023-05-29 03:15:54 | 114.065552 | 22.551100 | 324.0 | 168.0 | 11751.0 | 722 |
307421 | 36805 | 324 | 168 | 2023-05-29 04:14:40 | 114.065552 | 22.551100 | 2023-05-29 04:23:40 | 114.066521 | 22.519133 | 325.0 | 132.0 | 540.0 | 723 |
337431 | 36805 | 325 | 132 | 2023-05-29 05:13:33 | 114.066521 | 22.519133 | 2023-05-29 23:53:51 | 114.120354 | 22.544300 | 380.0 | 160.0 | 67218.0 | 724 |
725 rows × 13 columns
根据停靠点和行程信息,您可以对轨迹数据进行切片,以提取停靠点和行程期间的轨迹点。由于您之前已执行冗余消除,因此停靠点期间的冗余轨迹点已被移除。因此,与行程期间的轨迹数据相比,停靠点期间的轨迹数据将具有明显更少的数据点。
轨迹切片
通过上述代码,已成功从数据中提取停车和旅行信息。但是,在获取的行程信息中,仅包含每次行程起点和终点的时间、纬度、经度信息,而不包含行程轨迹信息。为了进一步分析车辆的行驶轨迹,需要从每次行程的时间段中提取轨迹数据,即根据行驶信息对轨迹数据集进行切片。在先前计算的旅行信息中,每个旅行记录都有一个旅行 ID、开始时间和结束时间列。轨迹切片的结果是提取行程中的轨迹点,并为每个轨迹点分配一个行程 ID 标签。
下图说明了轨迹切片的概念。将为轨迹数据创建一个标志列,以标记每行是否在所需的切片时间段内。然后,将行程数据中的每个行程记录分解为开始时间记录(标志标签为 1)和结束时间记录(标志标签为 -1),并插入到轨迹数据中。接下来,对标志列进行分组并按车辆求和,以获得标志 1 列。在结果中,flag1 列值为 1(行程)和标志列值为 0(非临时插入的数据)的行是所需的轨迹数据。
可以使用“tbd.traj_slice”执行轨迹数据切片的代码,代码示例如下:
[18]:
# Extract trajectory points during parking
stay_points = tbd.traj_slice(data, stay, traj_col=['id', 'time'], slice_col=[
'id', 'stime', 'etime', 'stayid'])
stay_points
[18]:
id | time | lon | lat | OpenStatus | speed | stayid | |
---|---|---|---|---|---|---|---|
23320 | 22396 | 2023-05-29 06:10:09 | 114.005547 | 22.655800 | 0.0 | 1.0 | 0.0 |
23321 | 22396 | 2023-05-29 06:20:42 | 114.005547 | 22.655800 | 0.0 | 0.0 | 0.0 |
23322 | 22396 | 2023-05-29 06:25:09 | 114.005417 | 22.655767 | 0.0 | 0.0 | 0.0 |
23323 | 22396 | 2023-05-29 06:25:17 | 114.005417 | 22.655767 | 0.0 | 0.0 | 0.0 |
23324 | 22396 | 2023-05-29 06:30:09 | 114.005402 | 22.655767 | 0.0 | 0.0 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... |
307425 | 36805 | 2023-05-29 04:14:40 | 114.066452 | 22.550966 | 0.0 | 9.0 | 543.0 |
337431 | 36805 | 2023-05-29 04:23:40 | 114.066521 | 22.519133 | 0.0 | 20.0 | 544.0 |
337432 | 36805 | 2023-05-29 04:23:55 | 114.066521 | 22.519133 | 0.0 | 0.0 | 544.0 |
337433 | 36805 | 2023-05-29 05:13:27 | 114.066521 | 22.519133 | 1.0 | 0.0 | 544.0 |
337434 | 36805 | 2023-05-29 05:13:33 | 114.067230 | 22.519751 | 1.0 | 3.0 | 544.0 |
8428 rows × 7 columns
[19]:
# Extract trajectory points during travel
move_points = tbd.traj_slice(data, move, traj_col=['id', 'time'], slice_col=[
'id', 'stime', 'etime', 'moveid'])
move_points
[19]:
id | time | lon | lat | OpenStatus | speed | moveid | |
---|---|---|---|---|---|---|---|
0 | 22396 | 2023-05-29 00:00:29 | 113.996719 | 22.693333 | 1.0 | 20.0 | 0.0 |
27 | 22396 | 2023-05-29 00:01:01 | 113.995514 | 22.695032 | 1.0 | 34.0 | 0.0 |
28 | 22396 | 2023-05-29 00:01:09 | 113.995430 | 22.695766 | 1.0 | 41.0 | 0.0 |
29 | 22396 | 2023-05-29 00:01:41 | 113.995369 | 22.696484 | 1.0 | 0.0 | 0.0 |
30 | 22396 | 2023-05-29 00:02:21 | 113.995430 | 22.696650 | 1.0 | 17.0 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... |
132774 | 36805 | 2023-05-29 23:53:03 | 114.120354 | 22.544333 | 1.0 | 3.0 | 724.0 |
132775 | 36805 | 2023-05-29 23:53:09 | 114.120354 | 22.544300 | 1.0 | 2.0 | 724.0 |
132776 | 36805 | 2023-05-29 23:53:15 | 114.120354 | 22.544300 | 1.0 | 1.0 | 724.0 |
132777 | 36805 | 2023-05-29 23:53:21 | 114.120354 | 22.544300 | 1.0 | 0.0 | 724.0 |
132778 | 36805 | 2023-05-29 23:53:51 | 114.120354 | 22.544300 | 0.0 | 0.0 | 724.0 |
397892 rows × 7 columns
轨迹增密化和稀疏化
为了便于后续任务,例如将轨迹数据中的行驶路径与道路网络相匹配,我们在行驶过程中对轨迹点进行致密化或稀疏化。在此阶段,我们将 ID 列指定为行程 ID (moveid) 列,这意味着在对轨迹点执行致密化或稀疏化操作时,我们分别考虑每个行程。此操作的代码如下:
[59]:
# Trajectory densification
move_points_densified = tbd.traj_densify(
move_points, col=['moveid', 'time', 'lon', 'lat'], timegap=15)
move_points_densified
[59]:
id | time | lon | lat | OpenStatus | speed | moveid | |
---|---|---|---|---|---|---|---|
0 | 22396.0 | 2023-05-29 00:00:29 | 113.996719 | 22.693333 | 1.0 | 20.0 | 0.0 |
2 | NaN | 2023-05-29 00:00:30 | 113.996681 | 22.693386 | NaN | NaN | 0.0 |
3 | NaN | 2023-05-29 00:00:45 | 113.996116 | 22.694183 | NaN | NaN | 0.0 |
4 | NaN | 2023-05-29 00:01:00 | 113.995552 | 22.694979 | NaN | NaN | 0.0 |
1 | 22396.0 | 2023-05-29 00:01:01 | 113.995514 | 22.695032 | 1.0 | 34.0 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... |
397889 | 36805.0 | 2023-05-29 23:53:15 | 114.120354 | 22.544300 | 1.0 | 1.0 | 724.0 |
397890 | 36805.0 | 2023-05-29 23:53:21 | 114.120354 | 22.544300 | 1.0 | 0.0 | 724.0 |
4175974 | NaN | 2023-05-29 23:53:30 | 114.120354 | 22.544300 | NaN | NaN | 724.0 |
4175975 | NaN | 2023-05-29 23:53:45 | 114.120354 | 22.544300 | NaN | NaN | 724.0 |
397891 | 36805.0 | 2023-05-29 23:53:51 | 114.120354 | 22.544300 | 0.0 | 0.0 | 724.0 |
1211070 rows × 7 columns
[60]:
# Trajectory sparsification
move_points_sparsified = tbd.traj_sparsify(
move_points, col=['moveid', 'time', 'lon', 'lat'], timegap=120)
move_points_sparsified
[60]:
id | time | lon | lat | OpenStatus | speed | moveid | |
---|---|---|---|---|---|---|---|
0 | 22396 | 2023-05-29 00:00:29 | 113.996719 | 22.693333 | 1.0 | 20.0 | 0.0 |
4 | 22396 | 2023-05-29 00:02:21 | 113.995430 | 22.696650 | 1.0 | 17.0 | 0.0 |
7 | 22396 | 2023-05-29 00:04:21 | 113.992348 | 22.696733 | 0.0 | 36.0 | 0.0 |
10 | 22396 | 2023-05-29 00:06:21 | 113.986366 | 22.691000 | 0.0 | 48.0 | 0.0 |
12 | 22396 | 2023-05-29 00:08:21 | 113.989586 | 22.681749 | 0.0 | 43.0 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... |
397822 | 36805 | 2023-05-29 23:45:27 | 114.091217 | 22.540768 | 0.0 | 11.0 | 724.0 |
397835 | 36805 | 2023-05-29 23:47:21 | 114.093002 | 22.543383 | 1.0 | 0.0 | 724.0 |
397855 | 36805 | 2023-05-29 23:49:21 | 114.105850 | 22.545250 | 1.0 | 58.0 | 724.0 |
397875 | 36805 | 2023-05-29 23:51:21 | 114.119514 | 22.547033 | 1.0 | 24.0 | 724.0 |
397890 | 36805 | 2023-05-29 23:53:21 | 114.120354 | 22.544300 | 1.0 | 0.0 | 724.0 |
90172 rows × 7 columns
[ ]:
# define a function to plot the trajectory
def plot_traj(traj):
import folium
# 1. Create a map with the center at the average coordinates of the trajectory
m = folium.Map(location=[traj['lat'].mean(), traj['lon'].mean()], # Map center
zoom_start=14, # Map zoom level
tiles='cartodbpositron') # Map style
# 2. Add the trajectory
folium.PolyLine(
traj[['lat', 'lon']].values.tolist(), # Trajectory coordinates
color='red', # Trajectory color
weight=2.5, # Trajectory width
opacity=1).add_to(m) # Trajectory opacity, add to the map after creating the trajectory
# 3. Add trajectory points
for i in range(len(traj)):
folium.CircleMarker(
location=[traj['lat'].iloc[i], traj['lon'].iloc[i]], # Trajectory point coordinates
radius=3, # Trajectory point radius
color='red', # Trajectory point color
).add_to(m) # Fill opacity, add to the map after creating the trajectory point
# 4. Add start and end markers
folium.Marker([traj['lat'].iloc[0], traj['lon'].iloc[0]], # Start point coordinates
popup='Start', # Start marker label
icon=folium.Icon(color='green')).add_to(m) # Start marker color
folium.Marker([traj['lat'].iloc[-1], traj['lon'].iloc[-1]],
popup='End',
icon=folium.Icon(color='red')).add_to(m)
# 5. Display the map, directly in Jupyter Notebook
return m
[65]:
moveid = 51
# Original trajectory
traj = move_points[move_points['moveid']==moveid]
plot_traj(traj)
[65]:
[66]:
# Densified trajectory
traj = move_points_densified[move_points_densified['moveid']==moveid]
plot_traj(traj)
[66]:
[67]:
# Sparsified trajectory
traj = move_points_sparsified[move_points_sparsified['moveid']==moveid]
plot_traj(traj)
[67]:
轨迹平滑
在处理车辆轨迹数据时,轨迹点表示对车辆实际“状态”的“观察”。由于误差,观察到的数据可能与车辆的实际状态有所不同。
如何更准确地估计车辆的实际状态?考虑上一节中提到的检测轨迹漂移的方法,该方法涉及将轨迹点的位置与先前轨迹点的位置进行比较,以检查显着和不合理的跳跃。这种方法基本上基于根据车辆先前的轨迹预测车辆未来可能的位置。如果下一个记录的轨迹点明显偏离预期位置,则可以确定轨迹异常。
这种方法与卡尔曼滤波的概念有相似之处。卡尔曼滤波是一种线性二次估计算法,用于线性动态系统中的状态估计。它将先前的状态估计(即当前轨迹点的预测位置)与当前观测数据(当前轨迹点的记录位置)相结合,以获得当前状态的最优估计。
卡尔曼滤波的实现涉及使用先前的最佳结果预测当前值,然后使用观测值校正当前值以获得最佳结果。这种方法有效地减少了噪声的影响,可以更准确地估计车辆的实际状态。
[84]:
move_id =51
traj = move_points[move_points['moveid'] == move_id].copy()
traj_smoothed = tbd.traj_smooth(traj,col = ['id','time','lon', 'lat'],proj=False,process_noise_std = 0.01, measurement_noise_std = 1)
[85]:
# plot the trajectory
import folium
m = folium.Map(location=[traj['lat'].mean(), traj['lon'].mean()],
zoom_start=14,
tiles='cartodbpositron')
# original trajectory
folium.PolyLine(
traj[['lat', 'lon']].values.tolist(),
color='red',
weight=2.5,
opacity=1).add_to(m)
# smoothed trajectory
folium.PolyLine(
traj_smoothed[['lat', 'lon']].values.tolist(),
color='blue',
weight=2.5,
opacity=1).add_to(m)
m
[85]:
卡尔曼滤波器的目标是通过估计系统状态来优化观测值,同时考虑观测噪声和系统动力学的不确定性。它通过减少噪声影响和最小化小范围内的波动,在平滑轨迹数据方面具有优势。然而,卡尔曼滤波器不能完全消除所有噪声或处理轨迹漂移。
卡尔曼滤波器适用于轨迹数据中噪声相对稳定的情况,这意味着噪声方差保持不变。它在平滑由轨迹数据中的测量误差引起的小规模波动方面特别有效。
然而,当轨迹中出现显著漂移时,卡尔曼滤波器的有效性是有限的。漂移点被视为观测值,对状态估计有重大影响,卡尔曼滤波器无法直接处理。
此外,卡尔曼滤波需要指定过程误差和观测误差的协方差矩阵,这些参数设置会影响平滑效果。不正确的协方差矩阵设置可能会导致平滑轨迹数据出现显著偏差,尤其是在处理可能偏离道路网络的轨迹数据时。
在处理轨迹数据时,常见的方法是先去除漂移,然后进行平滑,最后进行路网匹配。这种方法背后的基本原理如下:
漂移消除步骤消除了数据中的明显漂移点,这些漂移点是大噪声分量。漂移点的存在会严重干扰后续处理步骤。去除或校正漂移点可确保后续处理的准确性和可靠性。
去除漂移后,轨迹数据可能仍包含一些噪声和波动。为了减少这些噪声和波动的影响,可以应用平滑来进一步处理轨迹数据,使其更平滑、更连续,并保持轨迹的整体趋势。
最后,平滑后的轨迹更稳定,更适合路网匹配。它减少了噪声和波动引起的误差,从而提高了路网匹配的准确性和可靠性。
4 三角形和六边形栅格的生成与旋转
在这个例子中,我们将介绍更多用于“TransBigData”栅格处理的选项,包括: - 添加旋转角度。- 三角形和六边形栅格。
旋转栅格
[1]:
#Read taxi gps data
import transbigdata as tbd
import pandas as pd
data = pd.read_csv('data/TaxiData-Sample.csv',header = None)
data.columns = ['VehicleNum','time','lon','lat','OpenStatus','Speed']
#Define the study area
bounds = [113.75, 22.4, 114.62, 22.86]
#Delete the data out of the study area
data = tbd.clean_outofbounds(data,bounds = bounds,col = ['lon','lat'])
[2]:
#Obtain the gridding parameters
params = tbd.area_to_params(bounds,accuracy = 1000)
#Add a rotation angle
params['theta'] = 5
print(params)
{'slon': 113.75, 'slat': 22.4, 'deltalon': 0.00974336289289822, 'deltalat': 0.008993210412845813, 'theta': 5, 'method': 'rect', 'gridsize': 1000}
[3]:
#Map the GPS data to grids
data['LONCOL'],data['LATCOL'] = tbd.GPS_to_grid(data['lon'],data['lat'],params)
#Aggregate data into grids
grid_agg = data.groupby(['LONCOL','LATCOL'])['VehicleNum'].count().reset_index()
#Generate grid geometry
grid_agg['geometry'] = tbd.grid_to_polygon([grid_agg['LONCOL'],grid_agg['LATCOL']],params)
#Change the type into GeoDataFrame
import geopandas as gpd
grid_agg = gpd.GeoDataFrame(grid_agg)
#Plot the grids
grid_agg.plot(column = 'VehicleNum',cmap = 'autumn_r',figsize=(10,5))
[3]:
<AxesSubplot:>

三角形和六边形栅格
[4]:
#Triangle grids
params['method'] = 'tri'
[5]:
#Map the GPS data to grids
data['loncol_1'],data['loncol_2'],data['loncol_3'] = tbd.GPS_to_grid(data['lon'],data['lat'],params)
#Aggregate data into grids
grid_agg = data.groupby(['loncol_1','loncol_2','loncol_3'])['VehicleNum'].count().reset_index()
#Generate grid geometry
grid_agg['geometry'] = tbd.grid_to_polygon([grid_agg['loncol_1'],grid_agg['loncol_2'],grid_agg['loncol_3']],params)
#Change the type into GeoDataFrame
import geopandas as gpd
grid_agg = gpd.GeoDataFrame(grid_agg)
#Plot the grids
grid_agg.plot(column = 'VehicleNum',cmap = 'autumn_r',figsize=(10,5))
[5]:
<AxesSubplot:>

[6]:
#Hexagon grids
params['method'] = 'hexa'
[7]:
#Map the GPS data to grids
data['loncol_1'],data['loncol_2'],data['loncol_3'] = tbd.GPS_to_grid(data['lon'],data['lat'],params)
#Aggregate data into grids
grid_agg = data.groupby(['loncol_1','loncol_2','loncol_3'])['VehicleNum'].count().reset_index()
#Generate grid geometry
grid_agg['geometry'] = tbd.grid_to_polygon([grid_agg['loncol_1'],grid_agg['loncol_2'],grid_agg['loncol_3']],params)
#Change the type into GeoDataFrame
import geopandas as gpd
grid_agg = gpd.GeoDataFrame(grid_agg)
#Plot the grids
grid_agg.plot(column = 'VehicleNum',cmap = 'autumn_r',figsize=(10,5))
[7]:
<AxesSubplot:>

5 栅格化参数优化
为什么要将数据聚合到栅格中?
在TransBigData中,栅格化框架由栅格化参数确定。每个格网参数都可以定义一个格网坐标系。参数如下:
params=(lonStart,latStart,deltaLon,deltaLat,theta)
然而,在我们的研究中如何选择合适的栅格参数是最基本的事情,这可能对最终的分析结果产生很大的影响。
一个好主意是输入城市路网数据并从路网优化栅格参数。但是,对于像TransBigData这样的栅格框架,这不是最好的解决方案。我们要分析的GPS数据不仅是车辆轨迹数据,它们也不必遵循给定的道路网络。此外,道路网络的空间特征已经包含在车辆轨迹中。因此,格网参数的选择应取决于GPS数据的原始空间属性。
在分析个人移动数据时,最佳栅格选择标准也不同。由于个人通常会停留更多时间并在其活动点中生成更多数据,因此更好的栅格化应将这些数据匹配到同一栅格中。结果应该是很少有栅格占用更多数据。
在这里,我们提供了三种方法来优化栅格参数:centerdist,gini和gridscount
[1]:
import pandas as pd
import geopandas as gpd
import transbigdata as tbd
#Read taxi gps data
tripdata = pd.read_csv(r'data/TaxiData-Sample.csv')
tripdata.columns = ['track_id','time','lon','lat','OpenStatus','Speed']
#Retain the data in given area
area = gpd.read_file(r'data/gis/szarea1.json')
tripdata = tbd.clean_outofshape(tripdata,area,col=['lon','lat'])
#Generate initial griding params
bounds = [113.6,22.4,114.8,22.9]
initialparams = tbd.area_to_params(bounds,accuracy = 500)
centerdist: 最小化栅格中心与GPS数据的距离
当一批距离很近的数据分布在栅格边缘时,GPS数据的偏差会导致这些数据被匹配到不同的栅格中。因此,解决方案之一是最小化栅格中心和GPS数据之间的距离。
[2]:
#Optimize gridding params
params_optimized = tbd.grid_params_optimize(tripdata,
initialparams,
col=['track_id','lon','lat'],
optmethod='centerdist',
sample=0, #not sampling
printlog=True)
Optimized index centerdist: 160.41280636449184
Optimized gridding params: {'slon': 113.60144616975187, 'slat': 22.401543058590295, 'deltalon': 0.004872390756896538, 'deltalat': 0.004496605206422906, 'theta': 43.585298279322615, 'method': 'rect'}

gini:最大化基尼指数
[3]:
#Optimize griding params
params_optimized = tbd.grid_params_optimize(tripdata,
initialparams,
col=['track_id','lon','lat'],
optmethod='gini',
sample=0, #not sampling
printlog=True)
Optimized index gini: -0.11709661279249717
Optimized gridding params: {'slon': 113.60363252207824, 'slat': 22.40161914185426, 'deltalon': 0.004872390756896538, 'deltalat': 0.004496605206422906, 'theta': 47.730990684694575, 'method': 'rect'}

gridscount: 最小化个体的栅格平均数
在此标准下,每个人都应出现在尽可能少的栅格中。
[4]:
#Optimize griding params
params_optimized = tbd.grid_params_optimize(tripdata,
initialparams,
col=['track_id','lon','lat'],
optmethod='gridscount',
sample=0, #not sampling
printlog=True)
Optimized index gridscount: 9.0
Optimized gridding params: {'slon': 113.60372085909265, 'slat': 22.403002740815666, 'deltalon': 0.004872390756896538, 'deltalat': 0.004496605206422906, 'theta': 44.56000665402531, 'method': 'rect'}

还支持优化三角形和六边形栅格化参数
[5]:
initialparams['method'] = 'tri'
[6]:
#Optimize gridding params
params_optimized = tbd.grid_params_optimize(tripdata,
initialparams,
col=['track_id','lon','lat'],
optmethod='centerdist',
sample=0, #not sampling
printlog=True)
Optimized index centerdist: 136.87564489047065
Optimized gridding params: {'slon': 113.60421146982776, 'slat': 22.402738210124514, 'deltalon': 0.004872390756896538, 'deltalat': 0.004496605206422906, 'theta': 31.61303640854649, 'method': 'tri'}

[7]:
initialparams = tbd.area_to_params(bounds,accuracy = 500/(6**0.5))
initialparams['method'] = 'hexa'
[8]:
#Optimize gridding params
params_optimized = tbd.grid_params_optimize(tripdata,
initialparams,
col=['track_id','lon','lat'],
optmethod='centerdist',
sample=0, #not sampling
printlog=True)
Optimized index centerdist: 135.60103782128888
Optimized gridding params: {'slon': 113.60043088516572, 'slat': 22.400303375881162, 'deltalon': 0.0019891451969749397, 'deltalat': 0.0018357313884130575, 'theta': 17.62535531106509, 'method': 'hexa'}

各类数据处理任务示例
6手机数据处理
[1]:
import pandas as pd
import transbigdata as tbd
data = pd.read_csv(r'data/mobiledata_sample.csv')
#make sure the time column is correct
data['stime'] = pd.to_datetime(data['stime'], format='%Y%m%d%H%M')
data = data.sort_values(by = ['user_id','stime'])
data.head()
[1]:
user_id | stime | longitude | latitude | date | |
---|---|---|---|---|---|
78668 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-01 00:00:00 | 121.43 | 30.175 | 20180601 |
78669 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-01 03:35:00 | 121.43 | 30.175 | 20180601 |
78670 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-01 04:25:00 | 121.43 | 30.175 | 20180601 |
78671 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-01 05:15:00 | 121.43 | 30.175 | 20180601 |
78289 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-01 06:05:00 | 121.43 | 30.175 | 20180601 |
从手机轨迹数据中识别停留和移动信息
在处理手机数据时,TransBigData的方法是首先将数据与网格对应,并将同一网格内的数据视为位于同一位置,以避免导致同一位置被识别为多个位置的数据定位错误。
[2]:
#Obtain gridding parameters
params = tbd.area_to_params([121.860, 29.295, 121.862, 29.301], accuracy=500)
#Identify stay and move infomation from mobile phone trajectory data
stay,move = tbd.mobile_stay_move(data,params,col = ['user_id','stime','longitude', 'latitude'])
[3]:
stay.head()
[3]:
user_id | stime | LONCOL | LATCOL | etime | lon | lat | duration | |
---|---|---|---|---|---|---|---|---|
0 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-01 00:00:00 | -83 | 196 | 2018-06-01 07:21:00 | 121.432040 | 30.176335 | 26460.0 |
1 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-01 07:36:00 | -81 | 191 | 2018-06-01 12:02:00 | 121.442352 | 30.153852 | 15960.0 |
2 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-01 12:20:00 | -83 | 196 | 2018-06-01 13:04:00 | 121.432040 | 30.176335 | 2640.0 |
3 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-01 14:34:00 | -60 | 189 | 2018-06-01 23:12:00 | 121.550631 | 30.144858 | 31080.0 |
4 | 00466ab30de56db7efbd04991b680ae1 | 2018-06-02 00:02:00 | -83 | 196 | 2018-06-02 09:36:00 | 121.432040 | 30.176335 | 34440.0 |
[4]:
move.head()
[4]:
user_id | SLONCOL | SLATCOL | stime | slon | slat | etime | elon | elat | ELONCOL | ELATCOL | duration | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 00466ab30de56db7efbd04991b680ae1 | -83 | 196 | 2018-06-01 07:21:00 | 121.432040 | 30.176335 | 2018-06-01 07:36:00 | 121.442352 | 30.153852 | -81.0 | 191.0 | 900.0 |
1 | 00466ab30de56db7efbd04991b680ae1 | -81 | 191 | 2018-06-01 12:02:00 | 121.442352 | 30.153852 | 2018-06-01 12:20:00 | 121.432040 | 30.176335 | -83.0 | 196.0 | 1080.0 |
2 | 00466ab30de56db7efbd04991b680ae1 | -83 | 196 | 2018-06-01 13:04:00 | 121.432040 | 30.176335 | 2018-06-01 14:34:00 | 121.550631 | 30.144858 | -60.0 | 189.0 | 5400.0 |
3 | 00466ab30de56db7efbd04991b680ae1 | -60 | 189 | 2018-06-01 23:12:00 | 121.550631 | 30.144858 | 2018-06-02 00:02:00 | 121.432040 | 30.176335 | -83.0 | 196.0 | 3000.0 |
4 | 00466ab30de56db7efbd04991b680ae1 | -83 | 196 | 2018-06-02 09:36:00 | 121.432040 | 30.176335 | 2018-06-02 10:56:00 | 121.406259 | 30.176335 | -88.0 | 196.0 | 4800.0 |
家庭和工作地点标识
[5]:
#Identify home location
home = tbd.mobile_identify_home(stay, col=['user_id','stime', 'etime','LONCOL', 'LATCOL','lon','lat'], start_hour=8, end_hour=20 )
home.head()
[5]:
user_id | LONCOL | LATCOL | lon | lat | |
---|---|---|---|---|---|
1781 | fcc3a9e9df361667e00ee5c16cb08922 | -147 | 292 | 121.102046 | 30.608009 |
1769 | f71e9d7d78e6f5bc9539d141e3a5a1c4 | -216 | 330 | 120.746272 | 30.778880 |
1752 | f6b65495b63574c2eb73c7e63ae38252 | -225 | -286 | 120.699867 | 28.008971 |
1739 | f1f4224a60da630a0b83b3a231022123 | 102 | 157 | 122.385927 | 30.000967 |
1700 | e96739aedb70a8e5c4efe4c488934b43 | -223 | 278 | 120.710179 | 30.545056 |
[6]:
#Identify work location
work = tbd.mobile_identify_work(stay, col=['user_id', 'stime', 'etime', 'LONCOL', 'LATCOL','lon','lat'], minhour=3, start_hour=8, end_hour=20,workdaystart=0, workdayend=4)
work.head()
[6]:
user_id | LONCOL | LATCOL | lon | lat | |
---|---|---|---|---|---|
0 | fcc3a9e9df361667e00ee5c16cb08922 | -146 | 292 | 121.107203 | 30.608009 |
1 | f71e9d7d78e6f5bc9539d141e3a5a1c4 | -219 | 325 | 120.730804 | 30.756397 |
2 | f6b65495b63574c2eb73c7e63ae38252 | -225 | -286 | 120.699867 | 28.008971 |
3 | f1f4224a60da630a0b83b3a231022123 | 103 | 153 | 122.391083 | 29.982981 |
5 | e1a1dfb5a77578c889bd3368ffe1d30f | -62 | 138 | 121.540319 | 29.915532 |
[7]:
# If you want to filter out the users with work place location from home location
home['flag'] = 1
work = pd.merge(work,home,how='left')
home = home.drop(['flag'],axis = 1)
work = work[work['flag'].isnull()].drop(['flag'],axis = 1)
绘制活动图
[8]:
#Plot the activity of the user, different color represent different location
uid = 'fcc3a9e9df361667e00ee5c16cb08922'
stay['group'] = stay['LONCOL'].astype(str)+','+stay['LATCOL'].astype(str)
tbd.plot_activity(stay[stay['user_id']==uid],figsize = (20, 5))

7 地铁网络数据获取与拓扑建模
[1]:
import warnings
warnings.filterwarnings('ignore')
以下示例演示如何使用 TransBigData 下载地铁线路并为地铁线路网络构建拓扑网络模型
下载地铁线路
[2]:
import pandas as pd
import numpy as np
import geopandas as gpd
import transbigdata as tbd
line,stop = tbd.getbusdata('厦门',['1号线','2号线','3号线'])
Obtaining city id: 厦门success
1号线
地铁1号线(镇海路-岩内) success
地铁1号线(岩内-镇海路) success
2号线
地铁2号线(五缘湾-天竺山) success
地铁2号线(天竺山-五缘湾) success
3号线
地铁3号线(厦门火车站-蔡厝) success
地铁3号线(蔡厝-厦门火车站) success
地铁3号线南延段(厦门火车站-沙坡尾) success
地铁3号线南延段(沙坡尾-厦门火车站) success
[3]:
line.plot()
[3]:
<AxesSubplot:>

[4]:
stop.plot()
[4]:
<AxesSubplot:>

将地铁线路分成几个部分
“tbd.split_subwayline”方法可用于将地铁线路与地铁站进行切片,以获取地铁路段信息(此步骤在地铁客流可视化中很有用)
[5]:
metroline_splited = tbd.split_subwayline(line,stop)
metroline_splited.plot(column = pd.Series(metroline_splited.index))
[5]:
<AxesSubplot:>

地铁网络拓扑建模
我们还可以使用地铁站数据来构建地铁网络的拓扑模型。此步骤对于后续识别地铁行驶路径非常有用。生成的图形依赖于 NetworkX。
[6]:
#Modeling for subway network topology
line['speed'] = 55 #operation speed 55km/h
line['stoptime'] = 0.5 #stop time at each stations 30s
import networkx as nx
G = tbd.metro_network(line,stop, transfertime=5)
nx.draw(G,node_size=20)

[7]:
path = tbd.get_shortest_path(G,stop,'镇海路','蔡厝')
path
[7]:
['地铁1号线镇海路',
'地铁1号线中山公园',
'地铁1号线将军祠',
'地铁1号线文灶',
'地铁1号线湖滨东路',
'地铁3号线湖滨东路',
'地铁3号线体育中心',
'地铁3号线人才中心',
'地铁3号线湖里公园',
'地铁3号线华荣路',
'地铁3号线火炬园',
'地铁3号线小东山',
'地铁3号线安兜',
'地铁3号线坂尚',
'地铁3号线湖里创新园',
'地铁3号线五缘湾',
'地铁3号线林前',
'地铁3号线鼓锣',
'地铁3号线后村',
'地铁3号线蔡厝']
[8]:
tbd.get_path_traveltime(G,path)
[8]:
49.34680872200037
[9]:
# k th shortest paths
paths = tbd.get_k_shortest_paths(G,stop,'镇海路','蔡厝',2)
paths
[9]:
[['地铁1号线镇海路',
'地铁1号线中山公园',
'地铁1号线将军祠',
'地铁1号线文灶',
'地铁1号线湖滨东路',
'地铁3号线湖滨东路',
'地铁3号线体育中心',
'地铁3号线人才中心',
'地铁3号线湖里公园',
'地铁3号线华荣路',
'地铁3号线火炬园',
'地铁3号线小东山',
'地铁3号线安兜',
'地铁3号线坂尚',
'地铁3号线湖里创新园',
'地铁3号线五缘湾',
'地铁3号线林前',
'地铁3号线鼓锣',
'地铁3号线后村',
'地铁3号线蔡厝'],
['地铁1号线镇海路',
'地铁1号线中山公园',
'地铁1号线将军祠',
'地铁1号线文灶',
'地铁1号线湖滨东路',
'地铁1号线莲坂',
'地铁1号线莲花路口',
'地铁1号线吕厝',
'地铁1号线乌石浦',
'地铁1号线塘边',
'地铁1号线火炬园',
'地铁3号线火炬园',
'地铁3号线小东山',
'地铁3号线安兜',
'地铁3号线坂尚',
'地铁3号线湖里创新园',
'地铁3号线五缘湾',
'地铁3号线林前',
'地铁3号线鼓锣',
'地铁3号线后村',
'地铁3号线蔡厝']]
[10]:
tbd.get_path_traveltime(G,paths[1])
[10]:
49.633890662025024
8 共享单车出行需求的社区发现
对于共享单车需求来说,每一次出行都可以看作是从起点到终点的一段过程。当我们把起点和终点看成节点,把它们之间的行程当作边时,就可以构建一个网络。通过分析该网络,我们可以得到有关城市空间连接结构或共享单车需求的宏观出行特征的信息。
社区检测,也称为图分区,帮助我们揭示网络中节点之间的隐藏关系。在这个例子中,我们将介绍如何从共享单车数据将TransBigData集成到社区检测的分析过程中。
要运行这个例子,你可能必须安装``igraph``和``seaborn``:
pip install igraphpip install seaborn
数据预处理
[1]:
# Fristly, import packages.
import pandas as pd
import numpy as np
import geopandas as gpd
import transbigdata as tbd
[2]:
#Read bicycle sharing data
bikedata = pd.read_csv(r'data/bikedata-sample.csv')
bikedata.head(5)
[2]:
BIKE_ID | DATA_TIME | LOCK_STATUS | LONGITUDE | LATITUDE | |
---|---|---|---|---|---|
0 | 5 | 2018-09-01 0:00:36 | 1 | 121.363566 | 31.259615 |
1 | 6 | 2018-09-01 0:00:50 | 0 | 121.406226 | 31.214436 |
2 | 6 | 2018-09-01 0:03:01 | 1 | 121.409402 | 31.215259 |
3 | 6 | 2018-09-01 0:24:53 | 0 | 121.409228 | 31.214427 |
4 | 6 | 2018-09-01 0:26:38 | 1 | 121.409771 | 31.214406 |
[3]:
#Read the polygon of the study area
shanghai_admin = gpd.read_file(r'data/shanghai.json')
#delete the data outside of the study area
bikedata = tbd.clean_outofshape(bikedata, shanghai_admin, col=['LONGITUDE', 'LATITUDE'], accuracy=500)
使用``tbd.bikedata_to_od``识别共享单车行程信息
[4]:
move_data,stop_data = tbd.bikedata_to_od(bikedata,
col = ['BIKE_ID','DATA_TIME','LONGITUDE','LATITUDE','LOCK_STATUS'])
move_data.head(5)
[4]:
BIKE_ID | stime | slon | slat | etime | elon | elat | |
---|---|---|---|---|---|---|---|
96 | 6 | 2018-09-01 0:00:50 | 121.406226 | 31.214436 | 2018-09-01 0:03:01 | 121.409402 | 31.215259 |
561 | 6 | 2018-09-01 0:24:53 | 121.409228 | 31.214427 | 2018-09-01 0:26:38 | 121.409771 | 31.214406 |
564 | 6 | 2018-09-01 0:50:16 | 121.409727 | 31.214403 | 2018-09-01 0:52:14 | 121.412610 | 31.214905 |
784 | 6 | 2018-09-01 0:53:38 | 121.413333 | 31.214951 | 2018-09-01 0:55:38 | 121.412656 | 31.217051 |
1028 | 6 | 2018-09-01 11:35:01 | 121.419261 | 31.213414 | 2018-09-01 11:35:13 | 121.419518 | 31.213657 |
[5]:
#Calculate the travel distance
move_data['distance'] = tbd.getdistance(move_data['slon'],move_data['slat'],move_data['elon'],move_data['elat'])
#Remove too long and too short trips
move_data = move_data[(move_data['distance']>100)&(move_data['distance']<10000)]
执行数据栅格化:
[6]:
#obtain gridding params
bounds = (120.85, 30.67, 122.24, 31.87)
params = tbd.grid_params(bounds,accuracy = 500)
#aggregate the travel informations
od_gdf = tbd.odagg_grid(move_data, params, col=['slon', 'slat', 'elon', 'elat'])
od_gdf.head(5)
/opt/anaconda3/envs/transbigdata/lib/python3.9/site-packages/pandas/core/dtypes/cast.py:122: ShapelyDeprecationWarning: The array interface is deprecated and will no longer work in Shapely 2.0. Convert the '.coords' to a numpy array instead.
arr = construct_1d_object_array_from_listlike(values)
[6]:
SLONCOL | SLATCOL | ELONCOL | ELATCOL | count | SHBLON | SHBLAT | EHBLON | EHBLAT | geometry | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 26 | 95 | 26 | 96 | 1 | 120.986782 | 31.097177 | 120.986782 | 31.101674 | LINESTRING (120.98678 31.09718, 120.98678 31.1... |
40803 | 117 | 129 | 116 | 127 | 1 | 121.465519 | 31.250062 | 121.460258 | 31.241069 | LINESTRING (121.46552 31.25006, 121.46026 31.2... |
40807 | 117 | 129 | 117 | 128 | 1 | 121.465519 | 31.250062 | 121.465519 | 31.245565 | LINESTRING (121.46552 31.25006, 121.46552 31.2... |
40810 | 117 | 129 | 117 | 131 | 1 | 121.465519 | 31.250062 | 121.465519 | 31.259055 | LINESTRING (121.46552 31.25006, 121.46552 31.2... |
40811 | 117 | 129 | 118 | 126 | 1 | 121.465519 | 31.250062 | 121.470780 | 31.236572 | LINESTRING (121.46552 31.25006, 121.47078 31.2... |
可视化OD数据
[7]:
#Create figure
import matplotlib.pyplot as plt
fig =plt.figure(1,(8,8),dpi=300)
ax =plt.subplot(111)
plt.sca(ax)
#Load basemap
tbd.plot_map(plt,bounds,zoom = 11,style = 8)
#Create colorbar
cax = plt.axes([0.05, 0.33, 0.02, 0.3])
plt.title('Data count')
plt.sca(ax)
#Plot OD
od_gdf.plot(ax = ax,column = 'count',cmap = 'Blues_r',linewidth = 0.5,vmax = 10,cax = cax,legend = True)
#Plot compass and scale
tbd.plotscale(ax,bounds = bounds,textsize = 10,compasssize = 1,textcolor = 'white',accuracy = 2000,rect = [0.06,0.03],zorder = 10)
plt.axis('off')
plt.xlim(bounds[0],bounds[2])
plt.ylim(bounds[1],bounds[3])
plt.show()

创建网络
提取节点数据
将“LONCOL”和“LATCOL”列合并到一个字段中并提取节点集
[8]:
#Combine the ``LONCOL`` and ``LATCOL`` columns into one field
od_gdf['S'] = od_gdf['SLONCOL'].astype(str) + ',' + od_gdf['SLATCOL'].astype(str)
od_gdf['E'] = od_gdf['ELONCOL'].astype(str) + ',' + od_gdf['ELATCOL'].astype(str)
#extract node set
node = set(od_gdf['S'])|set(od_gdf['E'])
node = pd.DataFrame(node)
#reindex the node
node['id'] = range(len(node))
node
[8]:
0 | id | |
---|---|---|
0 | 164,81 | 0 |
1 | 71,125 | 1 |
2 | 102,118 | 2 |
3 | 125,115 | 3 |
4 | 143,76 | 4 |
... | ... | ... |
9806 | 98,167 | 9806 |
9807 | 46,130 | 9807 |
9808 | 118,82 | 9808 |
9809 | 158,57 | 9809 |
9810 | 104,169 | 9810 |
9811 rows × 2 columns
提取边数据
[9]:
#Merge the node information to the OD data to extract edge data.
node.columns = ['S','S_id']
od_gdf = pd.merge(od_gdf,node,on = ['S'])
node.columns = ['E','E_id']
od_gdf = pd.merge(od_gdf,node,on = ['E'])
#Extract edge data
edge = od_gdf[['S_id','E_id','count']]
edge
[9]:
S_id | E_id | count | |
---|---|---|---|
0 | 6251 | 4211 | 1 |
1 | 5879 | 8676 | 1 |
2 | 8432 | 8676 | 3 |
3 | 5511 | 8676 | 1 |
4 | 3386 | 8676 | 1 |
... | ... | ... | ... |
68468 | 5663 | 5835 | 2 |
68469 | 7738 | 4266 | 2 |
68470 | 360 | 8003 | 2 |
68471 | 6759 | 601 | 3 |
68472 | 6081 | 3107 | 3 |
68473 rows × 3 columns
创建网络
[10]:
import igraph
#Create Network
g = igraph.Graph()
#Add node
g.add_vertices(len(node))
#Add edge
g.add_edges(edge[['S_id','E_id']].values)
#Add weight
edge_weights = edge[['count']].values
for i in range(len(edge_weights)):
g.es[i]['weight'] = edge_weights[i]
社区检测
[11]:
#Community detection
g_clustered = g.community_multilevel(weights = edge_weights, return_levels=False)
[12]:
#Modularity
g_clustered.modularity
[12]:
0.8496074605497185
[13]:
#Assign the group result to the node
node['group'] = g_clustered.membership
#rename the columns
node.columns = ['grid','node_id','group']
node
[13]:
grid | node_id | group | |
---|---|---|---|
0 | 164,81 | 0 | 0 |
1 | 71,125 | 1 | 1 |
2 | 102,118 | 2 | 2 |
3 | 125,115 | 3 | 3 |
4 | 143,76 | 4 | 4 |
... | ... | ... | ... |
9806 | 98,167 | 9806 | 9 |
9807 | 46,130 | 9807 | 555 |
9808 | 118,82 | 9808 | 6 |
9809 | 158,57 | 9809 | 132 |
9810 | 104,169 | 9810 | 86 |
9811 rows × 3 columns
可视化社区
[14]:
#Count the number of grids per community
group = node['group'].value_counts()
#Extract communities with more than 10 grids
group = group[group>10]
#Retain only these community grids
node = node[node['group'].apply(lambda r:r in group.index)]
#Get the grid number
node['LONCOL'] = node['grid'].apply(lambda r:r.split(',')[0]).astype(int)
node['LATCOL'] = node['grid'].apply(lambda r:r.split(',')[1]).astype(int)
#Generate the geometry
node['geometry'] = tbd.gridid_to_polygon(node['LONCOL'],node['LATCOL'],params)
#Change it into GeoDataFrame
import geopandas as gpd
node = gpd.GeoDataFrame(node)
node
/var/folders/b0/q8rx9fj965b5p7yqq8zhvdx80000gn/T/ipykernel_30130/418053260.py:9: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
node['LONCOL'] = node['grid'].apply(lambda r:r.split(',')[0]).astype(int)
/var/folders/b0/q8rx9fj965b5p7yqq8zhvdx80000gn/T/ipykernel_30130/418053260.py:10: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
node['LATCOL'] = node['grid'].apply(lambda r:r.split(',')[1]).astype(int)
/var/folders/b0/q8rx9fj965b5p7yqq8zhvdx80000gn/T/ipykernel_30130/418053260.py:12: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
node['geometry'] = tbd.gridid_to_polygon(node['LONCOL'],node['LATCOL'],params)
[14]:
grid | node_id | group | LONCOL | LATCOL | geometry | |
---|---|---|---|---|---|---|
1 | 71,125 | 1 | 1 | 71 | 125 | POLYGON ((121.22089 31.22983, 121.22615 31.229... |
2 | 102,118 | 2 | 2 | 102 | 118 | POLYGON ((121.38398 31.19835, 121.38924 31.198... |
3 | 125,115 | 3 | 3 | 125 | 115 | POLYGON ((121.50498 31.18486, 121.51024 31.184... |
4 | 143,76 | 4 | 4 | 143 | 76 | POLYGON ((121.59967 31.00949, 121.60493 31.009... |
5 | 142,87 | 5 | 4 | 142 | 87 | POLYGON ((121.59441 31.05896, 121.59967 31.058... |
... | ... | ... | ... | ... | ... | ... |
9802 | 103,103 | 9802 | 8 | 103 | 103 | POLYGON ((121.38924 31.13090, 121.39450 31.130... |
9803 | 162,133 | 9803 | 28 | 162 | 133 | POLYGON ((121.69963 31.26580, 121.70489 31.265... |
9804 | 107,130 | 9804 | 41 | 107 | 130 | POLYGON ((121.41028 31.25231, 121.41554 31.252... |
9806 | 98,167 | 9806 | 9 | 98 | 167 | POLYGON ((121.36293 31.41868, 121.36819 31.418... |
9808 | 118,82 | 9808 | 6 | 118 | 82 | POLYGON ((121.46815 31.03647, 121.47341 31.036... |
8522 rows × 6 columns
[15]:
node.plot('group')
[15]:
<AxesSubplot:>

[16]:
#Use the group column to merge polygon
node_community = tbd.merge_polygon(node,'group')
#Input polygon GeoDataFrame data, take the exterior boundary of the polygon to form a new polygon
node_community = tbd.polyon_exterior(node_community,minarea = 0.000100)
/opt/anaconda3/envs/transbigdata/lib/python3.9/site-packages/transbigdata/gisprocess.py:205: ShapelyDeprecationWarning: Iteration over multi-part geometries is deprecated and will be removed in Shapely 2.0. Use the `geoms` property to access the constituent parts of a multi-part geometry.
for i in p:
[17]:
#Generate palette
import seaborn as sns
## l: Luminance
## s: Saturation
cmap = sns.hls_palette(n_colors=len(node_community), l=.7, s=0.8)
sns.palplot(cmap)

[19]:
#Create figure
import matplotlib.pyplot as plt
fig =plt.figure(1,(8,8),dpi=300)
ax =plt.subplot(111)
plt.sca(ax)
#Load basemap
tbd.plot_map(plt,bounds,zoom = 10,style = 6)
#Set colormap
from matplotlib.colors import ListedColormap
#Disrupting the order of the community
node_community = node_community.sample(frac=1)
#Plot community
node_community.plot(cmap = ListedColormap(cmap),ax = ax,edgecolor = '#333',alpha = 0.8)
#Add scale
tbd.plotscale(ax,bounds = bounds,textsize = 10,compasssize = 1,textcolor = 'k'
,accuracy = 2000,rect = [0.06,0.03],zorder = 10)
plt.axis('off')
plt.xlim(bounds[0],bounds[2])
plt.ylim(bounds[1],bounds[3])
plt.show()

9 公交 GPS 数据的到离站信息识别
要运行这个例子,你可能需要安装``seaborn``:
pip install seaborn
以下示例显示了如何使用 TransBigData 处理公交车 GPS 数据,包括识别公交车到达和离开信息、计算公交车的行驶时间和运行速度。
[1]:
import warnings
warnings.filterwarnings('ignore')
[2]:
import transbigdata as tbd
import pandas as pd
import geopandas as gpd
读取数据
读取公交车GPS数据
[3]:
BUS_GPS= pd.read_csv(r'data/busgps.csv',header = None)
BUS_GPS.columns = ['GPSDateTime', 'LineId', 'LineName', 'NextLevel', 'PrevLevel',
'Strlatlon', 'ToDir', 'VehicleId', 'VehicleNo', 'unknow']
#Convert the time column to datetime type
BUS_GPS['GPSDateTime'] = pd.to_datetime(BUS_GPS['GPSDateTime'])
转换坐标
[4]:
#Slice the latitude and longitude string
BUS_GPS['lon'] = BUS_GPS['Strlatlon'].apply(lambda r:r.split(',')[0])
BUS_GPS['lat'] = BUS_GPS['Strlatlon'].apply(lambda r:r.split(',')[1])
#Convert coordinates
BUS_GPS['lon'],BUS_GPS['lat'] = tbd.gcj02towgs84(BUS_GPS['lon'].astype(float),BUS_GPS['lat'].astype(float))
BUS_GPS.head(5)
[4]:
GPSDateTime | LineId | LineName | NextLevel | PrevLevel | Strlatlon | ToDir | VehicleId | VehicleNo | unknow | lon | lat | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2019-01-16 23:59:59 | 7100 | 71 | 2 | 1 | 121.335413,31.173188 | 1 | 沪D-R7103 | Z5A-0021 | 1 | 121.330858 | 31.175129 |
1 | 2019-01-17 00:00:00 | 7100 | 71 | 2 | 1 | 121.334616,31.172271 | 1 | 沪D-R1273 | Z5A-0002 | 1 | 121.330063 | 31.174214 |
2 | 2019-01-17 00:00:00 | 7100 | 71 | 24 | 23 | 121.339955,31.173025 | 0 | 沪D-R5257 | Z5A-0020 | 1 | 121.335390 | 31.174958 |
3 | 2019-01-17 00:00:01 | 7100 | 71 | 14 | 13 | 121.409491,31.20433 | 0 | 沪D-R5192 | Z5A-0013 | 1 | 121.404843 | 31.206179 |
4 | 2019-01-17 00:00:03 | 7100 | 71 | 15 | 14 | 121.398615,31.200253 | 0 | 沪D-T0951 | Z5A-0022 | 1 | 121.393966 | 31.202103 |
读取公交线路数据
[5]:
shp = r'data/busline.json'
linegdf = gpd.GeoDataFrame.from_file(shp,encoding = 'gbk')
line = linegdf.iloc[:1].copy()
line.plot()
[5]:
<AxesSubplot:>

读取公交站台数据
[6]:
shp = r'data/busstop.json'
stop = gpd.GeoDataFrame.from_file(shp,encoding = 'gbk')
stop = stop[stop['linename'] == '71路(延安东路外滩-申昆路枢纽站)']
stop.plot()
[6]:
<AxesSubplot:>

识别到达和离开信息
[7]:
arriveinfo = tbd.busgps_arriveinfo(BUS_GPS,line,stop)
Cleaning data...
Position matching......
Matching arrival and leaving info.........................................................................................................................................................
[8]:
arriveinfo
[8]:
arrivetime | leavetime | stopname | VehicleId | |
---|---|---|---|---|
0 | 2019-01-17 07:19:42 | 2019-01-17 07:31:14 | 延安东路外滩 | 1 |
1 | 2019-01-17 09:53:08 | 2019-01-17 10:09:34 | 延安东路外滩 | 1 |
0 | 2019-01-17 07:13:23 | 2019-01-17 07:15:45 | 西藏中路 | 1 |
1 | 2019-01-17 07:34:24 | 2019-01-17 07:35:38 | 西藏中路 | 1 |
2 | 2019-01-17 09:47:03 | 2019-01-17 09:50:22 | 西藏中路 | 1 |
... | ... | ... | ... | ... |
2 | 2019-01-17 16:35:52 | 2019-01-17 16:36:49 | 吴宝路 | 148 |
3 | 2019-01-17 19:21:09 | 2019-01-17 19:23:44 | 吴宝路 | 148 |
0 | 2019-01-17 13:36:26 | 2019-01-17 13:45:04 | 申昆路枢纽站 | 148 |
1 | 2019-01-17 15:52:26 | 2019-01-17 16:32:46 | 申昆路枢纽站 | 148 |
2 | 2019-01-17 19:24:54 | 2019-01-17 19:25:55 | 申昆路枢纽站 | 148 |
8984 rows × 4 columns
单程旅行时间
根据上面获得的“到达信息”计算单程旅行时间。给定公交线路的起点和终点站名称,“tbd.busgps_onewaytime”可以计算两个车站之间的行驶时间。
[9]:
onewaytime = tbd.busgps_onewaytime(arriveinfo,
start = '延安东路外滩',
end = '申昆路枢纽站',col = ['VehicleId','stopname', 'arrivetime', 'leavetime'])
[10]:
onewaytime
[10]:
time | stopname | VehicleId | time1 | stopname1 | VehicleId1 | duration | shour | direction | |
---|---|---|---|---|---|---|---|---|---|
0 | 2019-01-17 07:31:14 | 延安东路外滩 | 1 | 2019-01-17 08:24:42 | 申昆路枢纽站 | 1.0 | 3208.0 | 7 | 延安东路外滩-申昆路枢纽站 |
1 | 2019-01-17 10:09:34 | 延安东路外滩 | 1 | 2019-01-17 11:03:49 | 申昆路枢纽站 | 1.0 | 3255.0 | 10 | 延安东路外滩-申昆路枢纽站 |
0 | 2019-01-17 13:11:43 | 延安东路外滩 | 2 | 2019-01-17 14:05:17 | 申昆路枢纽站 | 2.0 | 3214.0 | 13 | 延安东路外滩-申昆路枢纽站 |
1 | 2019-01-17 15:42:28 | 延安东路外滩 | 2 | 2019-01-17 16:37:00 | 申昆路枢纽站 | 2.0 | 3272.0 | 15 | 延安东路外滩-申昆路枢纽站 |
0 | 2019-01-17 18:46:11 | 延安东路外滩 | 3 | 2019-01-17 19:51:54 | 申昆路枢纽站 | 3.0 | 3943.0 | 18 | 延安东路外滩-申昆路枢纽站 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1 | 2019-01-17 17:11:43 | 申昆路枢纽站 | 144 | 2019-01-17 18:13:22 | 延安东路外滩 | 144.0 | 3699.0 | 17 | 申昆路枢纽站-延安东路外滩 |
0 | 2019-01-17 08:15:44 | 申昆路枢纽站 | 147 | 2019-01-17 09:14:46 | 延安东路外滩 | 147.0 | 3542.0 | 8 | 申昆路枢纽站-延安东路外滩 |
1 | 2019-01-17 10:51:34 | 申昆路枢纽站 | 147 | 2019-01-17 11:50:03 | 延安东路外滩 | 147.0 | 3509.0 | 10 | 申昆路枢纽站-延安东路外滩 |
0 | 2019-01-17 13:45:04 | 申昆路枢纽站 | 148 | 2019-01-17 14:44:03 | 延安东路外滩 | 148.0 | 3539.0 | 13 | 申昆路枢纽站-延安东路外滩 |
1 | 2019-01-17 16:32:46 | 申昆路枢纽站 | 148 | 2019-01-17 17:31:34 | 延安东路外滩 | 148.0 | 3528.0 | 16 | 申昆路枢纽站-延安东路外滩 |
375 rows × 9 columns
为了显示数字的英文,这里我们将车站名称和方向名称更改为英文:
[11]:
onewaytime.loc[onewaytime['stopname']=='延安东路外滩','stopname']="Yanan road station"
onewaytime.loc[onewaytime['stopname1']=='申昆路枢纽站','stopname1']="Shenkun station"
onewaytime.loc[onewaytime['direction']=='延安东路外滩-申昆路枢纽站','direction']="Yanan road-Shenkun"
onewaytime.loc[onewaytime['direction']=='申昆路枢纽站-延安东路外滩','direction']="Shenkun-Yanan road"
[12]:
## Draw box plot for one-way travel time
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
fig = plt.figure(1,(8,4),dpi = 250)
ax1 = plt.subplot(111)
sns.boxplot(x = 'shour',y = onewaytime['duration']/60,hue = 'direction',data = onewaytime)
plt.ylabel('One-way travel time(minutes)')
plt.xlabel('Hour')
plt.ylim(0)
plt.show()

公交车的行驶速度
[13]:
#Convert coordinate system to projection coordinate system for later calculation of distance
line.crs = {'init':'epsg:4326'}
line_2416 = line.to_crs(epsg = 2416)
#Obtain the geometry inside the bus route data
lineshp = line_2416['geometry'].iloc[0]
linename = line_2416['name'].iloc[0]
lineshp
[13]:
[14]:
#Remove the data with abnormal speed
#Vehicle speed units converted to km/h
onewaytime['speed'] = (lineshp.length/onewaytime['duration'])*3.6
onewaytime = onewaytime[onewaytime['speed']<=60]
[15]:
## Travel speed distribution
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['font.serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus']=False
fig = plt.figure(1,(8,4),dpi = 250)
ax1 = plt.subplot(111)
sns.boxplot(x = 'shour',y = 'speed',hue = 'direction',data = onewaytime)
plt.ylabel('Operating speed(km/h)')
plt.xlabel('Hour')
plt.ylim(0)
plt.show()

10 出租车GPS轨迹数据的地图匹配
本示例使用TransBigData+leuvenmapmatching实现出租车GPS数据的道路网络匹配
准备轨迹数据
[1]:
import transbigdata as tbd
import pandas as pd
#Read_data
data = pd.read_csv('data/TaxiData-Sample.csv',header = None)
data.columns = ['VehicleNum','Time','Lng','Lat','OpenStatus','Speed']
[2]:
from leuvenmapmatching.matcher.distance import DistanceMatcher
from leuvenmapmatching.map.inmem import InMemMap
from leuvenmapmatching import visualization as mmviz
[3]:
#obtain OD from trajectory data
oddata = tbd.taxigps_to_od(data,col = ['VehicleNum','Time','Lng','Lat','OpenStatus'])
#extract deliver and idle trip trajectories
data_deliver,data_idle = tbd.taxigps_traj_point(data,oddata,col=['VehicleNum', 'Time', 'Lng', 'Lat', 'OpenStatus'])
建模路网
可以从openstreetmap下载路网。
[4]:
# obtain road network
import osmnx as ox
bounds = [113.75, 22.4, 114.62, 22.86]
north, south, east, west = bounds[3], bounds[1], bounds[2], bounds[0]
G = ox.graph_from_bbox(north, south, east, west, network_type='drive')
[5]:
#save road network
ox.save_graphml(G,'shenzhen.graphml')
如果你已经有路网数据…
[6]:
# Read the road network
import osmnx as ox
filepath = "shenzhen.graphml"
G = ox.load_graphml(filepath)
[7]:
#Obtain the road GeoDataFrame and road centroid
nodes, edges = ox.graph_to_gdfs(G, nodes=True, edges=True)
edges['lon'] = edges.centroid.x
edges['lat'] = edges.centroid.y
/var/folders/b0/q8rx9fj965b5p7yqq8zhvdx80000gn/T/ipykernel_80320/1542180003.py:3: UserWarning: Geometry is in a geographic CRS. Results from 'centroid' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.
edges['lon'] = edges.centroid.x
/var/folders/b0/q8rx9fj965b5p7yqq8zhvdx80000gn/T/ipykernel_80320/1542180003.py:4: UserWarning: Geometry is in a geographic CRS. Results from 'centroid' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.
edges['lat'] = edges.centroid.y
[8]:
#convert to projection coordinates
G_p = ox.project_graph(G, to_crs=2416)
nodes_p, edges_p = ox.graph_to_gdfs(G_p, nodes=True, edges=True)
[9]:
edges_p.plot()
[9]:
<AxesSubplot:>

[11]:
# create road network
map_con = InMemMap(name='pNEUMA', use_latlon=False) # , use_rtree=True, index_edges=True)
for node_id, row in nodes_p.iterrows():
map_con.add_node(node_id, (row['y'], row['x']))
for node_id_1, node_id_2, _ in G_p.edges:
map_con.add_edge(node_id_1, node_id_2)
地图匹配
[12]:
# Extract one of the trajectory using transbigdata
import geopandas as gpd
tmp_gdf = data_deliver[data_deliver['ID'] == 27].sort_values(by='Time')
# trajectory densify
tmp_gdf = tbd.traj_densify(
tmp_gdf, col=['ID', 'Time', 'Lng', 'Lat'], timegap=15)
# convert coordinate
tmp_gdf['geometry'] = gpd.points_from_xy(tmp_gdf['Lng'], tmp_gdf['Lat'])
tmp_gdf = gpd.GeoDataFrame(tmp_gdf)
tmp_gdf.crs = {'init': 'epsg:4326'}
tmp_gdf = tmp_gdf.to_crs(2416)
# obtain trajectoies
path = list(zip(tmp_gdf.geometry.y, tmp_gdf.geometry.x))
# create mapmatcher
matcher = DistanceMatcher(map_con,
max_dist=500,
max_dist_init=170,
min_prob_norm=0.0001,
non_emitting_length_factor=0.95,
obs_noise=50,
obs_noise_ne=50,
dist_noise=50,
max_lattice_width=20,
non_emitting_states=True)
# mapmatching
states, _ = matcher.match(path, unique=False)
# plot the result
mmviz.plot_map(map_con, matcher=matcher,
show_labels=False, show_matching=True, # show_graph=True,
filename=None)
/opt/anaconda3/lib/python3.8/site-packages/pyproj/crs/crs.py:131: FutureWarning: '+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6
in_crs_string = _prepare_from_proj_string(in_crs_string)
Searching closeby nodes with linear search, use an index and set max_dist
/opt/anaconda3/lib/python3.8/site-packages/leuvenmapmatching/visualization.py:194: UserWarning: linestyle is redundantly defined by the 'linestyle' keyword argument and the fmt string "o-" (-> linestyle='-'). The keyword argument will take precedence.
ax.plot(px, py, 'o-', linewidth=linewidth, markersize=linewidth * 2, alpha=0.75,
[12]:
(<Figure size 1440x846.228 with 1 Axes>, <AxesSubplot:xlabel='X', ylabel='Y'>)

[14]:
#Obtain the path GeoDataFrame
pathdf = pd.DataFrame(matcher.path_pred_onlynodes,columns = ['u'])
pathdf['v'] = pathdf['u'].shift(-1)
pathdf = pathdf[-pathdf['v'].isnull()]
pathgdf = pd.merge(pathdf,edges_p.reset_index())
pathgdf = gpd.GeoDataFrame(pathgdf)
pathgdf.plot()
pathgdf.crs = {'init':'epsg:2416'}
pathgdf_4326 = pathgdf.to_crs(4326)
/opt/anaconda3/lib/python3.8/site-packages/pyproj/crs/crs.py:131: FutureWarning: '+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6
in_crs_string = _prepare_from_proj_string(in_crs_string)

可视化
[15]:
#Visualize with road network
import matplotlib.pyplot as plt
fig = plt.figure(1,(8,8),dpi = 100)
ax = plt.subplot(111)
plt.sca(ax)
fig.tight_layout(rect = (0.05,0.1,1,0.9))
#visualization bounds
bounds = pathgdf_4326.unary_union.bounds
gap = 0.003
bounds = [bounds[0]-gap,bounds[1]-gap,bounds[2]+gap,bounds[3]+gap]
#plot the matched path
pathgdf_4326.plot(ax = ax,zorder = 1)
#plot the road network geometry
tbd.clean_outofbounds(edges,bounds,col = ['lon','lat']).plot(ax = ax,color = '#333',lw = 0.1)
#plot the trajectory points
tmp_gdf.to_crs(4326).plot(ax = ax,color = 'r',markersize = 5,zorder = 2)
plt.axis('off')
plt.xlim(bounds[0],bounds[2])
plt.ylim(bounds[1],bounds[3])
plt.show()

核心方法
数据栅格化
|
在边界或形状中生成矩形栅格 |
|
生成栅格化参数 |
|
将 GPS 数据与栅格匹配。 |
|
栅格的中心位置。 |
|
根据栅格ID生成几何列。 |
|
输入格网 ID 两列、地理面和格网参数。 |
|
从栅格重新生成栅格化参数。 |
|
优化栅格参数 |
|
输入经纬度和精度,编码geohash码 |
|
解码geohash码 |
|
输入geohash码生成geohash栅格单元格 |
栅格化框架

- transbigdata.area_to_grid(location, accuracy=500, method='rect', params='auto')
在边界或形状中生成矩形栅格
- 参数:
location (bounds(List) or shape(GeoDataFrame)) – 生成栅格的位置。如果边界为 [lon1, lat1, lon2, lat2](WGS84),其中 lon1 , lat1 是左下角坐标,lon2 , lat2 是右上角坐标 如果是形状,则应为 GeoDataFrame
accuracy (number) – 栅格尺寸(米)
method (str) – 直角、三角或六角
params (list or dict) – 栅格化参数。有关栅格化参数的详细信息,请参阅 https://transbigdata.readthedocs.io/en/latest/grids.html。给出格网参数时,将不使用精度。
- 返回:
grid (GeoDataFrame) – Grid GeoDataFrame、LONCOL 和 LATCOL 是栅格的索引,HBLON 和 HBLAT 是栅格的中心
参数 (列表或字典) – 栅格参数。有关栅格化参数的详细信息,请参阅 https://transbigdata.readthedocs.io/en/latest/grids.html。
- transbigdata.area_to_params(location, accuracy=500, method='rect')
生成栅格化参数
- 参数:
location (bounds(List) or shape(GeoDataFrame)) – 生成栅格的位置。如果边界为 [lon1, lat1, lon2, lat2](WGS84),其中 lon1 , lat1 是左下角坐标,lon2 , lat2 是右上角坐标 如果是形状,则应为 GeoDataFrame
accuracy (number) – 栅格尺寸(米)
method (str) – 直角、三角或六角
- 返回:
参数 – 栅格参数。有关栅格化参数的详细信息,请参阅 https://transbigdata.readthedocs.io/en/latest/grids.html。
- 返回类型:
list or dict
- transbigdata.GPS_to_grid(lon, lat, params)
将 GPS 数据与栅格匹配。输入是经度、纬度和格网参数列。输出是栅格 ID。
- 参数:
lon (Series) – 经度栏
lat (Series) – 纬度栏
params (list or dict) – 栅格化参数。有关栅格化参数的详细信息,请参阅 https://transbigdata.readthedocs.io/en/latest/grids.html。
- 返回:
矩形栅格
[LONCOL,LATCOL] (list) – 两列 LONCOL 和 LATCOL 一起可以指定栅格。
三角形和六边形栅格
[loncol_1,loncol_2,loncol_3] (list) – 栅格纬度的索引。两列 LONCOL 和 LATCOL 一起可以指定一个栅格。
- transbigdata.grid_to_centre(gridid, params)
栅格的中心位置。输入是格网ID和参数,输出是格网中心位置。
- 参数:
gridid (list) – 如果“矩形栅格”[LONCOL,LATCOL]:系列 两列 LONCOL 和 LATCOL 一起可以指定栅格。 如果“三角形和六边形栅格” [loncol_1,loncol_2,loncol_3] :系列 栅格纬度的索引。两列 LONCOL 和 LATCOL 一起可以指定一个栅格。
params (list or dict) – 栅格化参数。有关栅格化参数的详细信息,请参阅 https://transbigdata.readthedocs.io/en/latest/grids.html。
- 返回:
HBLON (Series) – 栅格中心的经度
HBLAT (Series) – 栅格中心的纬度
- transbigdata.grid_to_polygon(gridid, params)
基于格网 ID 生成几何列。输入是栅格 ID,输出是几何图形。支持矩形、三角形和六边形栅格
- 参数:
gridid (list) – 如果“矩形栅格”[LONCOL,LATCOL]:系列 两列 LONCOL 和 LATCOL 一起可以指定栅格。 如果“三角形和六边形栅格” [loncol_1,loncol_2,loncol_3] :系列 栅格纬度的索引。两列 LONCOL 和 LATCOL 一起可以指定一个栅格。
params (list or dict) – 栅格化参数。有关栅格化参数的详细信息,请参阅 https://transbigdata.readthedocs.io/en/latest/grids.html。
- 返回:
geometry – 栅格地理多边形的列
- 返回类型:
Series
- transbigdata.grid_to_area(data, shape, params, col=['LONCOL', 'LATCOL'])
输入格网 ID 两列、地理面和格网参数。输出是栅格。
- 参数:
data (DataFrame) – 数据,有两列栅格ID
shape (GeoDataFrame) – 地理多边形
params (list or dict) – 栅格化参数。有关栅格化参数的详细信息,请参阅 https://transbigdata.readthedocs.io/en/latest/grids.html。
col (List) – 列名称 [LONCOL,LATCOL] 用于矩形栅格,或 [loncol_1,loncol_2,loncol_3] 表示三和六栅格
- 返回:
data1 – 数据栅格化和映射到相应的地理多边形
- 返回类型:
DataFrame
- transbigdata.grid_to_params(grid)
从栅格重新生成栅格化参数。
- 参数:
grid (GeoDataFrame) – transbigdata生成的栅格
- 返回:
参数 – 栅格参数。有关栅格化参数的详细信息,请参阅 https://transbigdata.readthedocs.io/en/latest/grids.html。
- 返回类型:
list or dict
- transbigdata.grid_params_optimize(data, initialparams, col=['uid', 'lon', 'lat'], optmethod='centerdist', printlog=False, sample=0, pop=15, max_iter=50, w=0.1, c1=0.5, c2=0.5)
优化栅格参数
- 参数:
data (DataFrame) – 轨迹数据
initialparams (List) – 初始栅格参数
col (List) – 列名[uid,lon,lat]
optmethod (str) – 优化方法:centerdist, gini, gridscount
printlog (bool) – 是否打印明细结果
sample (int) – 采样数据作为输入,为0则不采样
pop – 来自 scikit-opt 的 PSO 中的参数
max_iter – 来自 scikit-opt 的 PSO 中的参数
w – 来自 scikit-opt 的 PSO 中的参数
c1 – 来自 scikit-opt 的 PSO 中的参数
c2 – 来自 scikit-opt 的 PSO 中的参数
- 返回:
params_optimized – 优化的参数
- 返回类型:
List
geohash编码
Geohash 是一种公共地理编码系统,可将纬度和经度地理位置编码为字母和数字字符串,这些字符串也可以解码回纬度和经度。每个字符串代表一个栅格编号,字符串的长度越长,精度越高。根据wiki<https://en.wikipedia.org/wiki/Geohash>,与精度对应的Geohash字符串长度表如下。
geohash 长度(精度) |
纬度位 |
lng位 |
纬度错误 |
lng 错误 |
公里错误 |
---|---|---|---|---|---|
1 |
2 |
3 |
±23 |
±23 |
±2500 |
2 |
5 |
5 |
±2.8 |
±5.6 |
±630 |
3 |
7 |
8 |
±0.70 |
±0.70 |
±78 |
4 |
10 |
10 |
±0.087 |
±0.18 |
±20 |
5 |
12 |
13 |
±0.022 |
±0.022 |
±2.4 |
6 |
15 |
15 |
±0.0027 |
±0.0055 |
±0.61 |
7 |
17 |
18 |
±0.00068 |
±0.00068 |
±0.076 |
8 |
20 |
20 |
±0.000085 |
±0.00017 |
±0.019 |
TransBigData还提供了基于Geohash的功能,三个功能如下:
- transbigdata.geohash_encode(lon, lat, precision=12)
输入经纬度和精度,编码geohash码
- 参数:
lon (Series) – 经度系列
lat (Series) – 纬度系列
precision (number) – geohash精度
- 返回:
geohash – 编码的geohash系列
- 返回类型:
Series
- transbigdata.geohash_decode(geohash)
解码geohash码
- 参数:
geohash (Series) – encoded geohash 系列
- 返回:
lon (Series) – 解码后的经度系列
lat (Series) – 解码后的纬度系列
- transbigdata.geohash_togrid(geohash)
输入geohash码生成geohash栅格单元格
- 参数:
geohash (Series) – encoded geohash 系列
- 返回:
poly – geohash 的栅格单元多边形
- 返回类型:
Series
与TransBigData软件包中提供的矩形网格处理方法相比,geohash速度较慢,并且不提供自由定义的网格大小。以下示例演示如何使用这三个函数来利用 geohash 编码、解码和可视化
import transbigdata as tbd
import pandas as pd
import geopandas as gpd
#read data
data = pd.read_csv('TaxiData-Sample.csv',header = None)
data.columns = ['VehicleNum','time','slon','slat','OpenStatus','Speed']
#encode geohash
data['geohash'] = tbd.geohash_encode(data['slon'],data['slat'],precision=6)
data['geohash']
0 ws0btw
1 ws0btz
2 ws0btz
3 ws0btz
4 ws0by4
...
544994 ws131q
544995 ws1313
544996 ws131f
544997 ws1361
544998 ws10tq
Name: geohash, Length: 544999, dtype: object
#Aggregate
dataagg = data.groupby(['geohash'])['VehicleNum'].count().reset_index()
dataagg['lon_geohash'],dataagg['lat_geohash'] = tbd.geohash_decode(dataagg['geohash'])
dataagg['geometry'] = tbd.geohash_togrid(dataagg['geohash'])
dataagg = gpd.GeoDataFrame(dataagg)
dataagg
geohash | VehicleNum | lon_geohash | lat_geohash | geometry | |
---|---|---|---|---|---|
0 | w3uf3x | 1 | 108. | 10.28 | POLYGON ((107.99561 10.27771, 107.99561 10.283... |
1 | webzz6 | 12 | 113.9 | 22.47 | POLYGON ((113.87329 22.46704, 113.87329 22.472... |
2 | webzz7 | 21 | 113.9 | 22.48 | POLYGON ((113.87329 22.47253, 113.87329 22.478... |
3 | webzzd | 1 | 113.9 | 22.47 | POLYGON ((113.88428 22.46704, 113.88428 22.472... |
4 | webzzf | 2 | 113.9 | 22.47 | POLYGON ((113.89526 22.46704, 113.89526 22.472... |
... | ... | ... | ... | ... | ... |
2022 | ws1d9u | 1 | 114.7 | 22.96 | POLYGON ((114.68628 22.96143, 114.68628 22.966... |
2023 | ws1ddh | 6 | 114.7 | 22.96 | POLYGON ((114.69727 22.96143, 114.69727 22.966... |
2024 | ws1ddj | 2 | 114.7 | 22.97 | POLYGON ((114.69727 22.96692, 114.69727 22.972... |
2025 | ws1ddm | 4 | 114.7 | 22.97 | POLYGON ((114.70825 22.96692, 114.70825 22.972... |
2026 | ws1ddq | 7 | 114.7 | 22.98 | POLYGON ((114.70825 22.97241, 114.70825 22.977... |
2027 rows × 5 columns
bounds = [113.6,22.4,114.8,22.9]
import matplotlib.pyplot as plt
import plot_map
fig =plt.figure(1,(8,8),dpi=280)
ax =plt.subplot(111)
plt.sca(ax)
tbd.plot_map(plt,bounds,zoom = 12,style = 4)
cax = plt.axes([0.05, 0.33, 0.02, 0.3])
plt.title('count')
plt.sca(ax)
dataagg.plot(ax = ax,column = 'VehicleNum',cax = cax,legend = True)
tbd.plotscale(ax,bounds = bounds,textsize = 10,compasssize = 1,accuracy = 2000,rect = [0.06,0.03],zorder = 10)
plt.axis('off')
plt.xlim(bounds[0],bounds[2])
plt.ylim(bounds[1],bounds[3])
plt.show()

轨迹处理
|
删除轨迹数据中的漂移。 |
|
删除与前后数据信息相同的数据,以减少数据量。 |
|
根据切片数据对轨迹数据进行切片。 |
|
使用卡尔曼滤波器的平滑轨迹。 |
|
按顺序分割轨迹,返回每段的起点和终点信息。 |
|
轨迹致密化,保证每个时间间隔秒都有一个轨迹点 |
|
轨迹稀疏化。 |
|
输入轨迹数据和栅格化参数,识别停留和移动 |
|
输入轨迹,生成GeoDataFrame |
|
最近地图匹配:查找道路网络上每个轨迹点的最近点。 |
|
计算轨迹长度。 |

- transbigdata.traj_clean_drift(data, col=['VehicleNum', 'Time', 'Lng', 'Lat'], method='twoside', speedlimit=80, dislimit=1000, anglelimit=30)
删除轨迹数据中的漂移。漂移定义为速度大于速度限制或当前点与下一个点之间的距离大于距离限制或当前点与前一点和下一个点之间的角度小于角度限制的数据。限速默认为80km/h,距离限制默认为1000m。清理漂移数据的方法分为两种方法:“单侧”和“双侧”。“单面”法是考虑当前点和下一个点的速度,“双边”法是考虑当前点、前一点和下一个点的速度。
- 参数:
data (DataFrame) – 数据
col (List) – 列名,顺序为[‘VehicleNum’, ‘Time’, ‘Lng’, ‘Lat’]
method (string) – 清洗漂移数据的方法,包括‘oneside’和‘twoside’
speedlimit (number) – 限速
dislimit (number) – 距离限制
anglelimit (number) – 角度限制
- 返回:
data1 – 清理后的数据
- 返回类型:
DataFrame
- transbigdata.traj_clean_redundant(data, col=['VehicleNum', 'Time', 'Lng', 'Lat'])
删除与前后数据信息相同的数据,以减少数据量。例如,如果一个人的几个连续数据具有相同的信息,除了时间,则只能保留第一个和最后两个数据
- 参数:
data (DataFrame) – 数据
col (List) – 列名称,按 [‘车辆 ID, 时间’] 的顺序排列。它会按时间排序,然后确定时间以外的其他列的信息
- 返回:
data1 – 清理后的数据
- 返回类型:
DataFrame
- transbigdata.traj_slice(traj_data, slice_data, traj_col=['vid', 'time'], slice_col=['vid', 'stime', 'etime', 'tripid'])
根据切片数据对轨迹数据进行切片。该方法根据指定的时间段(slice_data)从一组给定的轨迹数据(traj_data)中提取数据。
- 参数:
traj_data (DataFrame) – 轨迹数据,包含每辆车的轨迹
slice_data (DataFrame) – 切片数据,包含每个切片的开始时间、结束时间和车辆ID
traj_col (List) – 轨迹数据的列名,顺序为[VehicleNum,Time]
slice_col (List) – 切片数据的列名,按 [VehicleNum_slice、Stime、Etime、SliceId] 的顺序排列
- 返回:
data_sliced – 切片轨迹数据
- 返回类型:
DataFrame
示例
>>> tbd.traj_slice(GPSData, move, traj_col=['vid', 'time'], slice_col = ['vid','stime','etime','tripid'])
- transbigdata.traj_smooth(data, col=['id', 'time', 'lon', 'lat'], proj=False, process_noise_std=0.5, measurement_noise_std=1)
使用卡尔曼滤波器的平滑轨迹。
- 参数:
data (DataFrame) – 轨迹数据
col (list) – 轨迹数据的列名
proj (bool) – 是否进行等距投影
process_noise_std (float) – 过程噪声的标准偏差
measurement_noise_std (float) – 测量噪声的标准偏差
- 返回:
data – 平滑轨迹数据
- 返回类型:
DataFrame
- transbigdata.traj_segment(data, groupby_col=['id', 'moveid'], retain_col=['time', 'lon', 'lat'])
按顺序分割轨迹,返回每段的起点和终点信息。该功能可以分割GPS轨迹数据,计算每个线段的起点和终点信息,并将结果存储在DataFrame对象中。此函数的输入包括一个 pandas 数据帧对象,其中包含 GPS 轨迹数据、用于分组的字段名称和要保留的字段名称。输出是一个 pandas DataFrame 对象,其中包含每个线段的开始和结束信息,其中每行表示一个轨迹段。
- 参数:
data (DataFrame) – 轨迹数据需要预先排序。
groupby_col (List) – 指定要用于分段的分组依据字段的字符串列表。
retain_col (List) – 指定要保留的字段的字符串列表。
- 返回:
data – 包含每个线段的开始和结束信息,其中每行表示一个轨迹段。
- 返回类型:
DataFrame
- transbigdata.traj_densify(data, col=['Vehicleid', 'Time', 'Lng', 'Lat'], timegap=15)
轨迹致密化,保证每个时间间隔秒都有一个轨迹点
- 参数:
data (DataFrame) – 数据
col (List) – 列名,顺序为[Vehicleid, Time, lng, lat]
timegap (number) – 采样间隔(秒)
- 返回:
data1 – 处理后的数据
- 返回类型:
DataFrame
- transbigdata.traj_sparsify(data, col=['Vehicleid', 'Time', 'Lng', 'Lat'], timegap=15, method='subsample')
轨迹稀疏。当轨迹数据的采样频率过高时,数据量太大,这对于一些需要较少数据频率的研究进行分析是不方便的。此功能可以扩展采样间隔并减少数据量。
- 参数:
data (DataFrame) – 数据
col (List) – 列名,顺序为[Vehicleid, Time, lng, lat]
timegap (number) – 轨迹点之间的时间间隔
method (str) – ‘插值’或’子样本’
- 返回:
data1 – 稀疏轨迹数据
- 返回类型:
DataFrame
- transbigdata.traj_stay_move(data, params, col=['ID', 'dataTime', 'longitude', 'latitude'], activitytime=1800)
输入轨迹数据和栅格化参数,识别停留和移动
- 参数:
data (DataFrame) – 轨迹数据
params (List) – 栅格化参数
col (List) – 列名,顺序为[‘ID’,’dataTime’,’longitude’,’latitude’]
activitytime (Number) – 多少时间算活动
- 返回:
stay (DataFrame) – 停留信息
move (DataFrame) – 移动信息
- transbigdata.traj_to_linestring(traj_points, col=['Lng', 'Lat', 'ID'], timecol=None)
输入轨迹,生成GeoDataFrame
- 参数:
traj_points (DataFrame) – 轨迹数据
col (List) – 列名,顺序为[lng,lat,trajectoryid]
timecol (str(Optional)) – 可选,时间列的列名。如果给定,可以将返回的带有[经度,纬度,高度,时间]的geojson放入开普勒中以可视化轨迹
- 返回:
traj – 生成的轨迹
- 返回类型:
GeoDataFrame
- transbigdata.traj_mapmatch(traj, G, col=['lon', 'lat'])
最近地图匹配:查找道路网络上每个轨迹点的最近点。在进行最近邻匹配时,我们需要找到路网中每个轨迹点最近的路段,并将轨迹点与该路段进行匹配。在实践中,我们可以先提取路段的节点形成一组点(即从几何列中的每个 LineString 中提取每个坐标点),然后计算轨迹点与这组点之间的最近距离,最后将轨迹点与最近距离节点所在的路段匹配。这个过程有效地将点与线的匹配问题转化为点与点的匹配问题。
- 参数:
traj (DataFrame) – 待匹配的轨迹点数据集。
G (networkx multidigraph) – 用于匹配的路网,由osmnx创建。
col (list) – 轨迹点数据集中经度和纬度列的名称。
- 返回:
traj_matched – 匹配后的轨迹点数据集。
- 返回类型:
DataFrame
- transbigdata.traj_length(move_points, col=['lon', 'lat', 'moveid'], method='Haversine')
计算轨迹长度。输入轨迹点数据并计算每个轨迹的长度(以米为单位)。
- 参数:
move_points (DataFrame) – 轨迹点数据,包括轨迹ID、经度、纬度等。通过轨迹 id 区分不同的轨迹,轨迹点按时间顺序排列。
col (list) – Column names of the trajectory point data, in the order of [longitude, latitude, trajectory id]
method (str) – 计算轨迹长度的方法,可选“Haversine”或“Project”,默认为“Haversine”,使用球面三角公式计算距离,“Project”将数据转换为投影坐标系以计算平面距离。
- 返回:
move_trajs – 轨迹长度数据,包括轨迹 id 和轨迹长度两列,单位为米。
- 返回类型:
DataFrame
基础处理方法
数据质量分析
|
输出数据集的一般信息。 |
|
计算数据采样间隔。 |
- transbigdata.data_summary(data, col=['Vehicleid', 'Time'], show_sample_duration=False, roundnum=4)
输出数据集的一般信息。
- 参数:
data (DataFrame) – 轨迹点数据
col (List) – 列名,顺序为[‘Vehicleid’, ‘Time’]
show_sample_duration (bool) – 是否输出个别采样间隔
roundnum (number) – 小数位数
- transbigdata.sample_duration(data, col=['Vehicleid', 'Time'])
计算数据采样间隔。
- 参数:
data (DataFrame) – 数据
col (List) – 列名,顺序为[‘Vehicleid’, ‘Time’]
- 返回:
sample_duration – 列名持续时间的序列,内容是数据的采样间隔,以秒为单位
- 返回类型:
DataFrame
数据预处理
|
输入为研究区域左下角和右上角的纬度和经度坐标,并排除研究区域外的数据 |
|
输入研究区域的地理数据框并排除研究区域以外的数据 |
|
重新编号数据的ID列 |
|
对数据的ID列重新编号,如果相邻两条记录超过距离,则编号为新ID |
- transbigdata.clean_outofbounds(data, bounds, col=['Lng', 'Lat'])
输入为研究区域左下角和右上角的纬度和经度坐标,并排除研究区域外的数据
- 参数:
data (DataFrame) – 数据
bounds (List) – 研究区域左下角和右上角的纬度和经度,顺序为 [lon1, lat1, lon2, lat2]
col (List) – 经纬度列名
- 返回:
data1 – 研究范围内的数据
- 返回类型:
DataFrame
- transbigdata.clean_outofshape(data, shape, col=['Lng', 'Lat'], accuracy=500)
输入研究区域的地理数据框并排除研究区域以外的数据
- 参数:
data (DataFrame) – 数据
shape (GeoDataFrame) – 研究区的GeoDataFrame
col (List) – 经纬度列名
accuracy (number) – 栅格的大小。原理是先做数据栅格化,然后再做数据清理。尺寸越小,精度越高
- 返回:
data1 – 研究范围内的数据
- 返回类型:
DataFrame
- transbigdata.id_reindex(data, col, new=False, timegap=None, timecol=None, suffix='_new', sample=None)
重新编号数据的ID列
- 参数:
data (DataFrame) – 数据
col (str) – 要重新索引的ID列的名称
new (bool) – False:相同 ID 的新编号将是相同的索引;True:根据表的顺序,源 ID 再次出现,索引不同
timegap (number) – 如果某个个体在一段时间内没有出现(时间间隔是时间阈值),则将其编号为新个体。此参数应与 timecol 一起设置才能生效。
timecol (str) – time的列名,需要设置timegap才能生效
suffix (str) – 新列的后缀。设置为 False 时,将替换前一列
sample (int (optional)) – 对数据进行去采样
- 返回:
data1 – 重新编号的数据
- 返回类型:
DataFrame
- transbigdata.id_reindex_disgap(data, col=['uid', 'lon', 'lat'], disgap=1000, suffix='_new')
对数据的ID列重新编号,如果相邻两条记录超过距离,则编号为新ID
- 参数:
data (DataFrame) – 数据
col (str) – 要重新索引的ID列的名称
disgap (number) – 如果相邻的两条记录超过这个距离,这个数字就是新的ID
suffix (str) – 新列的后缀。设置为 False 时,将替换前一列
- 返回:
data1 – 重新编号的数据
- 返回类型:
DataFrame
数据采集
|
从地图服务获取公交站和公交线路的地理信息(仅限中国) |
|
输入关键字和高德地图ak。 |
|
从高德地图获取等时线reachcricle |
|
从mapbox等时线获取等时线 |
- transbigdata.getbusdata(city, keywords, accurate=True, timeout=20)
从地图服务获取公交站和公交线路的地理信息(仅限中国)
- 参数:
city (str) – 城市名称
keywords (list) – 关键字,行名
accurate (bool) – 精准匹配
timeout (number) – 取数据超时
- 返回:
data (GeoDataFrame) – 生成的总线(WGS84)
stop (GeoDataFrame) – 生成的公交车站(WGS84)
- transbigdata.getadmin(keyword, ak, jscode='', subdistricts=False, timeout=20)
输入关键字和 Amap ak。输出为行政边界的GIS文件(仅限中国)
- 参数:
keywords (str) – 关键字。它可能是城市名称(如深圳),也可能是行政代码(如 440500)
ak (str) – 地图访问令牌
jscode (jscode) – 高德安全码
subdistricts (bool) – 是否输出行政区界线信息
timeout (number) – 取数据超时
- 返回:
admin (GeoDataFrame) – 行政区划(WGS84)
区 (数据帧) – 子区的信息。这可用于进一步获取较低级别区域的边界
- transbigdata.get_isochrone_amap(lon, lat, reachtime, ak, jscode='', mode=2, timeout=20)
从高德地图获取等时线reachcricle
- 参数:
lon (float) – 起点经度(WGS84)
lat (float) – 起点纬度(WGS84)
reachtime (number) – 等时线到达时间
ak (str) – 高德地图访问令牌
jscode (jscode) – 高德安全码
mode (int or str) – 出行方式,应为0(公交)、1(地铁)、2(公交地铁)
timeout (number) – 取数据超时
- 返回:
isochrone – 等时线GeoDataFrame(WGS84)
- 返回类型:
GeoDataFrame
- transbigdata.get_isochrone_mapbox(lon, lat, reachtime, access_token='auto', mode='driving', timeout=20)
从mapbox等时线获取等时线
- 参数:
lon (float) – 起点经度(WGS84)
lat (float) – 起点纬度(WGS84)
reachtime (number) – 等时线到达时间
access_token (str) – Mapbox access token,如果是`auto`它将使用预设的access token
mode (bool) – 出行方式,应该是`driving`, walking or cycling
timeout (number) – 取数据超时
- 返回:
isochrone – 等时线GeoDataFrame(WGS84)
- 返回类型:
GeoDataFrame
GIS处理
|
在dfB_origin中搜索最近的点以查找dfA_origin,并计算距离 |
|
此方法会将 gdfB 中最近的点与 gdfA 匹配,并添加一个名为 dist 的新列 |
|
此方法将从 gdfB 进行搜索,以找到离 gdfA 中点最近的线。 |
|
输入是线的GeoDataFrame。 |
|
输入的是多边形几何的GeoDataFrame,col名。 |
|
输入是多边形几何的GeoDataFrame。 |
近邻配料
- transbigdata.ckdnearest(dfA_origin, dfB_origin, Aname=['lon', 'lat'], Bname=['lon', 'lat'])
在dfB_origin中搜索最近的点以查找dfA_origin,并计算距离
- 参数:
dfA_origin (DataFrame) – 数据帧A
dfB_origin (DataFrame) – 数据帧B
Aname (List) – DataFrame A中lng和lat的列
Bname (List) – DataFrame A中lng和lat的列
- 返回:
gdf – 输出数据帧
- 返回类型:
DataFrame
- transbigdata.ckdnearest_point(gdA, gdB)
此方法会将 gdfB 中最近的点与 gdfA 匹配,并添加一个名为 dist 的新列
- 参数:
gdA (GeoDataFrame) – GeoDataFrame A,点几何
gdB (GeoDataFrame) – GeoDataFrame B,点几何
- 返回:
gdf – 输出数据帧
- 返回类型:
DataFrame
- transbigdata.ckdnearest_line(gdfA, gdfB)
此方法将从 gdfB 进行搜索,以找到离 gdfA 中点最近的线。
- 参数:
gdA (GeoDataFrame) – GeoDataFrame A,点几何
gdB (GeoDataFrame) – GeoDataFrame B,线串几何
- 返回:
gdf – 在 gdfB 中的近线串中搜索 gdfA 中的点
- 返回类型:
DataFrame
点对点匹配(DataFrame与DataFrame)
In [1]: import transbigdata as tbd
In [2]: import pandas as pd
In [3]: import geopandas as gpd
In [4]: from shapely.geometry import LineString
In [5]: dfA = gpd.GeoDataFrame([[1,2],[2,4],[2,6],
...: [2,10],[24,6],[21,6],
...: [22,6]],columns = ['lon1','lat1'])
...:
In [6]: dfA
Out[6]:
lon1 lat1
0 1 2
1 2 4
2 2 6
3 2 10
4 24 6
5 21 6
6 22 6
In [7]: dfB = gpd.GeoDataFrame([[1,3],[2,5],[2,2]],columns = ['lon','lat'])
In [8]: dfB
Out[8]:
lon lat
0 1 3
1 2 5
2 2 2
In [9]: tbd.ckdnearest(dfA,dfB,Aname=['lon1','lat1'],Bname=['lon','lat'])
Out[9]:
lon1 lat1 index lon lat dist
0 1 2 0 1 3 1.111949e+05
1 2 4 1 2 5 1.111949e+05
2 2 6 1 2 5 1.111949e+05
3 2 10 1 2 5 5.559746e+05
4 24 6 1 2 5 2.437393e+06
5 21 6 1 2 5 2.105798e+06
6 22 6 1 2 5 2.216318e+06
点与点匹配(GeoDataFrame与GeoDataFrame)
将A表B表变为包含点信息的GeoDataFrame
In [10]: dfA['geometry'] = gpd.points_from_xy(dfA['lon1'],dfA['lat1'])
In [11]: dfA
Out[11]:
lon1 lat1 geometry
0 1 2 POINT (1.00000 2.00000)
1 2 4 POINT (2.00000 4.00000)
2 2 6 POINT (2.00000 6.00000)
3 2 10 POINT (2.00000 10.00000)
4 24 6 POINT (24.00000 6.00000)
5 21 6 POINT (21.00000 6.00000)
6 22 6 POINT (22.00000 6.00000)
In [12]: dfB['geometry'] = gpd.points_from_xy(dfB['lon'],dfB['lat'])
In [13]: dfB
Out[13]:
lon lat geometry
0 1 3 POINT (1.00000 3.00000)
1 2 5 POINT (2.00000 5.00000)
2 2 2 POINT (2.00000 2.00000)
In [14]: tbd.ckdnearest_point(dfA,dfB)
Out[14]:
lon1 lat1 geometry_x ... lon lat geometry_y
0 1 2 POINT (1.00000 2.00000) ... 1 3 POINT (1.00000 3.00000)
1 2 4 POINT (2.00000 4.00000) ... 2 5 POINT (2.00000 5.00000)
2 2 6 POINT (2.00000 6.00000) ... 2 5 POINT (2.00000 5.00000)
3 2 10 POINT (2.00000 10.00000) ... 2 5 POINT (2.00000 5.00000)
4 24 6 POINT (24.00000 6.00000) ... 2 5 POINT (2.00000 5.00000)
5 21 6 POINT (21.00000 6.00000) ... 2 5 POINT (2.00000 5.00000)
6 22 6 POINT (22.00000 6.00000) ... 2 5 POINT (2.00000 5.00000)
[7 rows x 8 columns]
点与线匹配(GeoDataFrame与GeoDataFrame)
将A表变为地理点,B表为线
In [15]: dfA['geometry'] = gpd.points_from_xy(dfA['lon1'],dfA['lat1'])
In [16]: dfB['geometry'] = [LineString([[1,1],[1.5,2.5],[3.2,4]]),
....: LineString([[1,0],[1.5,0],[4,0]]),
....: LineString([[1,-1],[1.5,-2],[4,-4]])]
....:
In [17]: dfB
Out[17]:
lon lat geometry index
0 1 3 LINESTRING (1.00000 1.00000, 1.50000 2.50000, ... 0
1 2 5 LINESTRING (1.00000 0.00000, 1.50000 0.00000, ... 1
2 2 2 LINESTRING (1.00000 -1.00000, 1.50000 -2.00000... 2
In [18]: tbd.ckdnearest_line(dfA,dfB)
Out[18]:
lon1 lat1 ... lat geometry_y
0 1 2 ... 3 LINESTRING (1.00000 1.00000, 1.50000 2.50000, ...
1 2 4 ... 3 LINESTRING (1.00000 1.00000, 1.50000 2.50000, ...
2 2 6 ... 3 LINESTRING (1.00000 1.00000, 1.50000 2.50000, ...
3 2 10 ... 3 LINESTRING (1.00000 1.00000, 1.50000 2.50000, ...
4 21 6 ... 3 LINESTRING (1.00000 1.00000, 1.50000 2.50000, ...
5 22 6 ... 3 LINESTRING (1.00000 1.00000, 1.50000 2.50000, ...
6 24 6 ... 5 LINESTRING (1.00000 0.00000, 1.50000 0.00000, ...
[7 rows x 8 columns]
打断线
在现实应用中,我们可能需要把很长的线打断为很多子线段,每一条线段不要超过一定的最大长度,此时则可以使用TransBigData包中的splitline_with_length方法。
- transbigdata.splitline_with_length(Centerline, maxlength=100)
输入是线串 GeoDataFrame。分割线的长度不长于最大长度
- 参数:
Centerline (GeoDataFrame) – 线串几何
maxlength (number) – 分割线的最大长度
- 返回:
splitedline – 分割线
- 返回类型:
GeoDataFrame
下面显示如何将线打断为100米一段的线段
#读取线要素
import geopandas as gpd
Centerline = gpd.read_file(r'test_lines.json')
Centerline.plot()

#转换线为投影坐标系
Centerline.crs = {'init':'epsg:4326'}
Centerline = Centerline.to_crs(epsg = '4517')
#计算线的长度
Centerline['length'] = Centerline.length
Centerline
Id | geometry | length | |
---|---|---|---|
0 | 0 | LINESTRING (29554925.232 4882800.694, 29554987... | 285.503444 |
1 | 0 | LINESTRING (29554682.635 4882450.554, 29554773... | 185.482276 |
2 | 0 | LINESTRING (29554987.079 4882521.969, 29555040... | 291.399180 |
3 | 0 | LINESTRING (29554987.079 4882521.969, 29555073... | 248.881529 |
4 | 0 | LINESTRING (29554987.079 4882521.969, 29554969... | 207.571197 |
5 | 0 | LINESTRING (29554773.177 4882288.671, 29554828... | 406.251357 |
6 | 0 | LINESTRING (29554773.177 4882288.671, 29554926... | 158.114403 |
7 | 0 | LINESTRING (29555060.286 4882205.456, 29555082... | 107.426629 |
8 | 0 | LINESTRING (29555040.278 4882235.468, 29555060... | 36.069941 |
9 | 0 | LINESTRING (29555060.286 4882205.456, 29555095... | 176.695446 |
#将线打断为最长100米的线段
import transbigdata as tbd
splitedline = tbd.splitline_with_length(Centerline,maxlength = 100)
#打断后线型不变
splitedline.plot()

#但内容已经变成一段一段了
splitedline
geometry | id | length | |
---|---|---|---|
0 | LINESTRING (29554925.232 4882800.694, 29554927... | 0 | 100.000000 |
1 | LINESTRING (29554946.894 4882703.068, 29554949... | 0 | 100.000000 |
2 | LINESTRING (29554968.557 4882605.443, 29554970... | 0 | 85.503444 |
0 | LINESTRING (29554682.635 4882450.554, 29554688... | 1 | 100.000000 |
1 | LINESTRING (29554731.449 4882363.277, 29554736... | 1 | 85.482276 |
0 | LINESTRING (29554987.079 4882521.969, 29554989... | 2 | 100.000000 |
1 | LINESTRING (29555005.335 4882423.650, 29555007... | 2 | 100.000000 |
2 | LINESTRING (29555023.592 4882325.331, 29555025... | 2 | 91.399180 |
0 | LINESTRING (29554987.079 4882521.969, 29554993... | 3 | 100.000000 |
1 | LINESTRING (29555042.051 4882438.435, 29555048... | 3 | 99.855617 |
2 | LINESTRING (29555111.265 4882370.450, 29555116... | 3 | 48.881529 |
0 | LINESTRING (29554987.079 4882521.969, 29554985... | 4 | 100.000000 |
1 | LINESTRING (29554973.413 4882422.908, 29554971... | 4 | 99.756943 |
2 | LINESTRING (29554930.341 4882335.023, 29554929... | 4 | 7.571197 |
0 | LINESTRING (29554773.177 4882288.671, 29554777... | 5 | 100.000000 |
1 | LINESTRING (29554816.361 4882198.476, 29554821... | 5 | 99.782969 |
2 | LINESTRING (29554882.199 4882125.314, 29554891... | 5 | 99.745378 |
3 | LINESTRING (29554976.612 4882096.588, 29554987... | 5 | 100.000000 |
4 | LINESTRING (29555076.548 4882100.189, 29555077... | 5 | 6.251357 |
0 | LINESTRING (29554773.177 4882288.671, 29554783... | 6 | 100.000000 |
1 | LINESTRING (29554869.914 4882314.006, 29554876... | 6 | 58.114403 |
0 | LINESTRING (29555060.286 4882205.456, 29555062... | 7 | 100.000000 |
1 | LINESTRING (29555081.239 4882107.675, 29555081... | 7 | 7.426629 |
0 | LINESTRING (29555040.278 4882235.468, 29555042... | 8 | 36.069941 |
0 | LINESTRING (29555060.286 4882205.456, 29555064... | 9 | 100.000000 |
1 | LINESTRING (29555094.981 4882299.244, 29555100... | 9 | 76.419694 |
多边形处理
- transbigdata.merge_polygon(data, col)
输入是面几何的地理数据帧和列名称。此函数将根据上述列中的类别合并多边形
- 参数:
data (GeoDataFrame) – 多边形几何
col (str) – 表示类别的列名
- 返回:
data1 – 合并后的多边形
- 返回类型:
GeoDataFrame
- transbigdata.polyon_exterior(data, minarea=0)
输入是面几何的地理数据帧。该方法将通过扩展 ploygon 的外部边界来构造新的多边形
- 参数:
data (GeoDataFrame) – 多边形几何
minarea (number) – 最小面积。
- 返回:
data1 – 处理后的多边形
- 返回类型:
GeoDataFrame
载入底图
|
绘制底图 |
|
为地图添加指南针和比例尺 |
|
|
|
设置地图保存路径 |
读取地图保存路径 |
|
读取mapboxtoken |
启动前设置
如果已经获取了 mapbox的access token,可以使用以下代码为 TransBigData 设置 mapbox的access token(只需要设置一次,以后重新打开 python 时不需要重新设置)
import transbigdata as tbd
#Set your mapboxtoken with the following code
tbd.set_mapboxtoken('pk.eyxxxxxxxxxx.xxxxxxxxx')
# The token you applied for must be set in it.
# Copying this line of code directly is invalid
此外,还需要设置地图底图的存储位置。下次显示相同位置时,将在本地读取和加载地图
# Set your map basemap storage path
# On linux or mac, the path is written like this.
# Note that there is a backslash at the end
tbd.set_imgsavepath(r'/Users/xxxx/xxxx/')
# On windows, the path is written like this.
# Finally, pay attention to two slashes to prevent escape
tbd.set_imgsavepath(r'E:\pythonscript\xxx\\')
设置完成后,下次绘制底图时,会在设置的路径下创建一个tileimg文件夹,并将所有底图放入其中。尝试以下代码,看看是否可以成功绘制底图
# Define display range
bounds = [113.6,22.4,114.8,22.9]
# Plot Frame
import matplotlib.pyplot as plt
fig =plt.figure(1,(8,8),dpi=250)
ax =plt.subplot(111)
plt.sca(ax)
# Add map basemap
tbd.plot_map(plt,bounds,zoom = 11,style = 4)
# Add scale bar and north arrow
tbd.plotscale(ax,bounds = bounds,textsize = 10,compasssize = 1,accuracy = 2000,rect = [0.06,0.03],zorder = 10)
plt.axis('off')
plt.xlim(bounds[0],bounds[2])
plt.ylim(bounds[1],bounds[3])
plt.show()

- transbigdata.plot_map(plt, bounds, zoom='auto', style=0, printlog=False)
绘制底图
- 参数:
plt (matplotlib.pyplot) – 在哪里绘制
bounds (List) – 底图的绘制边界 [lon1,lat1,lon2,lat2](WGS84 坐标系),其中 lon1 和 lat1 是左下角的坐标,lon2 和 lat2 是右上角的坐标
zoom (number) – 底图的放大倍率越大,加载时间越长。通常,单个城市的范围在 12 到 16 之间
printlog (bool) – 显示日志
style (number) – 地图底图的样式可以是1-10,如下
底图样式1:街道

底图样式2:户外

底图样式3:卫星

底图样式4:浅色

底图样式5:深色

底图样式6:light-ch(中文)

底图样式7:冰淇淋

底图样式8:夜景

底图样式9:地形

底图样式 10:基础蓝

底图样式 11:light(无标记)

底图样式 12:深色(无标记)

自定义样式
支持自定义mapbox样式
tbd.plot_map(plt,bounds,zoom = 11,style = 'mapbox://styles/ni1o1/cl38pljx0006r14qp7ioy7gcc')
指南针和刻度
- transbigdata.plotscale(ax, bounds, textcolor='k', textsize=8, compasssize=1, accuracy='auto', rect=[0.1, 0.1], unit='KM', style=1, **kwargs)
为地图添加指南针和比例尺
- 参数:
bounds (List) – 底图的绘制边界 [lon1,lat1,lon2,lat2](WGS84 坐标系),其中 lon1 和 lat1 是左下角的坐标,lon2 和 lat2 是右上角的坐标
textsize (number) – 文本的大小
compasssize (number) – 指南针的大小
accuracy (number) – 比例尺长度(m)
unit (str) – ‘KM’,’km’,’M’,’m’, 刻度单位
style (number) – 1 或 2,比例的样式
rect (List) – 图中比例尺的大致位置,如[0.9,0.9],在右上角
tbd.plotscale(ax,bounds = bounds,textsize = 10,compasssize = 1,accuracy = 2000,rect = [0.06,0.03])
坐标和距离
|
将GCJ02坐标转换为BD09坐标 |
|
将GCJ02坐标转换为WGS84坐标 |
|
将坐标从WGS84转换为GCJ02 |
|
将坐标从WGS84转换为BD09 |
|
将坐标从BD09转换为GCJ02 |
|
将坐标从BD09转换为WGS84 |
|
将坐标从BD09MC转换为BD09 |
|
转换所有数据的坐标。 |
|
从数据帧中按 [lon1, lat1, lon2, lat2] 的顺序输入起始/目标位置(十进制)。 |
坐标转换方式
TransBigData软件包提供GCJ02,BD09,BD09mc,WGS94等坐标的快速转换
- transbigdata.gcj02tobd09(lng, lat)
将GCJ02坐标转换为BD09坐标
- 参数:
lng (Series or number) – 经度
lat (Series or number) – 纬度
- 返回:
lng (系列或数字) – 经度(转换后)
lat (Series or number) – 纬度(转换)
- transbigdata.bd09togcj02(bd_lon, bd_lat)
将坐标从BD09转换为GCJ02
- 参数:
lng (Series or number) – 经度
lat (Series or number) – 纬度
- 返回:
lng (系列或数字) – 经度(转换后)
lat (Series or number) – 纬度(转换)
- transbigdata.wgs84togcj02(lng, lat)
将坐标从WGS84转换为GCJ02
- 参数:
lng (Series or number) – 经度
lat (Series or number) – 纬度
- 返回:
lng (系列或数字) – 经度(转换后)
lat (Series or number) – 纬度(转换)
- transbigdata.gcj02towgs84(lng, lat)
将GCJ02坐标转换为WGS84坐标
- 参数:
lng (Series or number) – 经度
lat (Series or number) – 纬度
- 返回:
lng (系列或数字) – 经度(转换后)
lat (Series or number) – 纬度(转换)
- transbigdata.wgs84tobd09(lon, lat)
将坐标从WGS84转换为BD09
- 参数:
lng (Series or number) – 经度
lat (Series or number) – 纬度
- 返回:
lng (系列或数字) – 经度(转换后)
lat (Series or number) – 纬度(转换)
- transbigdata.bd09towgs84(lon, lat)
将坐标从BD09转换为WGS84
- 参数:
lng (Series or number) – 经度
lat (Series or number) – 纬度
- 返回:
lng (系列或数字) – 经度(转换后)
lat (Series or number) – 纬度(转换)
- transbigdata.bd09mctobd09(x, y)
将坐标从BD09MC转换为BD09
- 参数:
x (Series or number) – x坐标
y (Series or number) – y 坐标
- 返回:
lng (系列或数字) – 经度(转换后)
lat (Series or number) – 纬度(转换)
坐标倒数转换,基于numpy列计算:
>>> data['Lng'],data['Lat'] = tbd.wgs84tobd09(data['Lng'],data['Lat'])
>>> data['Lng'],data['Lat'] = tbd.wgs84togcj02(data['Lng'],data['Lat'])
>>> data['Lng'],data['Lat'] = tbd.gcj02tobd09(data['Lng'],data['Lat'])
>>> data['Lng'],data['Lat'] = tbd.gcj02towgs84(data['Lng'],data['Lat'])
>>> data['Lng'],data['Lat'] = tbd.bd09togcj02(data['Lng'],data['Lat'])
>>> data['Lng'],data['Lat'] = tbd.bd09towgs84(data['Lng'],data['Lat'])
>>> data['Lng'],data['Lat'] = tbd.bd09mctobd09(data['Lng'],data['Lat'])
转换地理元素的坐标
- transbigdata.transform_shape(gdf, method)
转换所有数据的坐标。输入是地理元素的数据帧。
- 参数:
gdf (GeoDataFrame) – 地理要素
method (function) – 坐标转换函数
- 返回:
gdf – 转换后的结果
- 返回类型:
GeoDataFrame
测距
- transbigdata.getdistance(lon1, lat1, lon2, lat2)
从数据帧中按 [lon1, lat1, lon2, lat2] 的顺序输入起始/目标位置(十进制)。输出是距离 (m)。
- 参数:
lon1 (Series or number) – 起始经度
lat1 (Series or number) – 起始纬度
lon2 (Series or number) – 结束经度
lat2 (Series or number) – 结束纬度
- 返回:
distance – 距离
- 返回类型:
Series or number
数据可视化
|
输入是数据点,此函数将聚合然后可视化 |
|
输入的是轨迹数据和列名。 |
|
输入是OD数据和列。 |
在jupyter中显示可视化的设置
pip install keplergl
如果要在jupyter notebook中显示可视化,则需要勾选jupyter-js-widgets(可能需要另外安装)和keplergl-jupyter两个插件

数据点分布可视化
- transbigdata.visualization_data(data, col=['lon', 'lat'], accuracy=500, height=500, maptype='point', zoom='auto')
输入是数据点,此函数将聚合然后可视化
- 参数:
data (DataFrame) – 数据点
col (List) – 列名。用户可以按[经度,纬度]的顺序选择非权重的起点-目的地(OD)数据。为此,聚合是自动的。或者,用户也可以输入加权OD数据,按[经度、纬度、计数]的顺序排列。
zoom (number) – 地图缩放级别(可选)。
height (number) – 地图框的高度
accuracy (number) – 栅格大小
maptype (str) – 地图类型,‘点’或‘热图’
- 返回:
vmap – keplergl 提供的可视化
- 返回类型:
keplergl.keplergl.KeplerGl
轨道可视化
- transbigdata.visualization_trip(trajdata, col=['Lng', 'Lat', 'ID', 'Time'], zoom='auto', height=500)
输入是轨迹数据和列名称。输出是基于开普勒的可视化结果
- 参数:
trajdata (DataFrame) – 轨迹点数据
col (List) – 列名称,按 [经度、纬度、车辆 ID、时间] 的顺序排列
zoom (number) – 地图缩放级别
height (number) – 地图框的高度
- 返回:
vmap – keplergl 提供的可视化
- 返回类型:
keplergl.keplergl.KeplerGl
OD可视化
- transbigdata.visualization_od(oddata, col=['slon', 'slat', 'elon', 'elat'], zoom='auto', height=500, accuracy=500, mincount=0)
输入是 OD 数据和列。输出是基于开普勒的可视化结果
- 参数:
oddata (DataFrame) – 外径数据
col (List) – 列名。用户可以按[原点经度、原点纬度、目的地经度、目的地纬度]的顺序选择非权重的起点-目的地(OD)数据。为此,聚合是自动的。或者,用户也可以输入加权OD数据,按[原点经度、原点纬度、目的地经度、目的地纬度、计数]的顺序排列。
zoom (number) – 地图缩放级别(可选)。
height (number) – 地图框的高度
accuracy (number) – 栅格大小
mincount (number) – 最小OD数,OD数少的不显示
- 返回:
vmap – keplergl 提供的可视化
- 返回类型:
keplergl.keplergl.KeplerGl
活动分析
|
绘制个体的活动图 |
|
计算熵。 |
|
计算熵率。 |
|
点数据的置信椭圆参数估计 |
|
输入置信度椭圆的参数并绘制置信度椭圆 |
活动图
- transbigdata.plot_activity(data, col=['stime', 'etime', 'group'], figsize=(10, 5), dpi=250, shuffle=True, xticks_rotation=0, xticks_gap=1, yticks_gap=1, fontsize=12)
绘制个体的活动图
- 参数:
data (DataFrame) – 一个人的活动信息
col (List) – 列名[starttime,endtime,group],`group`控制颜色分组
figsize (List) – 体形尺寸
dpi (Number) – 图形的dpi
shuffle (bool) – 是否将活动顺序随机打乱
xticks_rotation (Number) – xticks的旋转角度
xticks_gap (Number) – xticks 的间隙
yticks_gap (Number) – yticks 的间隙
fontsize (Number) – xticks 和 yticks 的字体大小
熵
- transbigdata.entropy(sequence)
计算熵。
- 参数:
sequence (List,DataFrame,Series) – 序列数据
- 返回:
熵
- 返回类型:
Number
- transbigdata.entropy_rate(sequence)
计算熵率。参考文献:Goulet-Langlois, G., Koutsopoulos, H. N., Zhao, Z., & Zhao, J. (2017). Measuring regularity of individual travel patterns. IEEE Transactions on Intelligent Transportation Systems, 19(5), 1583-1592.
- 参数:
sequence (List,DataFrame,Series) – 序列数据
- 返回:
熵率
- 返回类型:
Number
置信椭圆
- transbigdata.ellipse_params(data, col=['lon', 'lat'], confidence=95, epsg=None)
点数据的置信椭圆参数估计
- 参数:
data (DataFrame) – 点数据
confidence (number) – 置信度:99,95 或 90
epsg (number) – 如果给定,原始坐标将从 WGS84 转换为给定的 EPSG 坐标系,以进行置信椭圆参数估计
col (List) – 列名,[lon,lat]
- 返回:
参数 – 质心椭圆参数[位置,宽度,高度,θ,面积,扁率] 分别[中心点坐标,短轴,长轴,角度,面积,扁率]
- 返回类型:
List
- transbigdata.ellipse_plot(ellip_params, ax, **kwargs)
输入置信度椭圆的参数并绘制置信度椭圆
- 参数:
ellip_params (List) – 质心椭圆参数[位置、宽度、高度、θ、面积、扁率] 分别[中心点坐标、短轴、长轴、角度、面积、扁率]
ax (matplotlib.axes._subplots.AxesSubplot) – 在哪里绘制
用法
import pandas as pd
import transbigdata as tbd
import numpy as np
#生成测试用数据
data = np.random.uniform(1,10,(100,2))
data[:,1:] = 0.5*data[:,0:1]+np.random.uniform(-2,2,(100,1))
data = pd.DataFrame(data,columns = ['x','y'])
#绘制数据分布
import matplotlib.pyplot as plt
plt.figure(1,(5,5))
#绘制数据点
plt.scatter(data['x'],data['y'],s = 0.5)
#绘制坐标轴
plt.plot([-10,10],[0,0],c = 'k')
plt.plot([0,0],[-10,10],c = 'k')
plt.xlim(-15,15)
plt.ylim(-15,15)
plt.show()

输入数据与xy坐标所在列名,置信度,估计椭圆参数 分别代表[中心点坐标,短轴,长轴,角度,面积,扁率
ellip_params = tbd.ellipse_params(data,confidence=95,col = ['x','y'])
ellip_params
[array([5.78928146, 2.88466235]),
4.6981983145616875,
14.04315715927693,
-58.15524535916836,
51.8186366184246,
0.6654457212665993]
再用tbd.ellipse_plot绘制置信椭圆
#绘制数据分布
import matplotlib.pyplot as plt
plt.figure(1,(5,5))
ax = plt.subplot(111)
#绘制数据点
plt.scatter(data['x'],data['y'],s = 0.5)
#获取置信椭圆参数并绘制椭圆
#99%置信椭圆
ellip_params = tbd.ellipse_params(data,confidence=99,col = ['x','y'])
tbd.ellipse_plot(ellip_params,ax,fill = False,edgecolor = 'r',linewidth = 1)
#95%置信椭圆
ellip_params = tbd.ellipse_params(data,confidence=95,col = ['x','y'])
tbd.ellipse_plot(ellip_params,ax,fill = False,edgecolor = 'b',linewidth = 1)
#90%置信椭圆
ellip_params = tbd.ellipse_params(data,confidence=90,col = ['x','y'])
tbd.ellipse_plot(ellip_params,ax,fill = False,edgecolor = 'k',linewidth = 1)
#绘制坐标轴
plt.plot([-10,10],[0,0],c = 'k')
plt.plot([0,0],[-10,10],c = 'k')
plt.xlim(-15,15)
plt.ylim(-15,15)
plt.show()

数据聚合
|
聚合数据到交通区域 |
|
聚合OD矩阵并生成网格几何。 |
|
生成OD聚合结果和对应的几何图形。 |
- transbigdata.dataagg(data, shape, col=['Lng', 'Lat', 'count'], accuracy=500)
聚合数据到交通区域
- 参数:
data (DataFrame) – 起源DataFrame
shape (GeoDataFrame) – 交通区形状
col (List) – 您可以选择输入两列,即 [‘Lng’、’Lat’],也可以选择输入三列,即 [‘Lng’、’Lat’、’count’]“,其中 count 表示点数
accuracy (number) – 这个想法是首先实现数据网格化,然后实现聚合。在这里,将确定网格大小。尺寸越小,精度就越高。
- 返回:
aggresult (GeoDataFrame) – 流量区域。计数列是输出结果
data1 (DataFrame) – 区域匹配数据
- transbigdata.odagg_grid(oddata, params, col=['slon', 'slat', 'elon', 'elat'], arrow=False, **kwargs)
聚合 OD 矩阵并生成格网几何。输入是 OD 矩阵(每行代表一个行程)。OD 将分配给格网,然后以地理数据帧的形式进行聚合。
- 参数:
oddata (DataFrame) – 外径数据
col (List) – 起点/终点位置的列,[‘slon’, ‘slat’, ‘elon’, ‘elat’]。每列的默认权重为 1。您还可以添加权重参数,例如 [‘slon’, ‘slat’, ‘elon’, ‘elat’, ‘count’]。
params (List) – 网格参数(lonStart,latStart,deltaLon,deltaLat),lonStart和latStart是左下角的坐标,deltaLon,deltaLat是单个网格的长度和宽度
arrow (bool) – 生成的OD地理线是否包含箭头
- 返回:
oddata1 – 聚合后OD的GeoDataFrame
- 返回类型:
GeoDataFrame
- transbigdata.odagg_shape(oddata, shape, col=['slon', 'slat', 'elon', 'elat'], params=None, round_accuracy=6, arrow=False, **kwargs)
生成 OD 聚合结果和相应的几何图形。输入是 OD 数据(每行代表一个行程)。OD 将分配给格网,然后以地理数据帧的形式进行聚合。
- 参数:
oddata (DataFrame) – 外径数据
shape (GeoDataFrame) – 目标交通区域的GeoDataFrame
col (List) – 起点/终点位置的列,[‘slon’, ‘slat’, ‘elon’ , ‘elat’]。每列的默认权重为 1。您还可以添加权重参数,例如 [‘slon’、’slat’、’elon’、’elat’、’count’]。
params (List (optional)) – 网格参数(lonStart,latStart,deltaLon,deltaLat),lonStart和latStart是左下角的坐标,deltaLon,deltaLat是单个网格的长度和宽度如果可用,数据网格化后,将根据网格中心匹配流量区域。如果不可用,则将根据经度和纬度处理匹配。当数据项数量较大时,由于数据网格化,匹配效率将大大提高。
round_accuracy (number) – 实现聚合时纬度和经度的小数位数
arrow (bool) – 生成的OD地理线是否包含箭头
- 返回:
oddata1 – 聚合后OD的GeoDataFrame
- 返回类型:
GeoDataFrame
其他
|
输入json数据,保存为文件。 |
- transbigdata.dumpjson(data, path)
输入 json 数据并将其另存为文件。此方法适用于解决 numpy 无法与 json 包兼容的问题。
- 参数:
data (json) – 需要保存的json数据
path (str) – 存储路径
特定数据处理方法
手机数据处理
|
输入停留点数据以识别夜间和白天的持续时间。 |
|
通过手机停留数据识别居住地位置。 |
|
通过手机停留数据识别工作地点。 |
- transbigdata.mobile_stay_duration(staydata, col=['stime', 'etime'], start_hour=8, end_hour=20)
输入停留点数据以识别夜间和白天的持续时间。
- 参数:
staydata (DataFrame) – 停留数据
col (List) – 列名,顺序为[‘starttime’,’endtime’]
start_hour (Number) – 一天中的开始时间
end_hour (Number) – 一天时间的结束时间
- 返回:
duration_night (Series) – 夜间持续时间
duration_day (Series) – 白天的持续时间
- transbigdata.mobile_identify_home(staydata, col=['uid', 'stime', 'etime', 'LONCOL', 'LATCOL'], start_hour=8, end_hour=20)
从手机停留数据中识别居住地位置。规则是确定夜间持续时间最长的位置。
- 参数:
staydata (DataFrame) – 停留数据
col (List) – 列名,按 [‘uid’, ‘stime’, ‘etime’, ‘locationtag1’, ‘locationtag2’, …] 的顺序排列。可以有多个“位置标签”列来指定位置。
start_hour (Number) – 一天时间的开始时间和结束时间
end_hour (Number) – 一天时间的开始时间和结束时间
- 返回:
home – 手机用户的家位置
- 返回类型:
DataFrame
- transbigdata.mobile_identify_work(staydata, col=['uid', 'stime', 'etime', 'LONCOL', 'LATCOL'], minhour=3, start_hour=8, end_hour=20, workdaystart=0, workdayend=4)
从手机停留数据中识别工作地点。规则是确定工作日白天持续时间最长的位置(平均持续时间应超过“minhour”)。
- 参数:
staydata (DataFrame) – 停留数据
col (List) – 列名,按 [‘uid’、stime’、’etime’、’locationtag1’、’locationtag2’, …] 的顺序排列。可以有多个“locationtag”列来指定位置。
minhour (Number) – 工作日的最短持续时间(小时)。
workdaystart (Number) – 一周中工作日的开始和结束。
workdayend (Number) – 一周中工作日的开始和结束。
start_hour (Number) – 一天时间的开始时间和结束时间
end_hour (Number) – 一天时间的开始时间和结束时间
- 返回:
work – 手机用户的工作地
- 返回类型:
DataFrame
出租汽车GPS数据处理
|
从出租车数据中删除乘客携带状态的瞬时变化记录。 |
|
输入出租车GPS数据,提取OD信息 |
|
输入出租车数据和OD数据,提取配送和闲置行程的轨迹点 |
- transbigdata.clean_taxi_status(data, col=['VehicleNum', 'Time', 'OpenStatus'], timelimit=None)
从出租车数据中删除乘客携带状态的瞬时变化记录。这些异常记录会影响旅行订单判断。判断方法:如果同一车辆上一条记录和下一条记录的乘客状态与该记录不同,则应删除该记录。
- 参数:
data (DataFrame) – 数据
col (List) – 列名,顺序为[‘VehicleNum’, ‘Time’, ‘OpenStatus’]
timelimit (number) – 可选,以秒为单位。如果上一条记录和下一条记录之间的时间小于时间阈值,则将删除该记录
- 返回:
data1 – 清理后的数据
- 返回类型:
DataFrame
- transbigdata.taxigps_to_od(data, col=['VehicleNum', 'Stime', 'Lng', 'Lat', 'OpenStatus'])
输入出租车GPS数据,提取OD信息
- 参数:
data (DataFrame) – 出租车GPS数据
col (List) – 列名在数据中,需要按顺序排列[车辆ID、时间、经度、纬度、乘客状态]
- 返回:
oddata – OD信息
- 返回类型:
DataFrame
- transbigdata.taxigps_traj_point(data, oddata, col=['Vehicleid', 'Time', 'Lng', 'Lat', 'OpenStatus'])
输入出租车数据和OD数据,提取配送和闲置行程的轨迹点
- 参数:
data (DataFrame) – 出租车GPS数据,col变量指定的字段名
oddata (DataFrame) – 出租车OD数据
col (List) – 栏目名称,需按顺序排列[车辆ID、时间、经度、纬度、旅客状态]
- 返回:
data_deliver (DataFrame) – 送货行程的轨迹点
data_idle (DataFrame) – 空闲行程的轨迹点
共享单车数据处理
|
输入共享单车订单数据(仅在锁打开和关闭时生成数据),指定列名称,并从中提取乘车和停车信息 |
- transbigdata.bikedata_to_od(data, col=['BIKE_ID', 'DATA_TIME', 'LONGITUDE', 'LATITUDE', 'LOCK_STATUS'], startend=None)
输入共享单车订单数据(仅在锁打开和关闭时生成数据),指定列名称,并从中提取乘车和停车信息
- 参数:
data (DataFrame) – 共享单车订单数据
col (List) – 列名,顺序不能更改。[“BIKE_ID”、“DATA_TIME”、“经度”、“纬度”、“LOCK_STATUS]
startend (List) – 观察周期的开始时间和结束时间,例如 [‘2018-08-27 00:00:00’、’2018-08-28 00:00:00’]。如果通过,则考虑骑行和停车情况(从观察期开始到自行车首次出现)和(从自行车最后一次出现到观察期结束)。
- 返回:
move_data (DataFrame) – 骑行数据
stop_data (DataFrame) – 停车数据
公交GPS数据处理
|
输入公交GPS数据、公交线路和车站GeoDataFrame,该方法可以识别公交车的到达和出发信息 |
|
输入出发信息表drive_info和车站信息表停靠点计算单程行车时间 |
- transbigdata.busgps_arriveinfo(data, line, stop, col=['VehicleId', 'GPSDateTime', 'lon', 'lat', 'stopname'], stopbuffer=200, mintime=300, disgap=200, project_epsg='auto', timegap=1800, projectoutput=False)
输入公交GPS数据、公交线路和车站GeoDataFrame,该方法可以识别公交车的到达和出发信息
- 参数:
data (DataFrame) – 总线全球定位系统数据。它应该是来自一条公交路线的数据,并且需要包含车辆ID,GPS时间,纬度和经度(wgs84)
line (GeoDataFrame) – 公交线路的GeoDataFrame
stop (GeoDataFrame) – 公交车站的GeoDataFrame
col (List) – 列名称,按 [车辆 ID、时间、经度、纬度、车站名称] 的顺序排列
stopbuffer (number) – 米。当车辆在此一定距离内接近车站时,视为到达车站。
mintime (number) – 秒。在短时间内,巴士再次到达公交车站,将不被视为再次到达
disgap (number) – 米。车辆前点和后点之间的距离,用于确定车辆是否在移动
project_epsg (number) – 匹配算法将数据转换为投影坐标系来计算距离,这里给出投影坐标系的epsg代码
timegap (number) – 秒。车辆没有出现多长时间,它将被视为新车
projectoutput (bool) – 是否输出投影数据
- 返回:
arrive_info – 公交到发信息
- 返回类型:
DataFrame
- transbigdata.busgps_onewaytime(arrive_info, start, end, col=['VehicleId', 'stopname', 'arrivetime', 'leavetime'])
输入出发信息表drive_info和车站信息表停靠点计算单程行车时间
- 参数:
arrive_info (DataFrame) – 发车信息表drive_info
start (Str) – 起始站名
end (Str) – 终点站名
col (List) – 列名[车号,站名,到达时间,离开时间]
- 返回:
onewaytime – 公交车单程时间
- 返回类型:
DataFrame
公交地铁网络拓扑建模
方法总览
|
输入地铁站数据并输出网络拓扑模型。 |
|
获取下一个地铁最短路径的出行路径 |
|
获取距离地铁nextwork的第k条最短路径 |
|
获取路径的行程时间 |
|
将地铁线路与地铁站进行切片以获取地铁部分信息(此步骤在地铁客流可视化中很有用) |
- transbigdata.metro_network(line, stop, transfertime=5, nxgraph=True)
输入地铁站数据并输出网络拓扑模型。生成的图形依赖于 NetworkX。行程时间包括:车站之间的运营时间+各车站的停靠时间+换乘时间
- 参数:
line (GeoDataFrame) – 线。应该有“线路”列来存储线路名称“速度”列来存储地铁速度,“停止时间”列来存储每个车站的停靠时间。
stop (GeoDataFrame) – 巴士/地铁站
transfertime (number) – 每次换乘所需时间
nxgraph (bool) – 默认值为 True,如果为 True,则输出 NetworkX 构造的网络 G,如果为 False,则输出 edges1(线段)、edge2(站换乘)和网络节点
- 返回:
当 nxgraph 参数为 True 时:**G**(networkx.classes.graph.Graph)— networkx 中构建的图 。 当 nxgraph 参数为 False 时:**edge1**(DataFrame) — 线段的网络边。**edge2**(DataFrame) — 用于传输的网络边缘。**node**(List) — 网络节点。
- transbigdata.get_shortest_path(G, stop, ostation, dstation)
获取下一个地铁最短路径的出行路径
- 参数:
G (networkx.classes.graph.Graph) – 地铁网络
stop (DataFrame) – 地铁站数据框
ostation (str) – O站名
dstation (str) – D站名
- 返回:
path – 旅行路径:站名列表
- 返回类型:
list
- transbigdata.get_k_shortest_paths(G, stop, ostation, dstation, k)
获取距离地铁nextwork的第k条最短路径
- 参数:
G (networkx.classes.graph.Graph) – 地铁网络
stop (DataFrame) – 地铁站数据框
ostation (str) – O站名
dstation (str) – D站名
k (int) – 第k条最短路径
- 返回:
paths – 旅行路径:旅行路径列表
- 返回类型:
list
- transbigdata.get_path_traveltime(G, path)
获取路径的行程时间
- 参数:
G (networkx.classes.graph.Graph) – 地铁网络
path (list) – 站名列表
- 返回:
traveltime – 路径的旅行时间
- 返回类型:
float
- transbigdata.split_subwayline(line, stop)
将地铁线路与地铁站进行切片以获取地铁部分信息(此步骤在地铁客流可视化中很有用)
- 参数:
line (GeoDataFrame) – 公交/地铁线路
stop (GeoDataFrame) – 巴士/地铁站
- 返回:
metro_line_splited – 生成的剖面线形状
- 返回类型:
GeoDataFrame