gotrackit 0.2.2__tar.gz → 0.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. {gotrackit-0.2.2/src/gotrackit.egg-info → gotrackit-0.2.4}/PKG-INFO +32 -21
  2. {gotrackit-0.2.2 → gotrackit-0.2.4}/README.md +31 -20
  3. {gotrackit-0.2.2 → gotrackit-0.2.4}/pyproject.toml +1 -1
  4. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/MapMatch.py +82 -35
  5. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/gps/GpsArray.py +2 -2
  6. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/gps/GpsTrip.py +7 -4
  7. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/gps/GpsXfer.py +1 -1
  8. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/gps/LocGps.py +17 -15
  9. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/map/Link.py +37 -9
  10. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/map/Net.py +71 -14
  11. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/map/Node.py +11 -5
  12. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/model/Markov.py +62 -246
  13. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/NetGen.py +13 -0
  14. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/SaveStreets/streets.py +5 -0
  15. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/tools/geo_process.py +2 -1
  16. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/visualization.py +24 -11
  17. {gotrackit-0.2.2 → gotrackit-0.2.4/src/gotrackit.egg-info}/PKG-INFO +32 -21
  18. {gotrackit-0.2.2 → gotrackit-0.2.4}/LICENSE +0 -0
  19. {gotrackit-0.2.2 → gotrackit-0.2.4}/setup.cfg +0 -0
  20. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/__init__.py +0 -0
  21. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/GlobalVal.py +0 -0
  22. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/WrapsFunc.py +0 -0
  23. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/__init__.py +0 -0
  24. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/generation/GpsGen.py +0 -0
  25. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/generation/__init__.py +0 -0
  26. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/gps/__init__.py +0 -0
  27. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/map/__init__.py +0 -0
  28. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/model/__init__.py +0 -0
  29. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/GlobalVal.py +0 -0
  30. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/Parse/__init__.py +0 -0
  31. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/Parse/gd_car_path.py +0 -0
  32. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/PublicTools/GeoProcess.py +0 -0
  33. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/PublicTools/GraphAna.py +0 -0
  34. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/PublicTools/IndexAna.py +0 -0
  35. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/PublicTools/MapProcess.py +0 -0
  36. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/PublicTools/__init__.py +0 -0
  37. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/PublicTools/od.py +0 -0
  38. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/Request/__init__.py +0 -0
  39. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/Request/api/WebApi.py +0 -0
  40. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/Request/api/__init__.py +0 -0
  41. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/Request/request_path.py +0 -0
  42. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/Request/usage/__init__.py +0 -0
  43. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/Request/usage/bd_ts.py +0 -0
  44. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/Request/usage/gd_car_path.py +0 -0
  45. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/DupProcess/DupLinks.py +0 -0
  46. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/DupProcess/__init__.py +0 -0
  47. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Merge/__init__.py +0 -0
  48. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Merge/get_merged_link_seq.py +0 -0
  49. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Merge/limit/__init__.py +0 -0
  50. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Merge/limit/attr_limit.py +0 -0
  51. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Merge/limit/direction_limit.py +0 -0
  52. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Merge/limit/same_head_tail_limit.py +0 -0
  53. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Merge/limit/two_degrees_group.py +0 -0
  54. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Merge/merge_links.py +0 -0
  55. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Merge/merge_short.py +0 -0
  56. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/MultiCoreMerge/__init__.py +0 -0
  57. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/MultiCoreMerge/limit/__init__.py +0 -0
  58. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/MultiCoreMerge/limit/attr_limit.py +0 -0
  59. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/MultiCoreMerge/limit/direction_limit.py +0 -0
  60. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/MultiCoreMerge/limit/same_head_tail_limit.py +0 -0
  61. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/MultiCoreMerge/limit/two_degrees_group.py +0 -0
  62. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/MultiCoreMerge/merge_links_multi.py +0 -0
  63. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/SaveStreets/__init__.py +0 -0
  64. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Split/SplitPath.py +0 -0
  65. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Split/__init__.py +0 -0
  66. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Tools/__init__.py +0 -0
  67. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/Tools/process.py +0 -0
  68. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/__init__.py +0 -0
  69. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/conn.py +0 -0
  70. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/increment.py +0 -0
  71. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/net_reverse.py +0 -0
  72. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/optimize_net.py +0 -0
  73. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/RoadNet/save_file.py +0 -0
  74. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/__init__.py +0 -0
  75. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/book_mark.py +0 -0
  76. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netreverse/format_od.py +0 -0
  77. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netxfer/SumoConvert.py +0 -0
  78. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/netxfer/__init__.py +0 -0
  79. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/solver/Viterbi.py +0 -0
  80. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/solver/__init__.py +0 -0
  81. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/tools/__init__.py +0 -0
  82. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/tools/coord_trans.py +0 -0
  83. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/tools/group.py +0 -0
  84. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit/tools/save_file.py +0 -0
  85. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit.egg-info/SOURCES.txt +0 -0
  86. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit.egg-info/dependency_links.txt +0 -0
  87. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit.egg-info/requires.txt +0 -0
  88. {gotrackit-0.2.2 → gotrackit-0.2.4}/src/gotrackit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gotrackit
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: A Python Package for Map Matching Algorithm Based on Hidden Markov Model
5
5
  Author-email: Kai Tang <794568794@qq.com>
6
6
  License: LICENCE
@@ -38,50 +38,61 @@ Requires-Dist: geopy
38
38
 
39
39
  ~ 一个包搞定:路网获取、路网优化、宏微观地图匹配、匹配可视化、问题路段快速定位 ~
40
40
 
41
- 唐铠, 794568794@qq.com, tangkai@zhechengdata.com
41
+ Developed by Tang Kai, Email: 794568794@qq.com & tangkai@zhechengdata.com
42
42
  </div>
43
43
  <br>
44
44
 
45
45
 
46
46
 
47
- **版本状态:04.27即将更新更新: v0.2.2**
47
+ **版本状态:05.07已经更新: v0.2.3**
48
48
 
49
49
  更新命令:pip install --upgrade -i https://pypi.org/simple/ gotrackit
50
50
 
51
- - 向量化改造, 且引入FMM(Fast Map Matching)路径预存储机制, 大规模路网匹配效率大幅度提升
52
51
 
53
- - 完善报错机制, 遇到GPS脏数据不再报错停止, 而是跳过, 并且在所有的agents计算完毕后输出有问题的agent编号
52
+ - 地图匹配接口效率优化, 相较于v0.2.2小幅度提升
53
+
54
+ - 地图匹配接口报错机制优化
55
+
56
+ - 地图匹配接口移除html_fldr参数, 使用out_fldr替代
57
+
58
+ - 地图匹配接口增加即时输出开关instant_output, 打开后, 每匹配完一条轨迹马上进行结果存储
59
+
60
+ - 路网构建: crs判断BUG修复、境外路网构建失败BUG修复
61
+
62
+ - 增加 环路 处理功能
63
+
64
+
65
+ **不要下载GitHub仓库上的代码来使用!!! 直接pip安装gotrackit为第三方库即可使用**
54
66
 
55
- - BUG修复
56
67
 
57
68
  <br>
58
69
 
59
70
  <div align=center>
60
- ~ v0.2.2效率将大幅度提升 ~
71
+ ~ v0.2.4(相较于0.2.1)效率将大幅度提升, 最高可以提升10倍的性能 !~
61
72
  </div>
62
73
 
63
74
  <br>
64
75
 
65
76
  与上一版本对比:
66
77
 
67
- | 样例数据 | 有效的GPS点数 | top_k(k邻近候选参数) | gps_buffer(临域半径) | 候选路段条数 | 状态转移次数 | v0.2.1版解算时间 | v0.2.2版解算时间 |
68
- |----------------|----------|----------------|------------------|---------|------------|-------------|-----------|
69
- | 1辆车,深圳稀疏轨迹点样例1 | 190 | 60 | 500m | 10615 | 629788次 | 28秒 | **3.3秒** |
70
- | 1辆车,深圳稀疏轨迹点样例2 | 400 | 20 | 120m | 5137 | 82006次 | 7.8秒 | **1.7秒** |
78
+ | 样例数据 | 有效的GPS点数 | top_k(k邻近候选参数) | gps_buffer(临域半径) | 候选路段条数 | 状态转移次数 | v0.2.1版解算时间 | v0.2.4版解算时间 |
79
+ |----------------|----------|----------------|------------------|---------|------------|-------------|-------------|
80
+ | 1辆车,深圳稀疏轨迹点样例1 | 190 | 60 | 500m | 10615 | 629788次 | 28秒 | **1.87秒** |
81
+ | 1辆车,深圳稀疏轨迹点样例2 | 400 | 20 | 120m | 5137 | 82006次 | 7.8秒 | **0.89秒** |
71
82
 
72
83
 
73
- v0.2.2多核效率对比:
84
+ v0.2.4多核效率对比:
74
85
 
75
- 基于上表深圳稀疏轨迹点样例2,我们将他复制150份,进行多核测试,可以看到到6核时, 效率已经不再提升,最快96s解算完150条轨迹,平均每条轨迹0.64s,相较于1.7s再次提升了60%,在车辆数较多时,多核的效率提升很明显。
86
+ 基于上表深圳稀疏轨迹点样例2,我们将他复制150份,进行多核测试,可以看到到6核时, 效率已经不再提升,最快89s解算完150条轨迹,平均每条轨迹0.59s,相较于0.89s再次提升了30%,在车辆数较多时,多核的效率提升很明显。
76
87
 
77
- | 样例数据 | 有效的GPS点数 | top_k | gps_buffer | 候选路段条数 | 状态转移次数 | v0.2.2解算时间 |
88
+ | 样例数据 | 有效的GPS点数 | top_k | gps_buffer | 候选路段条数 | 状态转移次数 | v0.2.4解算时间 |
78
89
  |-------------------------------------------|----------|----------------|------------------|-----|--------|------------|
79
- | 150辆车的GPS轨迹(单核串行,子图搜索,有构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 300.0秒 |
80
- | 150辆车的GPS轨迹(3核并行,子图搜索,有构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 139.6秒 |
81
- | 150辆车的GPS轨迹(3核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 120.3秒 |
82
- | 150辆车的GPS轨迹(4核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 104.9 |
83
- | 150辆车的GPS轨迹(5核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 96.4秒 |
84
- | 150辆车的GPS轨迹(6核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 97.5秒 |
90
+ | 150辆车的GPS轨迹(单核串行,子图搜索,有构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 290.0秒 |
91
+ | 150辆车的GPS轨迹(3核并行,子图搜索,有构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 130.6秒 |
92
+ | 150辆车的GPS轨迹(3核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 113.3秒 |
93
+ | 150辆车的GPS轨迹(4核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 97.3 |
94
+ | 150辆车的GPS轨迹(5核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 89.4秒 |
95
+ | 150辆车的GPS轨迹(6核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 91.5秒 |
85
96
 
86
97
 
87
98
  <br>
@@ -155,7 +166,7 @@ v0.2.2多核效率对比:
155
166
  - 算法原理讲解部分不涉及复杂的公式推导,使用动画形式剖析算法原理,简洁明了。
156
167
 
157
168
  **匹配结果自动优化**
158
- - 对基于HMM匹配的初步路径进行了优化,对于不连通的位置会自动补路,对于实际路网不连通的位置会输出警告,方便用户检查路网。
169
+ - 对基于HMM匹配的初步路径进行了优化,对于不连通的位置会自动搜路补全,对于实际路网不连通的位置会输出警告信息,方便用户回溯问题。
159
170
 
160
171
 
161
172
 
@@ -16,50 +16,61 @@
16
16
 
17
17
  ~ 一个包搞定:路网获取、路网优化、宏微观地图匹配、匹配可视化、问题路段快速定位 ~
18
18
 
19
- 唐铠, 794568794@qq.com, tangkai@zhechengdata.com
19
+ Developed by Tang Kai, Email: 794568794@qq.com & tangkai@zhechengdata.com
20
20
  </div>
21
21
  <br>
22
22
 
23
23
 
24
24
 
25
- **版本状态:04.27即将更新更新: v0.2.2**
25
+ **版本状态:05.07已经更新: v0.2.3**
26
26
 
27
27
  更新命令:pip install --upgrade -i https://pypi.org/simple/ gotrackit
28
28
 
29
- - 向量化改造, 且引入FMM(Fast Map Matching)路径预存储机制, 大规模路网匹配效率大幅度提升
30
29
 
31
- - 完善报错机制, 遇到GPS脏数据不再报错停止, 而是跳过, 并且在所有的agents计算完毕后输出有问题的agent编号
30
+ - 地图匹配接口效率优化, 相较于v0.2.2小幅度提升
31
+
32
+ - 地图匹配接口报错机制优化
33
+
34
+ - 地图匹配接口移除html_fldr参数, 使用out_fldr替代
35
+
36
+ - 地图匹配接口增加即时输出开关instant_output, 打开后, 每匹配完一条轨迹马上进行结果存储
37
+
38
+ - 路网构建: crs判断BUG修复、境外路网构建失败BUG修复
39
+
40
+ - 增加 环路 处理功能
41
+
42
+
43
+ **不要下载GitHub仓库上的代码来使用!!! 直接pip安装gotrackit为第三方库即可使用**
32
44
 
33
- - BUG修复
34
45
 
35
46
  <br>
36
47
 
37
48
  <div align=center>
38
- ~ v0.2.2效率将大幅度提升 ~
49
+ ~ v0.2.4(相较于0.2.1)效率将大幅度提升, 最高可以提升10倍的性能 !~
39
50
  </div>
40
51
 
41
52
  <br>
42
53
 
43
54
  与上一版本对比:
44
55
 
45
- | 样例数据 | 有效的GPS点数 | top_k(k邻近候选参数) | gps_buffer(临域半径) | 候选路段条数 | 状态转移次数 | v0.2.1版解算时间 | v0.2.2版解算时间 |
46
- |----------------|----------|----------------|------------------|---------|------------|-------------|-----------|
47
- | 1辆车,深圳稀疏轨迹点样例1 | 190 | 60 | 500m | 10615 | 629788次 | 28秒 | **3.3秒** |
48
- | 1辆车,深圳稀疏轨迹点样例2 | 400 | 20 | 120m | 5137 | 82006次 | 7.8秒 | **1.7秒** |
56
+ | 样例数据 | 有效的GPS点数 | top_k(k邻近候选参数) | gps_buffer(临域半径) | 候选路段条数 | 状态转移次数 | v0.2.1版解算时间 | v0.2.4版解算时间 |
57
+ |----------------|----------|----------------|------------------|---------|------------|-------------|-------------|
58
+ | 1辆车,深圳稀疏轨迹点样例1 | 190 | 60 | 500m | 10615 | 629788次 | 28秒 | **1.87秒** |
59
+ | 1辆车,深圳稀疏轨迹点样例2 | 400 | 20 | 120m | 5137 | 82006次 | 7.8秒 | **0.89秒** |
49
60
 
50
61
 
51
- v0.2.2多核效率对比:
62
+ v0.2.4多核效率对比:
52
63
 
53
- 基于上表深圳稀疏轨迹点样例2,我们将他复制150份,进行多核测试,可以看到到6核时, 效率已经不再提升,最快96s解算完150条轨迹,平均每条轨迹0.64s,相较于1.7s再次提升了60%,在车辆数较多时,多核的效率提升很明显。
64
+ 基于上表深圳稀疏轨迹点样例2,我们将他复制150份,进行多核测试,可以看到到6核时, 效率已经不再提升,最快89s解算完150条轨迹,平均每条轨迹0.59s,相较于0.89s再次提升了30%,在车辆数较多时,多核的效率提升很明显。
54
65
 
55
- | 样例数据 | 有效的GPS点数 | top_k | gps_buffer | 候选路段条数 | 状态转移次数 | v0.2.2解算时间 |
66
+ | 样例数据 | 有效的GPS点数 | top_k | gps_buffer | 候选路段条数 | 状态转移次数 | v0.2.4解算时间 |
56
67
  |-------------------------------------------|----------|----------------|------------------|-----|--------|------------|
57
- | 150辆车的GPS轨迹(单核串行,子图搜索,有构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 300.0秒 |
58
- | 150辆车的GPS轨迹(3核并行,子图搜索,有构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 139.6秒 |
59
- | 150辆车的GPS轨迹(3核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 120.3秒 |
60
- | 150辆车的GPS轨迹(4核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 104.9 |
61
- | 150辆车的GPS轨迹(5核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 96.4秒 |
62
- | 150辆车的GPS轨迹(6核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 97.5秒 |
68
+ | 150辆车的GPS轨迹(单核串行,子图搜索,有构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 290.0秒 |
69
+ | 150辆车的GPS轨迹(3核并行,子图搜索,有构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 130.6秒 |
70
+ | 150辆车的GPS轨迹(3核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 113.3秒 |
71
+ | 150辆车的GPS轨迹(4核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 97.3 |
72
+ | 150辆车的GPS轨迹(5核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 89.4秒 |
73
+ | 150辆车的GPS轨迹(6核并行,全图搜索,无构建子图的额外开销,提前预计算路径) | 6w | 20 | 120m | 75W | 1200W次 | 91.5秒 |
63
74
 
64
75
 
65
76
  <br>
@@ -133,7 +144,7 @@ v0.2.2多核效率对比:
133
144
  - 算法原理讲解部分不涉及复杂的公式推导,使用动画形式剖析算法原理,简洁明了。
134
145
 
135
146
  **匹配结果自动优化**
136
- - 对基于HMM匹配的初步路径进行了优化,对于不连通的位置会自动补路,对于实际路网不连通的位置会输出警告,方便用户检查路网。
147
+ - 对基于HMM匹配的初步路径进行了优化,对于不连通的位置会自动搜路补全,对于实际路网不连通的位置会输出警告信息,方便用户回溯问题。
137
148
 
138
149
 
139
150
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gotrackit"
7
- version = "0.2.2"
7
+ version = "0.2.4"
8
8
  dependencies = ["geopandas>=0.14.1", "shapely", "networkx", "pandas", "numpy", "keplergl", "geopy"]
9
9
  requires-python = ">=3.8"
10
10
  authors = [
@@ -26,19 +26,19 @@ class MapMatch(object):
26
26
  time_format: str = "%Y-%m-%d %H:%M:%S", time_unit: str = 's',
27
27
  gps_buffer: float = 200.0, gps_route_buffer_gap: float = 15.0,
28
28
  max_increment_times: int = 2, increment_buffer: float = 15.0,
29
- beta: float = 20.0, gps_sigma: float = 20.0, dis_para: float = 0.1,
29
+ beta: float = 6.0, gps_sigma: float = 30.0, dis_para: float = 0.1,
30
30
  is_lower_f: bool = False, lower_n: int = 2,
31
31
  use_heading_inf: bool = False, heading_para_array: np.ndarray = None,
32
32
  dense_gps: bool = True, dense_interval: float = 80.0,
33
33
  dwell_l_length: float = 10.0, dwell_n: int = 2, del_dwell: bool = True,
34
34
  dup_threshold: float = 10.0,
35
35
  is_rolling_average: bool = False, window: int = 2,
36
- export_html: bool = False, use_gps_source: bool = False, html_fldr: str = None,
36
+ export_html: bool = False, use_gps_source: bool = False, out_fldr: str = None,
37
37
  export_geo_res: bool = False,
38
38
  node_num_threshold: int = 2000, top_k: int = 20, omitted_l: float = 6.0,
39
39
  link_width: float = 1.5, node_radius: float = 1.5,
40
40
  match_link_width: float = 5.0, gps_radius: float = 6.0, export_all_agents: bool = False,
41
- visualization_cache_times: int = 50, multi_core_save: bool = False):
41
+ visualization_cache_times: int = 50, multi_core_save: bool = False, instant_output: bool = False):
42
42
  """
43
43
  :param flag_name: 标记字符名称, 会用于标记输出的可视化文件, 默认"test"
44
44
  :param net: gotrackit路网对象, 必须指定
@@ -64,14 +64,15 @@ class MapMatch(object):
64
64
  :param window: 滑动窗口大小, 默认2
65
65
  :param export_html: 是否输出网页可视化结果html文件, 默认True
66
66
  :param use_gps_source: 是否在可视化结果中使用GPS源数据进行展示, 默认False
67
- :param html_fldr: 保存网页可视化结果的文件目录, 默认当前目录
67
+ :param out_fldr: 保存匹配结果的文件目录, 默认当前目录
68
68
  :param export_geo_res: 是否输出匹配结果的几何可视化文件, 默认False
69
69
  :param node_num_threshold: 默认2000
70
70
  :param omitted_l: 当某GPS点与前后GPS点的平均距离小于该距离(m)时, 该GPS点的方向限制作用被取消
71
71
  :param gps_radius: HTML可视化中GPS点的半径大小,单位米,默认8米
72
72
  :param export_all_agents: 是否将所有agent的可视化存储于一个html文件中
73
- :param visualization_cache_times: 每匹配完几辆车再进行结果的统一存储, 默认50
73
+ :param visualization_cache_times: 每匹配完几辆车再进行(html or geojson文件)结果的统一存储, 默认50
74
74
  :param multi_core_save: 是否启用多进程进行结果存储
75
+ :param instant_output: 是否每匹配完一条轨迹就存储csv匹配结果
75
76
  """
76
77
  # 坐标系投影
77
78
  self.plain_crs = net.planar_crs
@@ -115,7 +116,7 @@ class MapMatch(object):
115
116
 
116
117
  self.export_html = export_html
117
118
  self.export_geo_res = export_geo_res
118
- self.html_fldr = html_fldr
119
+ self.out_fldr = r'./' if out_fldr is None else out_fldr
119
120
 
120
121
  self.may_error_list = dict()
121
122
  self.error_list = list()
@@ -134,6 +135,7 @@ class MapMatch(object):
134
135
  self.visualization_cache_times = visualization_cache_times
135
136
  self.multi_core_save = multi_core_save
136
137
  self.sub_net_buffer = self.gps_buffer + self.gps_route_buffer_gap + max_increment_times * increment_buffer
138
+ self.instant_output = instant_output
137
139
 
138
140
  def execute(self) -> tuple[pd.DataFrame, dict, list]:
139
141
  match_res_df = pd.DataFrame()
@@ -152,29 +154,49 @@ class MapMatch(object):
152
154
  for agent_id, _gps_df in self.gps_df.groupby(gps_field.AGENT_ID_FIELD):
153
155
  agent_count += 1
154
156
  print(rf'- gotrackit ------> No.{agent_count}: agent: {agent_id} ')
155
- gps_obj = GpsPointsGdf(gps_points_df=_gps_df, time_format=self.time_format,
156
- buffer=self.gps_buffer, time_unit=self.time_unit,
157
- plane_crs=self.plain_crs,
158
- max_increment_times=self.max_increment_times, increment_buffer=self.increment_buffer,
159
- dense_gps=self.dense_gps, dense_interval=self.dense_interval,
160
- dwell_l_length=self.dwell_l_length, dwell_n=self.dwell_n)
157
+ try:
158
+ gps_obj = GpsPointsGdf(gps_points_df=_gps_df, time_format=self.time_format,
159
+ buffer=self.gps_buffer, time_unit=self.time_unit,
160
+ plane_crs=self.plain_crs,
161
+ max_increment_times=self.max_increment_times,
162
+ increment_buffer=self.increment_buffer,
163
+ dense_gps=self.dense_gps, dense_interval=self.dense_interval,
164
+ dwell_l_length=self.dwell_l_length, dwell_n=self.dwell_n)
165
+ except Exception as e:
166
+ print('构建按GPS对象出错...')
167
+ print(repr(e))
168
+ self.error_list.append(agent_id)
169
+ continue
170
+
161
171
  del _gps_df
162
172
 
163
- if self.del_dwell:
164
- gps_obj.del_dwell_points()
173
+ # gps-process
174
+ try:
175
+ if self.del_dwell:
176
+ print(rf'gps-preprocessing: del dwell')
177
+ gps_obj.del_dwell_points()
178
+
179
+ # 降频处理
180
+ if self.is_lower_f:
181
+ print(rf'gps-preprocessing: lower frequency, size: {self.lower_n}')
182
+ gps_obj.lower_frequency(n=self.lower_n)
165
183
 
166
- # 降频处理
167
- if self.is_lower_f:
168
- print(rf'lower {self.lower_n} - frequency')
169
- gps_obj.lower_frequency(n=self.lower_n)
184
+ if self.is_rolling_average:
185
+ print(rf'gps-preprocessing: rolling average, window size: {self.rolling_window}')
186
+ gps_obj.rolling_average(window=self.rolling_window)
170
187
 
171
- if self.is_rolling_average:
172
- print(rf'rolling average by window size - {self.rolling_window}')
173
- gps_obj.rolling_average(window=self.rolling_window)
188
+ if self.dense_gps:
189
+ print(rf'gps-preprocessing: dense gps by interval: {self.dense_interval}m')
190
+ gps_obj.dense()
191
+ except Exception as e:
192
+ print(rf'gps数据预处理出错:{repr(e)}')
193
+ self.error_list.append(agent_id)
194
+ continue
174
195
 
175
- if self.dense_gps:
176
- print(rf'dense gps by interval - {self.dense_interval}m')
177
- gps_obj.dense()
196
+ if len(gps_obj.gps_gdf) <= 1:
197
+ print(r'经过数据预处理后GPS观测点数据不足2个')
198
+ self.error_list.append(agent_id)
199
+ continue
178
200
 
179
201
  # 依据当前的GPS数据(源数据)做一个子网络
180
202
  if self.use_sub_net:
@@ -199,15 +221,39 @@ class MapMatch(object):
199
221
  top_k=self.top_k, omitted_l=self.omitted_l)
200
222
 
201
223
  # 求解参数
202
- is_success = hmm_obj.generate_markov_para(add_single_ft)
224
+ try:
225
+ is_success = hmm_obj.generate_markov_para(add_single_ft)
226
+ except Exception as e:
227
+ print(rf'解算HMM参数出错:{repr(e)}')
228
+ is_success = False
203
229
  if not is_success:
230
+ self.error_list.append(agent_id)
204
231
  continue
205
- hmm_obj.solve()
206
- _match_res_df = hmm_obj.acquire_res()
232
+
233
+ # 求解模型
234
+ try:
235
+ hmm_obj.solve()
236
+ except Exception as e:
237
+ print(rf'求解HMM模型出错:{repr(e)}')
238
+ self.error_list.append(agent_id)
239
+ continue
240
+
241
+ # 获取结果
242
+ try:
243
+ _match_res_df = hmm_obj.acquire_res()
244
+ except Exception as e:
245
+ print(rf'获取匹配结果出错:{repr(e)}')
246
+ self.error_list.append(agent_id)
247
+ continue
248
+ if self.instant_output:
249
+ _match_res_df.to_csv(os.path.join(self.out_fldr, rf'{agent_id}_match_res.csv'),
250
+ encoding='utf_8_sig', index=False)
251
+ else:
252
+ match_res_df = pd.concat([match_res_df, _match_res_df])
253
+
207
254
  hmm_obj.format_war_info()
208
255
  if hmm_obj.is_warn:
209
256
  self.may_error_list[agent_id] = hmm_obj.format_warn_info
210
- match_res_df = pd.concat([match_res_df, _match_res_df])
211
257
 
212
258
  # if export files
213
259
  if self.export_html or self.export_geo_res:
@@ -216,8 +262,9 @@ class MapMatch(object):
216
262
  export_visualization(hmm_obj_list=hmm_res_list, use_gps_source=self.use_gps_source,
217
263
  export_geo=self.export_geo_res, export_html=self.export_html,
218
264
  gps_radius=self.gps_radius, export_all_agents=self.export_all_agents,
219
- out_fldr=self.html_fldr, flag_name=self.flag_name,
220
- multi_core_save=self.multi_core_save)
265
+ out_fldr=self.out_fldr, flag_name=self.flag_name,
266
+ multi_core_save=self.multi_core_save, sub_net_buffer=self.sub_net_buffer,
267
+ dup_threshold=self.dup_threshold)
221
268
  del hmm_res_list
222
269
  hmm_res_list = []
223
270
 
@@ -232,11 +279,11 @@ class MapMatch(object):
232
279
  pool = multiprocessing.Pool(processes=n)
233
280
  result_list = []
234
281
  for i in range(0, n):
235
- core_html_fldr = os.path.join(self.html_fldr, rf'core{i}')
236
- if os.path.exists(core_html_fldr):
282
+ core_out_fldr = os.path.join(self.out_fldr, rf'core{i}')
283
+ if os.path.exists(core_out_fldr):
237
284
  pass
238
285
  else:
239
- os.makedirs(core_html_fldr)
286
+ os.makedirs(core_out_fldr)
240
287
 
241
288
  agent_id_list = agent_group[i]
242
289
  gps_df = self.gps_df[self.gps_df[gps_field.AGENT_ID_FIELD].isin(agent_id_list)]
@@ -254,7 +301,7 @@ class MapMatch(object):
254
301
  dup_threshold=self.dup_threshold, is_rolling_average=self.is_rolling_average,
255
302
  window=self.rolling_window,
256
303
  export_html=self.export_html,
257
- use_gps_source=self.use_gps_source, html_fldr=core_html_fldr,
304
+ use_gps_source=self.use_gps_source, out_fldr=core_out_fldr,
258
305
  export_geo_res=self.export_geo_res,
259
306
  node_num_threshold=self.node_num_threshold,
260
307
  top_k=self.top_k, omitted_l=self.omitted_l, link_width=self.link_width,
@@ -262,7 +309,7 @@ class MapMatch(object):
262
309
  match_link_width=self.match_link_width, gps_radius=self.gps_radius,
263
310
  export_all_agents=self.export_all_agents,
264
311
  visualization_cache_times=self.visualization_cache_times,
265
- multi_core_save=False)
312
+ multi_core_save=False, instant_output=self.instant_output)
266
313
  result = pool.apply_async(mmp.execute,
267
314
  args=())
268
315
  result_list.append(result)
@@ -70,7 +70,7 @@ class GpsArray(object):
70
70
  return self.__crs
71
71
 
72
72
  def to_plane_prj(self) -> None:
73
- if self.gps_points_gdf.crs.srs == self.plane_crs:
73
+ if self.gps_points_gdf.crs.srs.upper() == self.plane_crs:
74
74
  self.__crs = self.plane_crs
75
75
  pass
76
76
  else:
@@ -78,7 +78,7 @@ class GpsArray(object):
78
78
  self.__crs = self.plane_crs
79
79
 
80
80
  def to_geo_prj(self) -> None:
81
- if self.gps_points_gdf.crs.srs == self.geo_crs:
81
+ if self.gps_points_gdf.crs.srs.upper() == self.geo_crs:
82
82
  self.__crs = self.geo_crs
83
83
  pass
84
84
  else:
@@ -57,10 +57,13 @@ class GpsTrip(GpsArray):
57
57
  # 时间差和距离差
58
58
  group_gps_gdf[next_time_field] = group_gps_gdf[time_field].shift(-1).fillna(group_gps_gdf[time_field])
59
59
  group_gps_gdf[next_p_field] = group_gps_gdf[geometry_field].shift(-1).fillna(group_gps_gdf[geometry_field])
60
- group_gps_gdf[time_gap_field] = group_gps_gdf.apply(
61
- lambda row: (row[next_time_field] - row[time_field]).seconds, axis=1)
62
- group_gps_gdf[dis_gap_field] = group_gps_gdf.apply(
63
- lambda row: row[next_p_field].distance(row[geometry_field]), axis=1)
60
+ group_gps_gdf[time_gap_field] = group_gps_gdf[next_time_field] - group_gps_gdf[time_field]
61
+ group_gps_gdf[time_gap_field] = group_gps_gdf[time_gap_field].apply(lambda t: t.seconds)
62
+ group_gps_gdf[dis_gap_field] = group_gps_gdf[next_p_field].distance(group_gps_gdf[geometry_field])
63
+ # group_gps_gdf[time_gap_field] = group_gps_gdf.apply(
64
+ # lambda row: (row[next_time_field] - row[time_field]).seconds, axis=1)
65
+ # group_gps_gdf[dis_gap_field] = group_gps_gdf.apply(
66
+ # lambda row: row[next_p_field].distance(row[geometry_field]), axis=1)
64
67
 
65
68
  # 切分主行程
66
69
  group_gps_gdf['main_label'] = (group_gps_gdf[time_gap_field] > self.group_gap_threshold).astype(int)
@@ -35,7 +35,7 @@ class Route2Gps(object):
35
35
  :return:
36
36
  """
37
37
 
38
- assert path_gdf.crs.srs == 'EPSG:4326'
38
+ assert path_gdf.crs.srs.upper() == 'EPSG:4326'
39
39
  assert len(path_o_time_df) >= 1
40
40
  assert {path_id_field, seq_field, time_cost_field, geometry_field}.issubset(set(path_gdf.columns))
41
41
  assert {path_id_field, o_time_field}.issubset(set(path_o_time_df.columns))
@@ -87,6 +87,7 @@ class GpsPointsGdf(object):
87
87
  except ValueError:
88
88
  self.__gps_points_gdf[gps_field.TIME_FIELD] = \
89
89
  pd.to_datetime(self.__gps_points_gdf[gps_field.TIME_FIELD], unit=time_unit)
90
+
90
91
  self.__gps_points_gdf.sort_values(by=[gps_field.TIME_FIELD], ascending=[True], inplace=True)
91
92
  self.__gps_points_gdf[gps_field.POINT_SEQ_FIELD] = [i for i in range(len(self.__gps_points_gdf))]
92
93
  self.__gps_points_gdf[gps_field.ORIGIN_POINT_SEQ_FIELD] = self.__gps_points_gdf[gps_field.POINT_SEQ_FIELD]
@@ -152,15 +153,20 @@ class GpsPointsGdf(object):
152
153
  # 距离差
153
154
  self.__gps_points_gdf[next_p_field] = self.__gps_points_gdf[geometry_field].shift(-1).fillna(
154
155
  self.__gps_points_gdf[geometry_field])
155
- self.__gps_points_gdf[dis_gap_field] = self.__gps_points_gdf.apply(
156
- lambda row: row[next_p_field].distance(row[geometry_field]), axis=1)
156
+ # self.__gps_points_gdf[dis_gap_field] = self.__gps_points_gdf.apply(
157
+ # lambda row: row[next_p_field].distance(row[geometry_field]), axis=1)
158
+ self.__gps_points_gdf[dis_gap_field] = self.__gps_points_gdf[next_p_field].distance(
159
+ self.__gps_points_gdf[geometry_field])
157
160
 
158
161
  def calc_adj_time_gap(self) -> None:
159
162
  # 时间差
160
163
  self.__gps_points_gdf[next_time_field] = self.__gps_points_gdf[time_field].shift(-1).fillna(
161
164
  self.__gps_points_gdf[time_field])
162
- self.__gps_points_gdf[time_gap_field] = self.__gps_points_gdf.apply(
163
- lambda row: (row[next_time_field] - row[time_field]).seconds, axis=1)
165
+ # self.__gps_points_gdf[time_gap_field] = self.__gps_points_gdf.apply(
166
+ # lambda row: (row[next_time_field] - row[time_field]).seconds, axis=1)
167
+ self.__gps_points_gdf[time_gap_field] = self.__gps_points_gdf[next_time_field] - self.__gps_points_gdf[
168
+ time_field]
169
+ self.__gps_points_gdf[time_gap_field] = self.__gps_points_gdf[time_gap_field].apply(lambda x: x.seconds)
164
170
 
165
171
  def calc_pre_next_dis(self) -> pd.DataFrame():
166
172
  self.calc_adj_dis_gap()
@@ -289,14 +295,10 @@ class GpsPointsGdf(object):
289
295
 
290
296
  def get_gps_array_buffer(self, buffer: float = 200.0, dup_threshold: float = 10.0) -> Polygon or None:
291
297
  """输出gps路径的buffer范围面域"""
292
- if len(self.__gps_points_gdf) <= 1:
293
- print(r'经过数据预处理后GPS观测点数据不足2个')
294
- return None
295
- else:
296
- gps_route_l = gpd.GeoSeries(LineString(self.__gps_points_gdf[gps_field.GEOMETRY_FIELD].to_list()))
297
- simplify_gps_route_l = gps_route_l.remove_repeated_points(dup_threshold)
298
- gps_array_buffer = simplify_gps_route_l[0].buffer(buffer)
299
- return gps_array_buffer
298
+ gps_route_l = gpd.GeoSeries(LineString(self.__gps_points_gdf[gps_field.GEOMETRY_FIELD].to_list()))
299
+ simplify_gps_route_l = gps_route_l.remove_repeated_points(dup_threshold)
300
+ gps_array_buffer = simplify_gps_route_l[0].buffer(buffer)
301
+ return gps_array_buffer
300
302
 
301
303
  def generate_candidate_link(self, net: Net = None) -> tuple[pd.DataFrame, list[int]]:
302
304
  """
@@ -305,7 +307,7 @@ class GpsPointsGdf(object):
305
307
  :return: GPS候选路段信息, 未匹配到候选路段的gps点id
306
308
  """
307
309
  gps_buffer_gdf = self.__gps_points_gdf[[gps_field.POINT_SEQ_FIELD, gps_field.GEOMETRY_FIELD]].copy()
308
- if gps_buffer_gdf.crs.srs != self.plane_crs:
310
+ if gps_buffer_gdf.crs.srs.upper() != self.plane_crs:
309
311
  gps_buffer_gdf = gps_buffer_gdf.to_crs(self.plane_crs)
310
312
 
311
313
  single_link_gdf = net.get_link_data()[[net_field.SINGLE_LINK_ID_FIELD, net_field.FROM_NODE_FIELD,
@@ -344,7 +346,7 @@ class GpsPointsGdf(object):
344
346
  return candidate_link, remain_gps_list
345
347
 
346
348
  def to_plane_prj(self) -> None:
347
- if self.__gps_points_gdf.crs.srs == self.plane_crs:
349
+ if self.__gps_points_gdf.crs.srs.upper() == self.plane_crs:
348
350
  self.__crs = self.plane_crs
349
351
  pass
350
352
  else:
@@ -352,7 +354,7 @@ class GpsPointsGdf(object):
352
354
  self.__crs = self.plane_crs
353
355
 
354
356
  def to_geo_prj(self) -> None:
355
- if self.__gps_points_gdf.crs.srs == self.geo_crs:
357
+ if self.__gps_points_gdf.crs.srs.upper() == self.geo_crs:
356
358
  self.__crs = self.geo_crs
357
359
  pass
358
360
  else: