如何优化OSMnx旅行时间多边形计算效率?
高效生成荷兰境内500个点位15分钟旅行时间多边形的优化方案
问题描述
我持有荷兰境内500个带经纬度坐标的点位,需要为每个点位生成15分钟驾车旅行时间范围的多边形。目前基于OSMnx、NetworkX和GeoPandas实现了功能,但每个点位都需下载25×25km的bounding box并转换为Multigraph,计算速度极慢。
曾尝试将荷兰路网分割为小块下载并存储为.graphml,合并后文件达2GB,处理时出现内存等问题。现寻求以下方向的解决方案:
- 如何避免重复下载路网?
- 有没有更优的旅行时间多边形计算方法?
- 推荐合适的替代工具库。
现有实现代码
# 选择数据集中的目标行 start = infra_dataframe[i-1:i] # 设置坐标系 start.crs = "EPSG:4326" # 设置旅行时间阈值(秒) distance_value = 900 # 900秒 = 15分钟 # 生成点位缓冲区域(7855为米制坐标系) buffer_value = distance_value*25 # 放大倍数确保覆盖所有可达区域 buffer_home = start.to_crs(epsg=7855).buffer(buffer_value).to_crs(epsg=4326) # 获取缓冲区域的边界框 bounds = buffer_home.bounds.loc[i-1] # 自定义道路过滤规则 cf = '["highway"~"motorway|motorway_link|trunk|trunk_link|primary|primary_link|secondary|secondary_link|tertiary|tertiary_link|residential|unclassified|living_street|service"]' # 下载边界框内的路网 region = ox.graph_from_bbox(bounds['maxy'], bounds['miny'], bounds['minx'], bounds['maxx'], network_type='drive', custom_filter=cf) # 为路网添加速度和旅行时间属性 G = ox.add_edge_speeds(region) G = ox.add_edge_travel_times(region) # 找到离起点最近的路网节点 center_node = ox.nearest_nodes(G, start['infra.lon'].iloc[0], start['infra.lat'].iloc[0]) # 计算从中心节点到所有节点的最短旅行时间 distances = nx.shortest_path_length(G, source=center_node, weight="travel_time") # 筛选出15分钟内可达的节点 drivable_nodes = {node: dist for node, dist in distances.items() if dist < distance_value} # 生成可达子图 G_reachable = G.subgraph(drivable_nodes.keys()) # 将子图转换为GeoDataFrame gdf_nodes, gdf_edges = ox.graph_to_gdfs(G_reachable) # 自定义函数生成可达区域多边形 reachable_polygon = create_polygon(gdf_nodes) # 将多边形存入GeoDataFrame gdf_reachable = gpd.GeoDataFrame(index=[0], crs='epsg:4326', geometry=[reachable_polygon])
优化方案
一、避免重复下载路网
- 预下载分区路网:不要按单个点位的buffer下载,而是下载覆盖所有500个点位的最小外接区域路网,或按荷兰行政区(如省份)划分成多个子区域,存储为
.graphml文件。计算时直接加载对应子区域的路网,而非重复调用OSMnx下载接口。若全荷兰路网过大,可按点位分布划分重叠子区域,每个子区域覆盖部分点位。 - 添加路网缓存逻辑:用点位的buffer范围作为缓存key,将下载好的graph对象通过
pickle序列化存储。后续遇到相同或重叠的buffer时,直接读取缓存文件,跳过重复下载步骤。
二、优化旅行时间多边形计算流程
- 批量执行可达性计算:若使用全区域路网,利用NetworkX的
nx.multi_source_dijkstra_path_length函数,一次性传入所有点位对应的中心节点列表,批量计算所有节点到这些源点的最短旅行时间,再分别提取每个源点的可达节点,避免逐个点位重复计算。 - 复用路网预处理结果:对加载的路网仅执行一次
add_edge_speeds和add_edge_travel_times操作,不要每个点位都重复处理。 - 优化多边形生成逻辑:自定义
create_polygon函数可能是性能瓶颈,可替换为更高效的实现:- 先用
gdf_nodes.unary_union.convex_hull快速生成凸包,再通过buffer(0)修复拓扑、simplify()简化形状; - 若不需要高精度,可使用可达节点的Voronoi图或Delaunay三角剖分生成多边形,比自定义函数更高效。
- 先用
- 缩小缓冲区域范围:当前
distance_value*25的buffer值(22500米)过大,可根据荷兰道路平均车速调整:按最高限速120km/h计算,15分钟最多行驶30km,但实际驾车不会全程高速,设置15km的buffer已足够覆盖所有可达区域,减少路网规模。
三、替代工具库推荐
- Pyrosm:直接从OSM PBF文件读取路网,支持按区域过滤,下载和加载速度比OSMnx更快,内存占用更低,适合预下载大规模路网并批量处理。
- GraphHopper:可本地部署的路由引擎,支持批量点位的等时线计算,生成旅行时间多边形的效率远高于NetworkX,适合处理500个点位的大规模计算需求。
- Valhalla:开源高性能路由引擎,专门优化了大规模路网的可达性计算,支持批量生成等时线,性能远超纯Python实现的工具。
内容的提问来源于stack exchange,提问作者jmt_r
相关产品推荐
相关产品推荐

