GeoPandas是什么?GIS空间分析实战指南(含:数据)

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

《GeoPandas是什么?GIS空间分析实战指南(含:数据)》这篇文章面向刚接触 Python GIS 的同学和初级 GIS 工程师,重点解决一个具体问题:如何理解 GeoPandas,并用它完成一次可复现的空间数据读取、坐标系检查、空间连接、缓冲区分析和结果导出。

引言:GeoPandas是什么,适合解决哪些GIS问题

GeoPandas 是 Python 生态中用于处理矢量空间数据的常用库。你可以把它理解为“带空间字段的 pandas”:pandas 擅长处理表格数据,GeoPandas 在此基础上增加了几何对象、坐标参考系和空间分析能力。

在日常 GIS 工作中,GeoPandas 常用于以下任务:

  • 读取 Shapefile、GeoJSON、GeoPackage 等矢量数据。
  • 检查和转换坐标系,例如从 WGS84 经纬度转为投影坐标系。
  • 计算点、线、面的空间关系,例如相交、包含、邻近。
  • 做缓冲区、叠加分析、空间连接、裁剪等基础空间分析。
  • 把分析结果导出为 GeoPackage、GeoJSON 或 Shapefile,交给 QGIS、ArcGIS Pro 或 WebGIS 使用。

如果你已经会一点 pandas,又经常需要处理行政区、POI、道路、网格、地块等矢量数据,那么 GeoPandas 是非常值得掌握的 Python GIS 工具。

GeoPandas是什么与GeoPandas空间分析流程示意图
GeoPandas 的典型工作流:读取空间数据、检查坐标系、执行空间分析、导出结果。

背景:为什么GIS空间分析需要GeoPandas

很多 GIS 初学者一开始会在 QGIS 或 ArcGIS Pro 中通过图形界面完成分析,这非常直观。但当数据量增多、步骤重复、结果需要批量更新时,纯手工操作会遇到几个问题:

  • 重复性差:同一个缓冲区或空间连接流程,每次都要手动点工具和参数。
  • 难以批处理:几十个城市、几百个图层需要循环处理时,图形界面效率较低。
  • 结果不易追溯:别人很难知道你当时选择了哪个字段、哪个坐标系、哪个空间关系。
  • 表格分析割裂:空间分析完成后,还要回到 Excel 或 pandas 里做统计汇总。

GeoPandas 的价值在于,它把空间数据处理和表格数据处理放在同一个 Python 工作流中。你可以像操作 DataFrame 一样筛选字段、分组统计,也可以直接做缓冲区、空间连接和坐标系转换。

本文使用一个典型场景说明 GeoPandas 空间分析流程:假设我们有一份城市 POI 点数据和一份行政区面数据,需要判断每个 POI 位于哪个行政区,并统计每个行政区内的 POI 数量。

原理:GeoDataFrame、几何字段和坐标系

1. GeoDataFrame是什么

GeoPandas 的核心数据结构是 GeoDataFrame。它和 pandas 的 DataFrame 很像,但多了一个特殊字段:geometry。这个字段用于存放点、线、面等几何对象。

一个 POI 点图层在 GeoPandas 中通常长这样:

name type geometry
某小学 教育 POINT (116.39 39.90)
某医院 医疗 POINT (116.41 39.91)

其中 geometry 字段不是普通文本,而是空间几何对象。GeoPandas 底层依赖 Shapely 进行几何计算,因此可以判断点是否在面内、两个面是否相交、线是否穿过面等。

2. CRS坐标参考系为什么重要

CRS 是坐标参考系,即空间数据使用的坐标系统。常见的 EPSG:4326 是经纬度坐标,单位是度;而投影坐标系的单位通常是米。

GeoPandas 空间分析中最常见的错误之一,就是在不合适的坐标系下计算距离、面积或缓冲区。例如,在 EPSG:4326 下直接执行 buffer(1000),并不表示 1000 米,而是 1000 度,这显然是错误的。

因此,做 GeoPandas 空间分析时必须先检查坐标系:

  • 做空间连接、相交判断:两个图层 CRS 必须一致。
  • 做距离、面积、缓冲区:建议使用以米为单位的投影坐标系。
  • 导出给 WebGIS 使用:常见选择是 EPSG:4326 或 EPSG:3857,具体看前端地图底图要求。

步骤:用GeoPandas完成一次空间分析实战

步骤1:安装GeoPandas环境

推荐使用 conda 创建独立环境,因为 GeoPandas 涉及 GDAL、PROJ、GEOS 等地理空间依赖,直接用 pip 在部分系统上可能出现编译或动态库问题。

conda create -n gis python=3.11
conda activate gis
conda install -c conda-forge geopandas pyogrio matplotlib

如果你使用的是 Jupyter Notebook,可以继续安装:

conda install -c conda-forge jupyterlab

安装完成后,在 Python 中测试:

import geopandas as gpd

print(gpd.__version__)

步骤2:准备示例数据

本文示例假设你有两份数据:

  • poi.geojson:POI 点数据,包含名称和类型字段。
  • districts.gpkg:行政区面数据,包含行政区名称字段。

文件目录建议如下:

project/
  data/
    poi.geojson
    districts.gpkg
  output/
  analysis.py

如果你暂时没有数据,可以用 QGIS 从公开数据中裁剪一小块行政区和 POI 数据作为练习。重点不是数据量,而是理解 GeoPandas 读取、检查、分析、导出的完整流程。

步骤3:读取矢量数据

import geopandas as gpd

poi = gpd.read_file("data/poi.geojson")
districts = gpd.read_file("data/districts.gpkg")

print(poi.head())
print(districts.head())

gpd.read_file() 可以读取多种矢量格式,包括 Shapefile、GeoJSON、GeoPackage、FileGDB 中的部分数据等。实际项目中,GeoPackage 比 Shapefile 更推荐,因为它支持 UTF-8 字段名、长字段名和多个图层,文件管理也更方便。

步骤4:检查字段、几何类型和坐标系

print(poi.columns)
print(districts.columns)

print(poi.geom_type.value_counts())
print(districts.geom_type.value_counts())

print(poi.crs)
print(districts.crs)

你需要确认三件事:

  • POI 是否为 Point 或 MultiPoint。
  • 行政区是否为 Polygon 或 MultiPolygon。
  • 两个图层是否有 CRS,并且 CRS 是否一致。

如果某个图层的 CRS 显示为 None,不要直接用 to_crs() 转换。你必须先确认原始数据实际采用的坐标系,再使用 set_crs() 正确声明。

# 仅当你确认 poi 原始坐标确实是 EPSG:4326 时才这样做
poi = poi.set_crs(epsg=4326)

步骤5:统一坐标系

空间连接要求两个 GeoDataFrame 使用相同 CRS。如果行政区数据和 POI 数据坐标系不同,需要转换其中一个。

districts = districts.to_crs(poi.crs)

这里的 to_crs() 是“坐标转换”,会改变坐标值;而 set_crs() 是“声明坐标系”,不会改变坐标值。很多 GeoPandas 分析结果异常,根源就是把这两个方法混用了。

步骤6:执行空间连接,判断POI属于哪个行政区

使用 gpd.sjoin() 可以完成空间连接。下面的代码把每个 POI 匹配到包含它的行政区。

poi_with_district = gpd.sjoin(
    poi,
    districts[["district_name", "geometry"]],
    how="left",
    predicate="within"
)

print(poi_with_district[["name", "type", "district_name"]].head())

参数说明:

  • how="left":保留所有 POI,即使某些点没有落入任何行政区。
  • predicate="within":表示点位于面内部。
  • districts[["district_name", "geometry"]]:只保留分析需要的字段,减少结果冗余。

如果你希望边界上的点也能被匹配,可以根据数据情况尝试 predicate="intersects"。但要注意,withinintersects 的空间语义不同,不能随意替换。

步骤7:按行政区统计POI数量

summary = (
    poi_with_district
    .groupby("district_name")
    .size()
    .reset_index(name="poi_count")
)

print(summary)

如果还想按 POI 类型统计,可以这样写:

type_summary = (
    poi_with_district
    .groupby(["district_name", "type"])
    .size()
    .reset_index(name="count")
)

print(type_summary)

这就是 GeoPandas 与 pandas 结合的优势:空间关系计算完成后,可以直接使用 pandas 的分组、透视、筛选和统计能力。

步骤8:把统计结果连接回行政区面

districts_result = districts.merge(
    summary,
    on="district_name",
    how="left"
)

districts_result["poi_count"] = districts_result["poi_count"].fillna(0).astype(int)

这样每个行政区面都带有 poi_count 字段,可以在 QGIS 或 ArcGIS Pro 中直接按数量分级设色。

步骤9:导出分析结果

districts_result.to_file(
    "output/district_poi_count.gpkg",
    layer="district_poi_count",
    driver="GPKG"
)

poi_with_district.to_file(
    "output/poi_with_district.geojson",
    driver="GeoJSON"
)

如果结果要给桌面 GIS 软件继续制图,推荐导出 GeoPackage。如果结果要给 WebGIS 前端测试,GeoJSON 更方便,但大数据量时不建议直接把完整 GeoJSON 加到浏览器。

常见坑:GeoPandas空间分析结果不对,多半先查这些

1. CRS不一致导致空间连接为空

如果 sjoin 后大部分行政区字段都是空值,第一步检查 CRS:

print(poi.crs)
print(districts.crs)

两个图层 CRS 不一致时,点和面可能看似都在同一城市,但坐标实际不在同一空间位置,空间连接自然匹配不到。

2. 把set_crs当成to_crs使用

set_crs() 只是告诉 GeoPandas“这份数据是什么坐标系”,不会移动坐标。to_crs() 才是把数据从一个坐标系转换到另一个坐标系。

简单判断:如果原始数据没有 CRS 但你知道它本来就是 EPSG:4326,用 set_crs;如果数据已经有 CRS,想转到 EPSG:3857 或本地投影坐标系,用 to_crs。

3. 在经纬度坐标系下计算面积和缓冲区

如果你执行下面的代码:

poi["buffer"] = poi.buffer(1000)

poi.crs 是 EPSG:4326,那么这个缓冲区不是 1000 米。正确做法是先转换到适合当地的投影坐标系,再计算缓冲区。

poi_projected = poi.to_crs(epsg=3857)
poi_projected["buffer_1000m"] = poi_projected.buffer(1000)

EPSG:3857 可用于一般 Web 地图近似展示,但如果要做严肃面积和距离计算,应优先选择本地合适的投影坐标系。

4. 几何无效导致叠加分析报错

行政区、地块、缓冲区等面数据可能存在自相交、重复节点、空几何等问题。可以先检查几何有效性:

invalid = districts[~districts.is_valid]
print(len(invalid))

在部分场景中,可以用 make_valid() 修复:

districts["geometry"] = districts.geometry.make_valid()

但自动修复并不等于业务上一定正确。涉及权属边界、规划红线、精确面积统计时,仍应回到数据生产环节确认。

5. Shapefile字段名被截断或中文乱码

Shapefile 对字段名长度、编码和文件组成有较多限制。GeoPandas 读写 Shapefile 时,如果遇到字段名被截断、中文乱码、文件缺失等问题,建议改用 GeoPackage。

方法比较:GeoPandas、QGIS、ArcPy该怎么选

工具 适合场景 优势 注意点
GeoPandas Python 批处理、空间分析自动化、表格统计结合 代码清晰,和 pandas 结合紧密,适合可复现流程 对超大数据和复杂拓扑分析不是万能,需要注意内存
QGIS 交互式制图、数据检查、初学者空间分析 界面直观,工具丰富,适合快速验证结果 批处理和流程复现需要模型构建器或 PyQGIS
ArcPy ArcGIS Pro 环境下的企业级自动化 与 ArcGIS 工具箱、地理数据库和企业流程结合紧密 依赖 ArcGIS 授权和特定环境
PostGIS 多用户、大数据量、服务端空间查询 空间索引强,适合数据库级分析和 WebGIS 后端 需要数据库建模、SQL 和运维基础

如果你的目标是学习 Python GIS,并处理中小规模矢量数据,GeoPandas 是非常合适的入口。如果数据已经进入企业数据库,或者需要多人并发查询,则应考虑 PostGIS。如果你主要做制图和人工检查,QGIS 或 ArcGIS Pro 仍然很重要。

检查清单:写GeoPandas脚本前先确认这些

  • 是否明确输入数据格式:Shapefile、GeoJSON、GeoPackage 还是数据库图层?
  • 是否确认每个图层的几何类型:点、线、面是否符合分析目标?
  • 是否检查 CRS:两个图层是否一致,是否适合距离和面积计算?
  • 是否只保留必要字段,避免空间连接后字段过多?
  • 是否检查空几何和无效几何?
  • 是否明确空间关系:within、contains、intersects、touches 还是 nearest?
  • 是否在导出前检查记录数、字段统计和地图叠加效果?
  • 是否选择合适的输出格式:GeoPackage 用于桌面 GIS,GeoJSON 用于轻量 WebGIS,数据库用于生产系统?

完成 GeoPandas 空间分析后,建议把结果加载到 QGIS 中叠加查看一次。代码统计正确不代表空间位置一定合理,地图检查仍然是 GIS 工作中的必要步骤。

FAQ:GeoPandas是什么相关常见问题

1. GeoPandas是什么,和pandas有什么区别?

pandas 主要处理普通表格数据,GeoPandas 在 pandas 的基础上增加了空间几何字段和空间分析能力。简单说,GeoPandas 可以处理“带坐标和图形的表格”。

2. GeoPandas可以替代QGIS吗?

不能简单替代。GeoPandas 适合自动化、批处理和可复现分析;QGIS 适合交互式制图、人工检查和可视化探索。实际工作中,两者经常配合使用。

3. GeoPandas适合处理多大的数据?

GeoPandas 主要在内存中处理数据,适合中小规模矢量数据。数据量很大、空间查询频繁或多人访问时,建议使用 PostGIS,并通过空间索引提升查询效率。

4. GeoPandas做缓冲区为什么结果很奇怪?

最常见原因是在 EPSG:4326 经纬度坐标系下直接做缓冲区。经纬度单位是度,不是米。应先转换到合适的投影坐标系,再执行 buffer()

5. GeoPandas读取Shapefile中文乱码怎么办?

可以尝试指定编码,但更推荐把数据转换为 GeoPackage。Shapefile 格式较老,对字段名、编码和文件结构限制较多,不适合作为复杂项目的长期数据格式。

6. GeoPandas空间连接没有结果怎么办?

先检查 CRS 是否一致,再检查两个图层是否真的空间重叠。还要确认使用的空间谓词是否合适,例如点落在面内通常用 within,面包含点可用 contains

结论:GeoPandas是Python GIS入门到实战的重要工具

GeoPandas是什么?从实践角度看,它就是 Python 中处理矢量 GIS 数据的核心工具之一。它把 pandas 的表格分析能力和空间几何分析能力结合起来,让 GIS 数据读取、坐标系检查、空间连接、缓冲区分析和结果导出都可以写成可复现的代码。

学习 GeoPandas 时,不建议只背 API。更重要的是掌握一条稳定工作流:先检查数据和 CRS,再选择正确的空间关系,最后验证结果并导出合适格式。只要这个流程清楚,GeoPandas 就能成为你处理 GIS 空间分析任务的高效工具。