GeoPandas怎么读?GIS空间分析实战(附:源码)
GeoPandas怎么读?GIS空间分析实战(附:源码)这篇文章面向刚开始学习 Python GIS 的同学和 GIS 工程入门用户,目标不是泛泛介绍库名,而是用一个可复现的小案例说明:GeoPandas 读什么数据、怎么读、读完以后如何做一次基础空间分析,并把结果导出给 QGIS 或 ArcGIS Pro 检查。
引言:GeoPandas怎么读,先从一个真实 GIS 任务开始
很多人搜索“GeoPandas怎么读”,其实有两层意思:一是 GeoPandas 这个词怎么理解,二是 GeoPandas 怎么读取空间数据。GeoPandas 可以理解为“带几何字段的 Pandas”,它把表格数据分析能力和空间几何处理能力结合起来,适合处理 Shapefile、GeoJSON、GeoPackage 等常见 GIS 数据。
本文用一个简单的空间分析任务贯穿:读取行政区面数据和点位数据,统一坐标系,判断每个点落在哪个行政区内,统计每个行政区的点数量,最后导出结果文件。

背景:为什么 GIS 用户需要学 GeoPandas
在传统 GIS 软件中,叠加分析、空间连接、字段统计通常通过工具箱完成。GeoPandas 的优势是把这些步骤写成代码,便于批处理、复用和自动化。
常见使用场景包括:
- 批量读取多个 Shapefile 或 GeoJSON 文件。
- 检查和统一坐标系,避免面积、距离、叠加分析出错。
- 对点、线、面数据做空间连接、缓冲区、裁剪和叠加。
- 把分析结果导出为 GeoPackage、Shapefile 或 GeoJSON。
- 结合 Pandas 做字段清洗、分类统计和报表输出。
如果你已经会一点 Pandas,再学习 GeoPandas 会很自然;如果你来自 QGIS 或 ArcGIS Pro,也可以把 GeoPandas 理解为“用 Python 写出来的 GIS 处理工具链”。
原理:GeoPandas读取空间数据后到底得到什么
GeoPandas 读取空间数据后,核心对象是 GeoDataFrame。它和 Pandas 的 DataFrame 很像,但多了一个特殊字段:geometry。这个字段保存点、线、面等空间几何对象。
一个 GeoDataFrame 通常包含三类信息:
- 属性字段:例如名称、类型、人口、编号等。
- 几何字段:例如 Point、LineString、Polygon、MultiPolygon。
- 坐标参考系统:也就是 CRS,用来说明坐标值属于哪个坐标系。
GeoPandas 的很多空间分析都依赖两个基础条件:
- 数据必须有有效的 geometry 字段。
- 参与空间运算的数据最好处于同一个 CRS。
如果两个图层一个是 WGS84 经纬度坐标,一个是投影坐标,直接做空间连接或距离计算,很容易得到错误结果。因此,学习 GeoPandas 不能只学 read_file(),还要学会检查 crs、转换坐标系和验证结果。
步骤:GeoPandas读取空间数据并完成空间分析
1. 安装 GeoPandas 环境
建议优先使用 Conda 或 Mamba 安装,因为 GeoPandas 依赖 GDAL、Fiona、pyproj、Shapely 等空间库,直接用 pip 在部分系统上可能遇到二进制依赖问题。
conda create -n py311_gis python=3.11
conda activate py311_gis
conda install -c conda-forge geopandas pyogrio rtree matplotlib
如果你使用 Jupyter Notebook,可以继续安装:
conda install -c conda-forge jupyterlab
2. 准备示例数据
本文假设你有两个文件:
data/districts.gpkg:行政区面数据,图层名为districts。data/poi.geojson:兴趣点数据,例如学校、医院、门店或采样点。
如果你的数据是 Shapefile,也可以把路径改成 data/districts.shp。但在实际项目中,更推荐 GeoPackage,因为它对中文字段名、长字段名和多图层支持更友好。
3. 读取面数据和点数据
import geopandas as gpd
districts = gpd.read_file("data/districts.gpkg", layer="districts")
poi = gpd.read_file("data/poi.geojson")
print(districts.head())
print(poi.head())
print(districts.crs)
print(poi.crs)
gpd.read_file() 是 GeoPandas 读取空间数据最常用的方法。它可以读取 Shapefile、GeoJSON、GeoPackage、FileGDB 等多种格式,具体支持情况取决于底层 GDAL 驱动。
4. 检查 geometry 和 CRS
读取数据后,不要马上分析,先检查几何类型、坐标系和空几何。
print(districts.geom_type.value_counts())
print(poi.geom_type.value_counts())
print("districts CRS:", districts.crs)
print("poi CRS:", poi.crs)
print("districts empty geometry:", districts.geometry.is_empty.sum())
print("poi empty geometry:", poi.geometry.is_empty.sum())
print("districts null geometry:", districts.geometry.isna().sum())
print("poi null geometry:", poi.geometry.isna().sum())
如果点图层中存在空几何,空间连接时这些记录不会得到正确匹配。可以先过滤:
districts = districts[~districts.geometry.is_empty & districts.geometry.notna()].copy()
poi = poi[~poi.geometry.is_empty & poi.geometry.notna()].copy()
5. 统一坐标系
如果两个图层 CRS 不一致,应把其中一个转换到另一个坐标系。对于空间连接,统一 CRS 是必要步骤。
if districts.crs != poi.crs:
poi = poi.to_crs(districts.crs)
print(districts.crs)
print(poi.crs)
注意:to_crs() 是坐标转换,不是简单修改标签。如果你的数据本来没有 CRS,但你知道它实际是 WGS84,可以使用 set_crs() 先定义坐标系。
poi = poi.set_crs("EPSG:4326", allow_override=True)
只有在你确认原始坐标就是 EPSG:4326 时才应该这样做。不要用 set_crs() 代替投影转换。
6. 执行空间连接:判断点落在哪个行政区
空间连接可以理解为 GIS 软件中的“按位置连接属性”。下面代码把每个 POI 点匹配到包含它的行政区面。
joined = gpd.sjoin(
poi,
districts[["district_id", "district_name", "geometry"]],
how="left",
predicate="within"
)
print(joined.head())
这里的参数含义如下:
poi:左表,表示要被匹配的点。districts:右表,表示行政区面。how="left":保留所有点,即使没有落入任何行政区。predicate="within":判断点是否位于面内部。
如果你希望边界上的点也能被匹配,可以根据数据情况尝试 predicate="intersects"。但在行政区统计中,边界点可能同时与多个面相交,需要额外处理。
7. 统计每个行政区的点数量
空间连接完成后,可以用 Pandas 的分组统计能力计算每个行政区内的点数量。
count_table = (
joined
.groupby(["district_id", "district_name"])
.size()
.reset_index(name="poi_count")
)
print(count_table.head())
把统计结果回连到行政区面数据:
result = districts.merge(
count_table,
on=["district_id", "district_name"],
how="left"
)
result["poi_count"] = result["poi_count"].fillna(0).astype(int)
print(result[["district_id", "district_name", "poi_count"]].head())
8. 导出结果给 QGIS 或 ArcGIS Pro 检查
推荐导出为 GeoPackage,便于后续在 QGIS、ArcGIS Pro 或其他 GIS 软件中查看。
result.to_file(
"output/district_poi_count.gpkg",
layer="district_poi_count",
driver="GPKG"
)
joined.to_file(
"output/poi_with_district.gpkg",
layer="poi_with_district",
driver="GPKG"
)
导出后可以在 QGIS 中打开 district_poi_count.gpkg,用 poi_count 字段做分级设色,检查空间统计结果是否符合直觉。
常见坑:GeoPandas读取和分析最容易错在哪里
1. 文件路径有中文或空格导致读取失败
现代 GeoPandas 对中文路径支持已经比早期好很多,但在不同系统、不同 GDAL 版本下仍可能遇到问题。建议项目路径尽量使用英文、数字和下划线。
data/project_001/input/poi.geojson
不要把数据长期放在桌面、微信下载目录或含特殊符号的临时目录中。
2. CRS 不一致却直接做空间分析
这是 GeoPandas 空间分析中最常见的问题。两个图层看起来都能绘制,但坐标系不同,空间连接、裁剪、叠加可能全部出错。
分析前至少检查:
print(layer1.crs)
print(layer2.crs)
如果 CRS 不一致,应使用 to_crs() 统一,而不是直接继续分析。
3. 把 set_crs 当成 to_crs 使用
set_crs() 是给数据“贴坐标系标签”,不会改变坐标值。to_crs() 才会真正转换坐标值。
| 方法 | 作用 | 是否改变坐标值 | 典型用途 |
|---|---|---|---|
set_crs() |
定义 CRS | 否 | 数据缺少 CRS,但你确认其真实坐标系 |
to_crs() |
转换 CRS | 是 | 把 WGS84 转为投影坐标,或统一两个图层 CRS |
4. Shapefile 字段名被截断
Shapefile 对字段名长度有限制,导出时长字段名可能被截断。例如 district_name 可能变成较短字段。为了减少字段损失,建议输出 GeoPackage。
5. 面数据几何无效导致叠加失败
如果行政区面存在自相交、空洞异常或重复边界,空间分析可能报错或结果异常。可以先检查几何有效性:
invalid_count = (~districts.geometry.is_valid).sum()
print("invalid geometry:", invalid_count)
对于简单问题,可以尝试:
districts["geometry"] = districts.geometry.make_valid()
但如果是正式生产数据,建议回到数据源头修复,避免把拓扑错误带入后续流程。
方法比较:GeoPandas、QGIS、ArcPy 怎么选
| 方法 | 适合场景 | 优点 | 限制 |
|---|---|---|---|
| GeoPandas | Python GIS、批处理、数据清洗、空间连接统计 | 代码清晰,适合自动化,和 Pandas 结合方便 | 超大数据性能有限,复杂拓扑处理不如专业 GIS 平台稳定 |
| QGIS | 交互式制图、快速检查、可视化处理 | 免费开源,工具丰富,适合学习和验证结果 | 大量重复任务需要模型构建器或脚本配合 |
| ArcPy | ArcGIS Pro 工作流自动化、企业数据处理 | 和 ArcGIS 生态结合紧密,工具箱能力强 | 依赖 ArcGIS 授权和环境 |
| PostGIS | 海量空间数据、服务端查询、多用户数据管理 | 空间索引强,适合 WebGIS 后端和长期数据管理 | 需要数据库设计和 SQL 能力 |
如果你的任务是中小规模数据清洗和空间统计,GeoPandas 很合适;如果要处理百万级以上复杂空间查询,建议考虑 PostGIS;如果需要和企业 ArcGIS 工具链对接,ArcPy 更自然。
检查清单:写 GeoPandas 空间分析脚本前先确认这些项
- 数据格式是否适合当前任务,优先考虑 GeoPackage 而不是老旧 Shapefile。
- 文件路径是否稳定,是否避免中文、空格和特殊符号。
- 每个图层是否成功读取为 GeoDataFrame。
geometry字段是否存在,是否有空几何或无效几何。- 参与空间分析的图层 CRS 是否一致。
- 是否正确区分
set_crs()和to_crs()。 - 空间连接谓词是否符合业务含义,例如
within、contains、intersects。 - 统计结果是否用 QGIS 或 ArcGIS Pro 可视化检查过。
- 导出格式是否保留字段名、编码和几何类型。
- 脚本是否把输入、输出路径分开,避免覆盖原始数据。
FAQ:GeoPandas怎么读相关常见问题
Q1:GeoPandas怎么读 Shapefile?
可以直接使用 gpd.read_file():
import geopandas as gpd
gdf = gpd.read_file("data/roads.shp")
print(gdf.head())
print(gdf.crs)
如果 Shapefile 包含中文字段或中文属性,建议检查编码问题。实际项目中也可以先用 QGIS 转为 GeoPackage,再用 GeoPandas 读取。
Q2:GeoPandas怎么读 GeoJSON?
GeoJSON 也可以直接读取:
gdf = gpd.read_file("data/poi.geojson")
print(gdf.geom_type.value_counts())
GeoJSON 常见坐标系是 WGS84,经纬度单位是度,不适合直接计算米制距离和面积。需要计算距离或面积时,应先转换到合适的投影坐标系。
Q3:GeoPandas读取空间数据后为什么没有 crs?
说明源文件没有写入坐标系信息,或者驱动没有正确识别。此时不要盲目转换,应先确认数据真实坐标系。如果确认是 WGS84,可以设置:
gdf = gdf.set_crs("EPSG:4326")
如果确认是某个地方投影坐标系,应设置对应 EPSG 编码或 CRS 定义。
Q4:GeoPandas空间连接结果为空怎么办?
优先检查四件事:
- 两个图层 CRS 是否一致。
- 点和面是否真的在同一空间范围。
- 是否存在空几何或无效几何。
predicate是否选错,例如边界点用within可能匹配不到。
可以打印数据范围辅助判断:
print(poi.total_bounds)
print(districts.total_bounds)
Q5:GeoPandas适合做大数据空间分析吗?
GeoPandas 适合中小规模矢量数据处理和脚本化分析。如果数据量很大,例如千万级要素、复杂叠加、多用户并发查询,建议使用 PostGIS、DuckDB Spatial 或分块处理策略。GeoPandas 更适合作为数据预处理、验证和自动化脚本工具。
Q6:GeoPandas和Pandas是什么关系?
GeoPandas 扩展了 Pandas。普通 DataFrame 主要处理表格字段,GeoDataFrame 在此基础上增加 geometry 字段和 CRS 信息,因此可以执行空间连接、缓冲区、投影转换、叠加分析等 GIS 操作。
结论:GeoPandas怎么读,关键是读懂数据、坐标系和分析流程
学习 GeoPandas,不要只停留在“怎么读文件”这一行代码上。真正实用的 GeoPandas 工作流应该包括:读取数据、检查 geometry、检查 CRS、统一坐标系、执行空间分析、统计结果、导出并可视化验证。
本文的空间连接统计案例覆盖了 Python GIS 入门中最常见的一类任务。掌握这个流程后,你可以把行政区换成网格、缓冲区、服务范围,把点数据换成门店、监测点、事故点或客户点,从而扩展到更多 GIS 空间分析场景。
建议你把上面的源码整理成一个独立脚本,并在自己的数据上跑一遍。只要坚持每次分析前检查 CRS 和 geometry,大多数 GeoPandas 读取空间数据和空间分析问题都能快速定位。