做GIS的人都知道,传统空间分析是在点线面上做文章;做图神经网络的人都知道,GNN吃的是图——节点带特征、边带权重。中间这一步,把「空间数据」翻译成「图结构」,长期是个手工活:先把POI落节点,再算两两距离定边,再把路网叠进去,最后导出成PyG的Tensor。
City2Graph把这一步封成了几行函数调用。本文拿济南趵突泉周边实测:1200个POI、4529条道路、8803栋建筑,跑通固定半径图、Waxman随机图、城市形态图、异构图转PyG全流程。
目录
一、City2Graph是什么
1.1它解决什么问题
1.2三个核心函数
二、数据准备:趵突泉周边的三栖数据
2.1三类数据清单
2.2数据获取的细节
三、fixed_radiusvsWaxman:四种连边方式对比
3.1四种图结构对比
3.1.1 对比数据
3.1.3 程序
3.1.3 出图对比
3.2两个值得注意的点
3.3四种图分别适合什么场景
四、morphological 500m:城市形态学图
4.1什么是morphological图
4.2从图上读出的五个结论
4.3空间结构诊断与改造建议
五、一行转PyGHeteroData:GIS到GNN的最后一公里
5.1 HeteroData长什么样
5.2转完之后能跑什么分析
六、什么时候用、什么时候别用
一、City2Graph是什么
1.1它解决什么问题
City2Graph是利物浦大学YutaSato团队2026年开源的GeoAI图库(BSD-3-Clause,GitHub约1.9kstar),对应论文发表在Computers,EnvironmentandUrbanSystems。
它解决一件事:把城市里多源的空间数据(POI点、道路线、建筑面、GTFS公交线路、共享单车OD)统一转成图结构,并且在三种数据格式之间互转——GeoPandasGeoDataFrame(GIS世界)、NetworkX(图算法世界)、PyGHeteroData(深度学习世界)。
1.2三个核心函数
关键函数三个:fixed_radius_graph(固定半径连边)、waxman_graph(随机几何图)、morphological_graph(城市形态学图)。加上gdf_to_pyg一行转PyG。
二、数据准备:趵突泉周边的三栖数据
2.1三类数据清单
测试范围选济南泉城广场周边1.2公里,实际POI集中在趵突泉片区。三类数据全部国内可获取:
数据 | 来源 | 数量 | 用途 |
POI兴趣点 | 高德 | 1200个(6类×200) | 图节点 |
道路网 | OvertureMaps | 4529条segments | network距离/morphological障碍物 |
建筑轮廓 | OvertureMaps | 8803栋 | morphological图节点 |
表1趵突泉周边实测数据清单
2.2数据获取的细节
- POI用高德个人key按餐饮、购物、风景名胜、医疗、住宿、生活服务六类各拉200条
- 数据坐标系一致需要转WGS-84;
3、道路和建筑都来自OvertureMaps2024开放数据集,city2graph的load_overture_data函数直接按bbox拉parquet。
三、fixed_radiusvsWaxman:四种连边方式对比
3.1四种图结构对比
3.1.1 对比数据
同样1200个POI,换四种连边规则,图结构差异巨大。
图类型 | 距离口径 | 节点 | 边数 | 图特征 |
fixed_radius100m | 欧氏 | 1200 | 22,521 | 硬阈值,边数最多 |
waxmaneuclidean | 欧氏随机 | 1200 | 14,808 | 中密度 |
waxmanmanhattan | 曼哈顿 | 1200 | 10,886 | 网格距离,边较少 |
waxmannetwork | 沿道路 | 1200 | 5,586 | 真实距离最长,边最少 |
表2四种图结构对比
3.1.3 核心程序
fixed_radius100m
fr_nodes, fr_edges = c2g.fixed_radius_graph(poi_m, radius=100, distance_metric="euclidean")waxmaneuclidean
w_eu_nodes, w_eu_edges = c2g.waxman_graph(poi_m, beta=0.5, r0=100, distance_metric="euclidean", seed=42)waxmanmanhattan
w_ma_nodes, w_ma_edges = c2g.waxman_graph(poi_m, beta=0.5, r0=100, distance_metric="manhattan", seed=42)waxmannetwork
w_nt_nodes, w_nt_edges = c2g.waxman_graph( poi_m, beta=0.5, r0=100, distance_metric="network", network_gdf=edges_m, network_weight="length", seed=42 )3.1.3 出图对比
固定半径(红)、欧氏Waxman(橙)、曼哈顿Waxman(黄)、沿道路Waxman(蓝)
图1四种连边方式对比
3.2两个值得注意的点
两个值得注意的点:
第一,曼哈顿距离的边数比欧氏少近30%。原因是曼哈顿距离对同样半径,「实际覆盖范围」是菱形而非圆形,在网格城市里邻居数天然偏少。
第二,沿道路连边后边数最少(5586),只有固定半径图的四分之一。原因是沿道路最短路径距离天然比直线距离长——两个POI直线200m,沿路可能要走400m,Waxman概率P=0.5·exp(-d/100)下,d越大连边概率越低。这就是「直线距离」和「步行可达性」的本质差异。
3.3四种图分别适合什么场景
四种图分别适合什么场景:
图类型 | 边数 | 适合场景 | 不适合 |
fixed_radius | 22,521 | 商圈覆盖、学区划片、15分钟生活圈等政策硬分析 | 真实步行可达性评估 |
waxmaneuclidean | 14,808 | GNN冷启动、POI相似度建模、快速实验 | 有明显河流/铁路阻隔的城市 |
waxmanmanhattan | 10,886 | 老城区网格街区模拟、步行距离近似 | 地形起伏、弯道多的城市 |
waxmannetwork | 5,586 | 商业选址、外卖配送范围、真实步行可达性 | 万级以上节点(all-pairs最短路耗时剧增) |
表3四种图的适用场景
一句话:做商业分析用network,做快速实验用euclidean,做政策硬分析用fixed_radius。
四、morphological500m:城市形态学图
4.1什么是morphological图
前三张图都是POI自己和自己连边。morphological_graph不一样——它用建筑面和道路段当「障碍物」,把城市空间切成两类节点:place(建筑围合出来的开放空间)和movement(街道本身),再连三种边:place相邻(touched_to)、街道连通(connected_to)、空间面向街道(faced_to)。
morphological代码:
nodes_dict, edges_dict = c2g.morphological_graph( buildings_gdf=buildings, segments_gdf=segments_m, center_point=center, distance=500, keep_buildings=True, keep_segments=True, )彩色点=place,灰线=道路
图2趵突泉周边morphological图
500m半径内跑出243个place、66条movement、共1037条边。这不是POI图,是「城市空间结构」图——它回答的问题是:这个商圈有几个开放空间、哪几条街把它们串起来。TOP10彩色标注,灰色=孤立place(115个)
图3院落群空间分布
4.2从图上读出的五个结论
从数据可以看出五个结论:
1)核心区主要院落群挤在不到1平方公里内,空间非常密集。
2)最大群(22个place)在核心区西北边缘,不在正中心。空间重心偏西,东边反而是小群。
3)南边有一整群独立院落(9个place),和核心区隔了约500m空白带,没有任何连通边——这是图上最明显的断裂带。
4)243个place里有115个是孤立点(灰色),占47%。近一半开放空间没有邻居,空间是碎的。
5)西边(群1/2/3/8)规模大,东边(群4/5/6/10)规模中等,没有一个群是压倒性主群——是多中心结构。
4.3空间结构诊断与改造建议
空间结构诊断:
问题1:近一半空间是孤立点。115个place没有任何touched_to邻居,说明开放空间被道路/建筑切割得很碎,没有形成连续的步行界面。
问题2:南边断裂带。核心区和南边独立群之间有500m宽的空白带,没有连通——两边的人流走不到一起。
问题3:最大群在边缘不在中心。22个place的最大群在西北边缘,说明核心区正中心的空间连通性反而不如边缘。
改造建议(图上能直接指出来的):
建议1:打通西北边缘的最大群(群1,22place)和中部群(群3,15place)。两个群隔得最近但没有连通边,打通后能合并成37place的超级院落群。
建议2:在南边断裂带(核心区和独立群之间500m空白)加一条步行连通通道,把南北两边的空间串起来。
建议3:把115个孤立点里位置相邻的几个先连起来,降低孤立点比例——孤立点越多,人流越散。
五、一行转PyGHeteroData:GIS到GNN的最后一公里
5.1HeteroData长什么样
所有图最终要落到PyG上训练。City2Graph一行gdf_to_pyg直接出HeteroData:
我们把POI(1200个)和建筑(8803栋)作为两类节点,bridge_nodes用knn=5把每个POI连到最近的5栋建筑,得到6000条(poi,is_nearby,building)边。gdf_to_pyg输出的HeteroData长这样:
HeteroData(
poi={x=[1200,0],pos=[1200,2]},
building={x=[8803,0],pos=[8803,2]},
(poi,is_nearby,building)={edge_index=[2,6000]},
(building,rev_is_nearby,poi)={edge_index=[2,6000]}
)
注意两点:一是自动生成了反向边rev_is_nearby,GNN训练时双向消息传递不用自己写;二是x目前是0维(没塞特征),把POI类型one-hot、建筑层高/屋顶形状灌进去,就是[1200,6]和[8803,3],直接能跑GCN。
pyg_to_nx回环也通:GeoPandas→NetworkX→PyG三方互转闭环。
5.2转完之后能跑什么分析
转完HeteroData之后能跑什么分析?
现在x=[1200,0]是空特征,灌三类特征进去就能跑GNN:POI类型one-hot(6类→[1200,6])、建筑面积/层高(→[8803,3])、图结构特征(节点度、中心度)。三个可直接落地的分析:
分析:图嵌入(商圈子群发现)。
- 用GraphSAGE把1200个POI降到2维,实际跑出来6类POI完全分成了6个独立簇。
- 右图——embedding同时学到了空间位置:颜色越黄越北、越紫越南,和实际纬度对应。这说明GNN不只是分类,还能把「业态」和「空间」两个维度同时编码进二维向量里。
转换程序:
nodes, edges = c2g.waxman_graph(poi, beta=0.5, r0=100, distance_metric="euclidean", seed=42)左图按POI类型着色(6类完全分开),右图按纬度着色(颜色渐变和空间位置对应)
图4 GraphSAGE2D嵌入
本次实测跑通了全流程:GeoPandas数据→四种图结构→morphological空间分析→PyGHeteroData→GraphSAGE嵌入。从GIS到GNN的最后一公里,City2Graph确实把手工活封成了几行函数。
六、什么时候用、什么时候别用
适合的场景:商圈活力分析(POI图)、步行可达性(network距离)、城市空间结构(morphological)、把已有GIS数据快速喂给GNN做选址/分类预测。
不适合的场景:大区域(全国级)图——1200个POI已经跑出2.2万边,10万节点就是百万边级别,内存吃紧;需要精确交通阻抗的——network模式用的是道路长度,不是真实驾车时间;建筑和道路数据国内依赖OvertureMaps,小地块可能不全。