为什么在与 Google 地图进行比较时,我从 OSMnx 或 networkx 得到的长度和行程时间不同?

问题描述 投票:0回答:1

我刚接触 OSM 数据、OSMnx 和 networkx 库,因此如果有更好的方法来实现从 A 到 B 位置的最短路径,我将不胜感激。

我正在尝试获取从 A 到 B 的最短路径。我成功获取了路径,但与 Google 地图返回的结果相比,长度和时间旅行有很大不同。
1. 为什么路径长度和旅行时间与Google Maps / Bing Maps有很大不同?
2. 如何提高准确率?

使用的地址: 3115 W 班克罗夫特街,托莱多,俄亥俄州 43606 6721 怀特福德中心路,兰伯特维尔,密歇根州 48144

OSMnx length = 9135 mts, travel time = 8.3 min.
Google Maps length = 9334.2 mts, travel time = 12 min.
BingMaps length = 9334.2 mts, travel time = 13 min.
Difference in distance is 199.2 mts and aprox ~ 5 min
import sys
import osmnx as ox
import networkx as nx
from shapely.geometry import box, Point
ox.config(use_cache=True, log_console=True)

def geocode(address):
    """Geocode an address using OSMnx."""
    try:
        x, y = ox.geocode(address)
    except Exception as e:
        print(f'Error: {str(e)}')
        return None, None
    return x, y

def boundary_constructor(orig_x, orig_y, dest_x, dest_y):
    """Create a bounding box around two points."""
    boundary_box = Point(orig_y, orig_x).buffer(0.001).union(Point(dest_y, dest_x).buffer(0.001)).bounds
    minx, miny, maxx, maxy = boundary_box
    bbox = box(*[minx, miny, maxx, maxy])
    return bbox

def getting_osm(bbox, network_type, truncate_edges):
    """Retrieve OSM data (roads, edges, nodes) for a given bounding box and network type."""
    G = ox.graph_from_polygon(bbox, retain_all=False, network_type=network_type, truncate_by_edge=truncate_edges)
    G = ox.add_edge_speeds(G)
    G = ox.add_edge_travel_times(G)
    roads = ox.graph_to_gdfs(G, nodes=False, edges=True)
    return G, roads

def find_closest_node(G, lat, lng, distance):
    """Find the closest node in a graph to a given latitude and longitude."""
    node_id, dist_to_loc = ox.distance.nearest_nodes(G, X=lat, Y=lng, return_dist=distance)
    return node_id, dist_to_loc

def shortest_path(G, orig_node_id, dest_node_id, weight):
    """Find the shortest path between two nodes in a graph."""
    try:
        route = ox.shortest_path(G, orig_node_id, dest_node_id, weight=weight)
    except nx.NetworkXNoPath as e:
        print(f"No path found between {orig_node_id} and {dest_node_id}")
        print(e)
    return route

def find_length_and_time(G, travel_length, travel_time):
    try:
        route_length = int(sum(ox.utils_graph.route_to_gdf(G, travel_length, "length")["length"]))
        route_time = int(sum(ox.utils_graph.route_to_gdf(G, travel_time, "travel_time")["travel_time"]))
    except Exception as e:
        print(f'Error: {e}')
    return route_length, route_time
    

def route_plotting(G, travel_length, travel_time):
    """Plot the shortest path between two addresses."""
    if travel_length and travel_time:
        fig, ax = ox.plot_graph_routes(
            G,
            routes=[travel_length, travel_time],
            route_colors=["r", "y"],
            route_linewidth=6,
            node_size=0
        )
    elif travel_length:
        ox.plot_route_folium(G, travel_length, popup_attribute='length')
    elif travel_time:
        ox.plot_route_folium(G, travel_time, popup_attribute='travel_time')

def main():
    # User address input
    origin_address = str(input('Enter the origin address: '))
    destination_address = str(input('Enter the destination adddress: '))
    # Geocode addresses
    orig_x, orig_y = geocode(origin_address)
    dest_x, dest_y = geocode(destination_address)
    # Check if geocoding was successful
    if not all([orig_x, orig_y, dest_x, dest_y]):
        print("Unable to geocode one or both addresses. Exiting...")
        sys.exit()
    # Create bounding box
    bbox = boundary_constructor(orig_x, orig_y, dest_x, dest_y) 
    # Retrieve OSM data
    G, roads = getting_osm(bbox, network_type='drive', truncate_edges='True')
    # Find closest node
    orig_node_id, dist_to_orig = find_closest_node(G, orig_y, orig_x, True)
    dest_node_id, dist_to_dest = find_closest_node(G, dest_y, dest_x, True)
    # find shortest path
    travel_length = shortest_path(G, orig_node_id, dest_node_id, weight='length')
    travel_time = shortest_path(G, orig_node_id, dest_node_id, weight='travel_time')
    # find route length and route time
    route_length, route_time = find_length_and_time(G, travel_length, travel_time)
    if route_length and route_time:
        print(f"Shortest travel length:{route_length: .2f} meters and takes {(route_time/60)} minutes") 
    elif route_length:
        print(f"Shortest travel length: {route_length: .2f}. No travel time found")
    elif route_time:
        print(f"Shortest travel time: {(route_time/60)}. No travel length found")
    # plot routes
    route_plotting(G, travel_length, travel_time)


if __name__ == "__main__":
    main()
networkx data-analysis openstreetmap shortest-path osmnx
1个回答
0
投票

为什么 Google 地图和 Bing 地图的路径长度和旅行时间如此不同?

从广义上讲,它是那些拥有更好数据和更好算法的地图提供商的某种组合。

从数据开始,开放街道地图中的大多数街道都没有标注最大法定速度。对于这些街道中的任何一条,OSMnx 都会尝试通过查看“高速公路类型”以及具有最大速度注释的相同高速公路类型的道路来猜测最大速度。 (来源。)假设是,如果一个城市的平均住宅街道的最高速度为 20 英里/小时,那么没有已知速度限制的住宅街道的最高速度可能为 20 英里/小时。当然,这个假设并不总是正确的,如果知道实际速度,您的路线计划将会更好。 为了改进这一点,如果您知道您管辖范围内未张贴街道的速度限制,您可以向

hwy_speeds

提供

add_edge_speeds()
参数。
这就涉及到下一个问题,那就是人们并不总是按照限速行驶。有时他们开得更快,或者有时交通堵塞,他们必须放慢速度。如果没有一些带有交通信息的数据源,这个问题很难解决。

另一个问题是 OSMnx 假设所有交叉点都需要零秒才能穿过。 OSM 用于查找最快路线的算法不允许交叉路口(或节点)有任何行驶时间。即使这不是问题,人们也需要计算出穿过十字路口需要多长时间。 (要解决这个问题,您需要考虑一些问题:这个十字路口有红绿灯吗?这是右转还是左转?您有优先通行权吗?)

总结来说,有四个因素会导致行程时间不同:

用该类别的平均速度来估算速度未知的街道
  • 超速行驶的司机
  • 交通
  • 假设交叉路口不需要时间
  • 在这四个因素中,其中两个可能会导致低估旅行时间。其中之一可能会导致高估。其中一个可能会影响您对任一方向的估计。根据我的经验,OSMnx 通常会低估旅行时间。

© www.soinside.com 2019 - 2024. All rights reserved.