You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:37:13