在R中构建sfnetwork时遇报错:顶点数不可为负
构建sfnetworks道路网络时遭遇"Number of vertices must not be negative"错误
我用R的sfnetworks包构建伦敦道路网络,运行创建网络的代码时触发错误。相关数据已通过Python预处理并保存为GeoJSON,以下是详细信息:
R代码及数据处理流程
数据读取
# Read in Data ## London borough boundary LondonBoroughs <- st_read(here::here('data', 'boundary', 'London_Borough_Excluding_MHW.shp')) %>% st_transform(., 27700) ## street nodes street_nodes <- st_read(here::here('data', 'cleaned_nodes.geojson')) %>% st_transform(., 27700) ## street edges street_edges <- st_read(here::here('data', 'cleaned_edges.geojson')) %>% st_transform(., 27700)
数据结构
- street_nodes:以
osmid(int64)为行索引,包含列:y(float64)、x(float64)、highway(object)、ref(object)、geometry(geometry) - street_edges:包含列:
u(int64)、v(int64)、key(int64)、osmid(object)、oneway(boolean)、length(float64)、from(int64)、to(int64)、junction(object)、area(object)、landuse(object)、geometry(geometry)
数据清洗
# Data cleaning ## remove duplicate street nodes - no duplicates street_nodes <- street_nodes %>% distinct() ## street nodes within London boundary street_nodes <- street_nodes[LondonBoroughs, ] ## street edges within London boundary street_edges <- street_edges[LondonBoroughs, ] ## remove duplicate street edges - no duplicates street_edges <- street_edges %>% distinct()
创建网络的代码(触发错误)
# create network net = sfnetwork(street_nodes, street_edges, directed = FALSE)
错误信息
Error in (function (edges, n = max(edges), directed = TRUE) :
At core/graph/type_indexededgelist.c:117 : Number of vertices must not be negative. Invalid value
Python预处理流程
数据通过OSMnx获取并预处理后保存,代码如下:
import os import wget import osmnx as ox import geopandas as gpd # bounding box of London bbox = (-0.5108706, 51.28117, 0.322123, 51.68948) # get road network and save as .shp G = ox.graph_from_bbox(bbox[3], bbox[1], bbox[2], bbox[0], network_type='all') ox.save_graph_shapefile(G, filepath='data/london_street/raw_osm_data', encoding='utf-8') # load as GeoDataFrame nodes = gpd.read_file('data/london_street/raw_osm_data/nodes.shp') edges = gpd.read_file('data/london_street/raw_osm_data/edges.shp') # node column rename nodes.rename(columns = {'street_cou' : 'street_count'}, inplace = True) # replace 'None' to empty string in node data nodes.fillna("",inplace=True) cleaned_nodes = nodes.copy() cleaned_nodes.set_index('osmid', inplace = True) cleaned_nodes.head(3) # replace 'None' to empty string in edge data edges.fillna("",inplace=True) # select columns of interest cleaned_edges = edges[['u', 'v', 'key', 'osmid', 'oneway', 'length', 'from', 'to', 'junction', 'area', 'landuse', 'geometry']].copy() cleaned_edges.head(1) # convert 'oneway' datatype to boolean cleaned_edges['oneway'] = cleaned_edges['oneway'].astype(bool) # save the cleaned nodes and edges file_path_nodes = "data/london_street/cleaned_osm_data/cleaned_nodes.geojson" cleaned_nodes.to_file(file_path_nodes, driver = "GeoJSON") file_path_edges = "data/london_street/cleaned_osm_data/cleaned_edges.geojson" cleaned_edges.to_file(file_path_edges, driver = "GeoJSON")
已尝试的解决方法
将边数据的to、from列及节点数据的osmid列转为字符类型,仍出现相同报错。
解决方案
该错误核心原因是边数据引用了节点数据中不存在的顶点ID,或是节点索引与边的u/v列类型不匹配,可按以下步骤解决:
1. 检查边与节点的ID匹配情况
运行代码找出边中存在但节点里没有的u/v值:
# 提取节点的osmid(节点以osmid为索引,转成整数向量) node_ids <- rownames(street_nodes) %>% as.integer() # 检查边的u列中不在节点ID里的值 missing_u <- setdiff(street_edges$u, node_ids) # 检查边的v列中不在节点ID里的值 missing_v <- setdiff(street_edges$v, node_ids) # 查看缺失的ID数量 cat("Missing u IDs count:", length(missing_u), "\n") cat("Missing v IDs count:", length(missing_v), "\n")
若存在缺失值,说明裁剪节点到伦敦边界时,误删了边仍在引用的节点,导致边的顶点无对应节点。
2. 清理无效边
删除引用不存在节点的边:
# 筛选出u和v都在节点ID中的有效边 valid_edges <- street_edges %>% filter(u %in% node_ids, v %in% node_ids) # 重新创建网络 net <- sfnetwork(street_nodes, valid_edges, directed = FALSE)
3. 确保节点索引与边的ID类型一致
GeoJSON保存可能改变索引类型,建议将节点的osmid转为显式列,避免类型不匹配:
# 把节点的索引转为列 street_nodes <- street_nodes %>% mutate(osmid = rownames(.) %>% as.integer()) %>% st_set_geometry("geometry") # 创建网络时指定节点ID列 net <- sfnetwork(street_nodes, valid_edges, node_key = "osmid", directed = FALSE)
4. 替代方案:直接用GraphML格式导入
若上述方法仍有问题,可跳过GeoJSON步骤,用OSMnx导出GraphML格式后直接导入R:
# Python中导出GraphML ox.save_graphml(G, filepath='data/london_street/london_network.graphml')
# R中读取并转为sfnetwork library(sfnetworks) net <- read_graphml(here::here('data', 'london_street', 'london_network.graphml')) %>% as_sfnetwork(directed = FALSE)
内容的提问来源于stack exchange,提问作者Phil
相关产品推荐
相关产品推荐

