🔗https://doi.org/10.1016/j.compenvurbsys.2026.102495
期刊:Computers, Environment and Urban Systems
发表时间:2026年7月
研究主题:GeoPandas、Python空间分析、矢量数据结构、开源GIS、地理计算
文章类型:软件架构与生态综述
核心内容:GeometryArray、GeoSeries、GeoDataFrame、Shapely、空间索引、空间连接、坐标系统、PyOGRIO、GeoParquet、Dask-GeoPandas
对于很多地理学研究者来说,GeoPandas可能只是Python代码中的一句:
“import geopandas as gpd”。
读取Shapefile、计算缓冲区、空间连接、转换坐标系、叠加分析、绘制地图,这些操作如今似乎已经十分自然。但十多年前,Python中的空间分析并没有这样统一的数据结构。几何对象、属性表、投影信息和文件读写往往由不同工具分别负责,研究者需要自己把它们拼接起来。
这篇发表于Computers, Environment and Urban Systems的文章,由GeoPandas核心开发者团队共同撰写,第一次系统梳理GeoPandas十余年的发展历程、底层数据结构、软件依赖、性能提升、生态系统以及未来方向。
文章最重要的观点可以概括为一句话:
GeoPandas真正重要的地方,不只是提供了一套GIS函数,而是把“空间对象”变成了Python数据科学体系中的标准数据结构。
一旦点、线、面能够像普通表格变量一样进入DataFrame,GIS分析就能够自然连接统计分析、机器学习、网络分析、遥感、城市计算和人工智能。GeoPandas因此逐渐从一个方便处理Shapefile的小工具,演变成Python空间数据科学生态中最底层的基础设施之一。
为什么Python需要一个“空间版DataFrame”?
GeoPandas诞生于2013年。当时Python的数据科学体系已经开始围绕NumPy和pandas快速发展。pandas的DataFrame提供了一种非常直观的数据组织方式:每一行是一个观测对象,每一列是一个变量。
例如,一份住房数据可以表示为:
每一行是一套住房,列中存放价格、面积、房龄和楼层。
但空间数据多了一个关键问题:
一套房、一条道路或者一个行政区,不仅有属性,还有空间形状。
一个公交站可能对应Point,一个道路中心线对应LineString,一个街道或城市边界则对应Polygon。早期Python已经拥有Shapely,可以处理单个几何对象;Fiona可以读取和写入GIS文件;PySAL能够进行空间统计。但这些工具缺少一个统一的数据结构,将几何对象和属性表稳定地组织在一起。
这正是GeoPandas解决的问题。
它沿用了GIS长期形成的经典逻辑:一个地理对象对应一组属性,同时对应一个几何对象。
因此,一张普通pandas表格:
人口|GDP|收入
经过GeoPandas扩展后可以变成:
人口|GDP|收入|geometry
最后一列geometry可以存储点、线、多边形等空间对象。
看似只是增加了一列,实际上这一设计意义很大。因为从此以后,空间数据既保持GIS的几何逻辑,又继承了pandas整套表格分析能力。筛选、分组、合并、统计和缺失值处理可以继续使用熟悉的pandas语法,而空间距离、缓冲区、相交关系和面积计算则通过GeoPandas完成。
GeoPandas真正做的事情,是把GIS世界和Python数据科学世界接了起来。
方法核心:GeoPandas的三层数据结构究竟是什么?
Fig. 1是整篇文章最值得理解的一张图。它展示了GeoPandas内部三个逐层嵌套的数据结构:GeometryArray、GeoSeries和GeoDataFrame。
如果把GeoPandas想象成一栋建筑,GeometryArray相当于地基,GeoSeries是一列真正可供使用的空间数据,GeoDataFrame则是研究者日常操作的完整数据表。
最底层是GeometryArray。
GeometryArray本质上是一维几何数组。里面存放的每一个对象都是Shapely geometry,例如Point、LineString或者Polygon。
用户平时很少直接操作GeometryArray,但大量核心空间能力实际上定义在这一层。它记录整组几何对象的坐标参考系统CRS,同时维护空间索引,并提供矢量化几何运算。
这里的“矢量化”非常重要。
假设我们有100万个建筑多边形,需要计算面积。一种低效做法是在Python中写循环,一个多边形一个多边形地计算。GeoPandas则把整个几何数组交给Shapely,而Shapely进一步调用底层由C/C++实现的GEOS计算库。
因此,表面上看我们写的是简单Python代码:
gdf.geometry.area
背后真正执行几何计算的却是高度优化的底层库。
这也是GeoPandas设计中的一个核心思想:让用户使用简单的Python接口,同时把真正昂贵的计算交给已经非常成熟的底层空间计算引擎。
第二层是GeoSeries。
GeoSeries可以理解为“带空间能力的pandas Series”。普通Series可能是一列房价、一列人口;GeoSeries则是一列几何对象。
GeometryArray负责保存和计算,GeoSeries把这些功能暴露给用户。因此我们才能直接调用面积、距离、质心、凸包、相交判断、旋转、简化等方法。
GeoSeries还负责把坐标参考系统和空间索引暴露出来,并支持地图绘制。
Fig. 2展示了GeoSeries最基础的静态制图能力。只需要调用plot,就可以借助Matplotlib把纽约行政区多边形画出来。Fig. 3进一步展示交互地图,GeoPandas可以调用Folium和Leaflet,让同一份空间数据进入可缩放、可交互的Web地图环境。
第三层,也是研究者最熟悉的GeoDataFrame。
GeoDataFrame继承自pandas DataFrame,同时允许表格中存在一个或多个geometry列。其中一列被指定为“active geometry”,即当前进行空间计算时默认使用的几何列。
这个设计比传统GIS文件更加灵活。
例如,一条道路既可以有道路中心线,也可以有道路实际占地范围。GeoDataFrame可以同时保存:
道路名称|道路等级|中心线geometry|道路面geometry
研究者可以根据任务切换当前使用的几何对象。
所以Fig. 1真正表达的是一条非常清楚的逻辑链:
Shapely几何对象 → GeometryArray组织几何 → GeoSeries提供空间操作 → GeoDataFrame将空间与属性完整结合。
这三层结构解释了GeoPandas为什么既像GIS,又像pandas。
从缓冲区到空间连接:GeoPandas如何把GIS操作变成Python方法?
建立数据结构以后,GeoPandas还需要解决第二个问题:传统GIS里的分析功能如何进入这一体系?
第一类是几何运算。
GeoPandas目前基本能够直接暴露Shapely提供的主要几何操作,包括面积、范围、距离、几何有效性检查,以及intersects、contains等空间关系判断;还包括intersection、union、difference等集合运算,以及centroid、convex hull、simplify等几何构造。
研究者看到的只是一条简短命令,真正的几何计算则由Shapely和GEOS完成。
第二类是空间索引。
这是大规模空间分析性能的关键。
假设有10万个住宅点和10万个学校点,希望判断每套住房附近最近的学校。如果完全两两比较,需要进行100亿次距离判断。
空间索引会先按照空间位置构建类似树状的搜索结构。明显距离很远的对象可以直接排除,只对可能匹配的对象进行精确几何判断。
GeoPandas通过Shapely提供的STRtree实现空间索引,并通过sindex暴露给用户。因此很多空间连接能够在大数据下保持较高效率。
第三类是空间连接和叠加。
普通pandas可以根据ID连接两张表,而空间数据很多时候没有共同ID。
例如:
“每个POI属于哪个街道?”
“每套住房距离哪个地铁站最近?”
“哪些建筑位于洪水风险区内?”
GeoPandas的spatial join允许研究者按照contains、intersects、within等空间关系连接两张GeoDataFrame,也可以使用nearest按照最近距离连接。
如果只需要连接属性,可以使用spatial join;如果需要同时改变几何形状,则使用overlay。例如两个多边形图层求intersection后,输出的是它们真正重叠的空间范围,并同时保留双方属性。
第四类是坐标系统。
GeoPandas把CRS直接绑定在GeometryArray上,因此不同几何列甚至可以保存不同的坐标参考系统。
这解决了空间分析中一个常见问题:经纬度适合展示全球位置,却不适合直接计算米制距离和面积。研究者可以保留WGS84经纬度几何,同时建立一列投影坐标几何用于距离计算,在同一个GeoDataFrame中管理两套表达。
第五类是数据输入与输出。
GeoPandas支持Shapefile、GeoPackage、GeoJSON、PostGIS,以及近年来越来越重要的Parquet、Feather和GeoParquet。也可以输出WKT、WKB和JSON等表示形式。
这部分看似只是“读取文件”,实际上直接决定空间分析工作流能否扩展到大型数据。
Fig. 4解释了GeoPandas一个非常重要的软件设计:GeoPandas本身并没有重新制造所有GIS功能,而是作为“胶水”,将多个成熟开源组件统一到一个Python接口中。
几何计算来自Shapely和GEOS,坐标转换来自PyPROJ和PROJ,文件读写主要由PyOGRIO调用GDAL完成,表格结构来自pandas和NumPy。
因此GeoPandas的成功并不是因为它自己实现了所有算法,而是因为它把复杂底层库隐藏起来,让研究者能够用一种统一的数据结构调用它们。
从“能处理空间数据”到真正成为基础设施
文章中最有冲击力的性能结果来自Fig. 5。
GeoPandas早期主要通过Fiona读取和写入GIS文件。Fiona功能稳定,但需要在Python层逐条迭代要素,当数据规模扩大以后,这一方式会成为明显瓶颈。
GeoPandas 1.0以后,PyOGRIO成为默认依赖。PyOGRIO通过GDAL批量读取空间对象,并可以进一步使用Apache Arrow传输数据。
作者使用三类数据进行测试,其中包括由3000万条LineString组成的Microsoft道路检测数据,以及包含356,508个复杂多边形的全球GADM数据,并比较Shapefile、GeoPackage、FlatGeobuf和GeoJSON等格式。
结果非常明显。
相较Fiona,PyOGRIO读取速度可以快3—28倍,平均约9倍;使用Apache Arrow后平均约12倍。写入速度提高4—14倍,平均约5倍;结合Arrow后平均约7倍。
这说明现代GeoPandas已经不再只是追求“Python写GIS更方便”,性能和大规模数据交互也成为核心目标。
当然,它仍然存在边界。
GeoPandas继承pandas的内存计算模式,通常需要把整个数据集装进RAM,而且主要是单线程处理。当数据超过内存容量时,GeoPandas本身并不能像真正的分布式数据库一样自动解决。
因此生态中出现了Dask-GeoPandas,将GeoDataFrame拆分成多个分区,实现并行、分布式和超内存处理。对于更大规模任务,也可以与DuckDB、SedonaDB等SQL空间引擎配合。
可视化也存在规模边界。交互式explore方法通常在数万要素以后逐渐受到限制,普通plot在超过10万个复杂几何对象时也可能明显变慢。此时Datashader、Lonboard等工具可以接替GeoPandas完成大规模可视化。
另一个更根本的限制来自地球本身。
Shapely和GEOS采用的是平面几何模型,但真实地球是曲面。在城市或区域尺度,将经纬度转换到合适投影坐标系后通常没有问题;到了洲际甚至全球尺度,单一平面投影很难保持准确。
因此GeoPandas未来的重要方向之一,是支持球面几何。
文章提到,团队已经资助开发基于Google S2的Python项目Spherely,并计划逐步让GeoPandas支持不同几何计算引擎。这意味着未来同一个GeoDataFrame可能根据任务选择Shapely的平面计算,也可以切换到更加适合全球尺度的球面计算。
GeoPandas的影响也已经远远超过传统GIS。
截至2026年4月,conda-forge中有355个软件包直接依赖GeoPandas;Libraries.io记录约2930个依赖包;GitHub检索则得到约5.87万个依赖GeoPandas的代码仓库。
Table 1(略)展示了这种生态扩散。城市研究中有PySAL、OSMnx、scikit-mobility等;环境与地球科学、气候研究、遥感以及空间组学等领域也大量使用GeoPandas。甚至用于量子芯片平面几何设计的qiskit-metal,也使用了GeoPandas的数据结构。
Fig. 6进一步展示了GeoPandas如何与contextily、xyzservices等工具结合,为普通矢量地图快速添加OpenStreetMap等背景瓦片。
这也解释了文章为什么把GeoPandas称为一种“fundamental data structure”。
它今天的价值已经类似pandas之于普通表格数据:许多更复杂的工具并不自己重新设计空间数据结构,而是直接接受GeoDataFrame作为输入,再在它之上做网络分析、空间计量、机器学习、交通可达性或城市形态计算。
总结
这篇文章表面上是在介绍GeoPandas,实际讨论的是一个更加基础的问题:一个成熟的空间数据科学体系,到底应该建立在什么样的数据结构之上?
GeoPandas给出的答案是,把几何对象和属性表统一起来,让空间数据成为Python数据科学体系中的“一等公民”。
GeometryArray负责组织几何对象和底层空间计算,GeoSeries把几何操作暴露为用户能够直接使用的方法,GeoDataFrame进一步把几何和属性整合到完整表格中。Shapely、GEOS、PROJ、GDAL、PyOGRIO等底层工具则负责真正高性能的计算、坐标转换和文件处理。
这种设计最大的价值,是让研究者不需要在GIS世界和数据科学世界之间反复切换。
一个城市研究项目可以用GeoPandas读取街道和建筑数据,使用OSMnx构建交通网络,用PySAL完成空间统计,再将结果送入scikit-learn或其他机器学习工具;整个过程中,GeoDataFrame可以始终作为核心空间数据载体。
GeoPandas也仍然面对大规模计算、内存限制、单线程性能和平面几何等问题。因此Dask-GeoPandas、GeoParquet、Apache Arrow以及未来的Spherely和多几何引擎,将决定它下一阶段能够扩展到什么尺度。
从2013年的一次SciPy会议实验,到2024年发布稳定的1.0版本,再到今天成为数万个项目背后的基础依赖,GeoPandas的意义已经远远超过一个Python包。
它真正完成的事情,是给Python建立了一套能够理解“空间”的基础数据结构。