GeoPandas教程学不会?geopandas中文文档详解坐标转换与空间连接!

ArcPy
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

如果你看完一圈资料仍然觉得“GeoPandas教程学不会?geopandas中文文档详解坐标转换与空间连接!”这个问题很真实,通常不是你不会 Python,而是没有把 GeoPandas 的两个核心概念理顺:坐标参考系统和空间关系。本文就围绕 GeoPandas 坐标转换、GeoPandas 空间连接、geopandas中文文档中最容易卡住的几个点,带你完成一个可复现的 GIS 分析流程。

引言:为什么 GeoPandas 教程看懂了,自己一跑就错?

很多 GIS 初学者学习 GeoPandas 时,会遇到三个典型问题:

  • 明明数据能读取,但面积、距离、缓冲区结果明显不对。
  • 两个图层都能显示,但做空间连接时结果全是空值。
  • 网上代码能运行,换成自己的 Shapefile、GeoJSON 或 GeoPackage 后就报错。

这些问题背后,大多不是函数记错,而是没有先检查坐标系、几何字段和空间谓词。GeoPandas 本质上是把 pandas 的表格能力和 Shapely 的几何计算能力结合起来,再通过 pyproj、Fiona 或 pyogrio 处理坐标系统与矢量数据读写。

本文用一个常见场景来讲:已有一份城市行政区边界数据和一份 POI 点数据,需要把它们统一坐标系,然后统计每个行政区内有多少 POI。这正是 GeoPandas 坐标转换和 GeoPandas 空间连接最常见的实际用法。

GeoPandas教程中的坐标转换与GeoPandas空间连接流程图
GeoPandas 坐标转换与空间连接的推荐工作流:先检查 CRS,再转换坐标系,最后执行空间连接和统计。

背景:geopandas中文文档里最容易混淆的几个概念

在正式写代码前,先把几个概念说清楚。很多 GeoPandas 教程之所以学不会,是因为直接从函数开始讲,跳过了 GIS 数据本身的逻辑。

1. GeoDataFrame 不是普通 DataFrame

GeoPandas 的核心对象是 GeoDataFrame。它和 pandas 的 DataFrame 很像,但多了一个几何列,通常叫 geometry。这个几何列里存放点、线、面等空间对象。

import geopandas as gpd

districts = gpd.read_file("districts.gpkg")
pois = gpd.read_file("pois.geojson")

print(type(districts))
print(districts.geometry.head())
print(districts.crs)

如果一个表没有有效的 geometry 列,它就不能直接做空间分析。你可以把 GeoDataFrame 理解为“带空间位置的属性表”。

2. CRS 决定坐标数字的含义

CRS 是 Coordinate Reference System,也就是坐标参考系统。它决定了坐标值代表经纬度,还是投影后的米制坐标。

  • EPSG:4326:常见的 WGS84 经纬度坐标,单位是度。
  • EPSG:3857:Web Mercator,常用于互联网地图显示,不适合严肃面积统计。
  • 本地投影坐标系:常用于距离、面积、缓冲区分析,单位通常是米。

GeoPandas 坐标转换常用 to_crs()。但要注意,to_crs() 是“已知原坐标系后转换到新坐标系”,不是随便给数据贴一个坐标系标签。

3. 空间连接不是普通字段连接

pandas 的 merge() 是按字段值连接,例如行政区编码相同就连接。GeoPandas 空间连接 sjoin() 是按几何空间关系连接,例如点是否落在面内、线是否与面相交。

常见空间关系包括:

  • within:一个几何对象在另一个几何对象内部。
  • contains:一个几何对象包含另一个几何对象。
  • intersects:两个几何对象有任意空间交集。
  • touches:两个几何对象边界接触但内部不重叠。

原理:GeoPandas 坐标转换与空间连接为什么必须放在一起理解?

GeoPandas 空间连接依赖两个图层的几何位置是否能在同一个坐标空间里比较。如果行政区边界是 EPSG:4490,而 POI 点是 EPSG:4326,虽然它们看起来都像经纬度,但仍应明确检查和统一 CRS。

如果一个图层是经纬度,一个图层是投影坐标,直接做 sjoin() 通常会出现以下结果:

  • 连接结果为空。
  • 点全部落到错误区域。
  • 运行不报错,但统计结果明显不合理。

正确流程应该是:

  1. 读取两个空间数据。
  2. 检查几何列是否有效。
  3. 检查两个图层的 CRS。
  4. 必要时用 to_crs() 统一坐标系。
  5. 选择合适的空间谓词执行 sjoin()
  6. 对连接结果做分组统计。
  7. 抽样核查地图位置和统计结果。

在 GeoPandas 中,坐标转换是空间分析的前置条件,空间连接是把空间关系转换成属性表关系的关键步骤。

步骤:用 GeoPandas 完成坐标转换与空间连接

步骤 1:安装并导入 GeoPandas

建议使用 conda 环境安装 GeoPandas,因为它依赖 GDAL、PROJ、GEOS 等底层 GIS 库,直接用 pip 在部分系统上容易遇到编译或动态库问题。

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

导入常用库:

import geopandas as gpd
import pandas as pd

步骤 2:读取行政区面数据和 POI 点数据

这里假设行政区数据是 GeoPackage,POI 数据是 GeoJSON。你也可以换成 Shapefile,但要注意中文字段名、编码和文件组件完整性。

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

print(districts.head())
print(pois.head())

print(districts.crs)
print(pois.crs)

如果 crs 输出为 None,说明数据没有坐标系定义。此时不要急着 to_crs(),要先确认数据真实坐标系。

步骤 3:检查几何类型和空几何

空间连接前必须确认行政区是面,POI 是点,并且几何对象不是空值。

print(districts.geom_type.value_counts())
print(pois.geom_type.value_counts())

print(districts.geometry.is_empty.sum())
print(pois.geometry.is_empty.sum())

districts = districts[~districts.geometry.is_empty & districts.geometry.notna()]
pois = pois[~pois.geometry.is_empty & pois.geometry.notna()]

如果行政区数据包含 MultiPolygon,通常不影响空间连接。如果 POI 数据出现 GeometryCollection 或线面混合,就需要先清洗。

步骤 4:确认并设置原始 CRS

如果数据已经有正确 CRS,可以直接查看:

print(districts.crs)
print(pois.crs)

如果 pois.crsNone,但你确认它的坐标是 WGS84 经纬度,可以使用 set_crs() 设置原始 CRS:

pois = pois.set_crs(epsg=4326)

注意:set_crs() 只是声明坐标系,不会改变坐标数值;to_crs() 才会真正转换坐标数值。这是 geopandas中文文档里非常关键但也最容易被忽略的一点。

步骤 5:执行 GeoPandas 坐标转换

为了让两个图层可以正确进行 GeoPandas 空间连接,建议把 POI 转换到行政区图层的 CRS。

if pois.crs != districts.crs:
    pois = pois.to_crs(districts.crs)

print(districts.crs)
print(pois.crs)

如果后续要计算面积、距离或缓冲区,不建议使用 EPSG:4326。应转换到适合研究区的投影坐标系。例如在中国局部城市分析中,可以使用合适的高斯克吕格投影、UTM 分带或本地官方投影坐标系。

步骤 6:执行空间连接 sjoin

现在可以用 gpd.sjoin() 统计点落在哪个行政区内。对于“点在面内”的问题,推荐把点作为左表,行政区作为右表,谓词使用 within

joined = gpd.sjoin(
    pois,
    districts[["district_id", "district_name", "geometry"]],
    how="left",
    predicate="within"
)

print(joined.head())

参数含义如下:

  • pois:左侧 GeoDataFrame,也就是要被分配行政区属性的点。
  • districts:右侧 GeoDataFrame,提供行政区属性。
  • how="left":保留所有 POI,即使没有落入任何行政区。
  • predicate="within":判断点是否在行政区面内部。

如果你的 GeoPandas 版本较旧,可能看到过 op 参数。较新版本中应使用 predicate。写教程或项目代码时,建议统一使用 predicate

步骤 7:统计每个行政区的 POI 数量

空间连接后,POI 表中已经带有行政区字段。接下来就可以按行政区分组统计。

poi_count = (
    joined
    .dropna(subset=["district_id"])
    .groupby(["district_id", "district_name"])
    .size()
    .reset_index(name="poi_count")
)

print(poi_count.head())

如果需要把统计结果再连接回行政区面图层,用普通字段连接即可:

districts_result = districts.merge(
    poi_count,
    on=["district_id", "district_name"],
    how="left"
)

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

步骤 8:导出结果文件

推荐导出为 GeoPackage,避免 Shapefile 字段名长度限制、中文编码和多文件管理问题。

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

如果只需要统计表,可以导出为 CSV:

poi_count.to_csv("output/poi_count_by_district.csv", index=False, encoding="utf-8-sig")

步骤 9:快速可视化检查

不要只相信代码运行成功。GeoPandas 坐标转换和空间连接做完后,最好做一次简单可视化检查。

ax = districts_result.plot(
    column="poi_count",
    legend=True,
    figsize=(8, 8),
    edgecolor="black",
    linewidth=0.3
)

pois.sample(min(500, len(pois))).plot(
    ax=ax,
    color="red",
    markersize=2
)

如果红色点明显偏离行政区边界,优先检查 CRS;如果少量边界点没有连接成功,再检查空间谓词和边界处理方式。

常见坑:GeoPandas 教程学不会,通常卡在这些地方

坑 1:把 set_crs 当成 to_crs

set_crs() 是设置坐标系标签,to_crs() 是坐标转换。两者不能混用。

# 正确:数据本来就是 EPSG:4326,但文件缺少 CRS 信息
pois = pois.set_crs(epsg=4326)

# 正确:把 EPSG:4326 转换为行政区图层坐标系
pois = pois.to_crs(districts.crs)

如果原始坐标系判断错了,再执行 to_crs(),结果会整体偏移,后续 GeoPandas 空间连接也会错。

坑 2:在经纬度坐标下计算面积和距离

EPSG:4326 的单位是度,不是米。用它直接计算面积、距离、缓冲区,结果没有实际米制意义。

# 不推荐:经纬度下计算面积
districts["area_wrong"] = districts.geometry.area

# 推荐:先转换到合适的投影坐标系
districts_projected = districts.to_crs(epsg=32650)
districts_projected["area_m2"] = districts_projected.geometry.area

这里的 EPSG:32650 只是示例,实际项目应根据研究区位置选择合适的投影坐标系。

坑 3:空间连接结果大量为空

如果 sjoin() 后很多记录没有匹配到行政区,通常检查以下几点:

  • 两个图层 CRS 是否一致。
  • 点是否真的落在行政区范围内。
  • 行政区面几何是否有效。
  • 空间谓词是否选错,例如应该用 intersects 却用了 within
  • 边界点是否刚好落在面边界上。

坑 4:行政区面几何无效

有些面数据存在自相交、环方向异常、空洞错误等问题,会影响空间连接和叠加分析。可以先检查几何有效性:

invalid_count = (~districts.geometry.is_valid).sum()
print(invalid_count)

如果有无效几何,可以尝试修复:

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

对于复杂生产数据,自动修复后还应在 QGIS 或 ArcGIS Pro 中抽样检查,避免边界被意外拆分。

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

Shapefile 对字段名长度和编码支持有限。GeoPandas 读写 Shapefile 时,常见问题包括字段名被截断、中文乱码、日期字段异常。

如果不是必须交付 Shapefile,建议优先使用 GeoPackage:

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

方法比较:GeoPandas、QGIS、PostGIS 做空间连接怎么选?

方法 适合场景 优点 限制
GeoPandas 中小规模矢量数据、自动化脚本、教学分析 代码清晰,容易和 pandas、Jupyter、机器学习流程结合 超大数据性能受内存限制,需要注意空间索引和数据规模
QGIS 交互式制图、人工检查、一次性处理 可视化强,参数直观,适合检查坐标系和几何问题 批处理和可重复性不如脚本方便
PostGIS 大规模空间数据、多人共享、数据库查询服务 空间索引强,适合复杂查询和线上服务 需要数据库环境,SQL 学习成本较高
ArcGIS Pro 企业 GIS 项目、标准化地理处理流程 工具链完整,坐标系管理和制图交付成熟 商业软件环境,自动化通常依赖 ArcPy

如果你是 GIS 学生或入门工程师,建议先用 QGIS 可视化检查数据,再用 GeoPandas 写出可重复脚本。数据量上来之后,再考虑迁移到 PostGIS。

检查清单:写 GeoPandas 空间分析脚本前先过一遍

  • 是否确认每个输入文件都能正确读取?
  • 是否检查了 GeoDataFrame.crs
  • 是否区分了 set_crs()to_crs()
  • 两个图层做空间连接前 CRS 是否一致?
  • 点、线、面几何类型是否符合分析目标?
  • 是否存在空几何或无效几何?
  • 空间谓词是否符合业务含义?
  • 连接结果是否抽样可视化检查?
  • 面积、距离、缓冲区是否在投影坐标系下完成?
  • 输出格式是否避开了 Shapefile 字段限制?

FAQ:关于 geopandas中文文档、坐标转换与空间连接的常见问题

1. GeoPandas 坐标转换用哪个函数?

GeoPandas 坐标转换使用 to_crs()。前提是数据已经有正确的原始 CRS。如果数据缺少 CRS 但你能确认原始坐标系,先用 set_crs() 声明,再用 to_crs() 转换。

2. set_crs 和 to_crs 有什么区别?

set_crs() 不改变坐标值,只是告诉 GeoPandas 这些坐标属于哪个坐标系。to_crs() 会根据坐标转换规则改变坐标值。把这两个函数用反,是 GeoPandas 教程学习中最常见的错误之一。

3. GeoPandas 空间连接结果为什么全是空?

优先检查两个图层的 CRS 是否一致,其次检查几何位置是否真的重叠,再检查 predicate 是否选对。点落在面内一般用 within,面包含点可以用 contains,只要有交集则用 intersects

4. 做 POI 落入行政区统计,应该用 within 还是 intersects?

常规情况下,点落入行政区面使用 within。如果有大量点恰好位于边界线上,within 可能不匹配,这时可以根据业务规则考虑 intersects,或者先对边界点做单独处理。

5. GeoPandas 能处理很大的空间数据吗?

GeoPandas 适合中小规模矢量数据分析。它支持空间索引,但主要仍受内存限制。如果数据达到千万级要素,或需要多人并发查询,建议使用 PostGIS、DuckDB Spatial 或分块处理策略。

6. 为什么在 GeoPandas 中计算面积会出现警告?

如果数据是地理坐标系,例如 EPSG:4326,GeoPandas 可能提示面积或距离结果不可靠。因为经纬度单位是度,不是米。应先转换到合适的投影坐标系,再计算面积、距离或缓冲区。

7. geopandas中文文档适合怎么学?

建议不要按 API 字母顺序硬读。更高效的路线是围绕任务学习:读取数据、检查 CRS、坐标转换、空间连接、叠加分析、字段统计、结果导出。每学一个函数,都用自己的 GIS 数据跑一遍。

结论:学会 GeoPandas,关键是先把空间逻辑跑通

GeoPandas教程学不会?geopandas中文文档详解坐标转换与空间连接!这类问题的核心,不是背更多函数,而是理解 GeoDataFrame、CRS、几何关系和空间谓词之间的关系。

实际项目中,推荐你固定使用这条流程:读取数据,检查 CRS,清理几何,执行 GeoPandas 坐标转换,选择正确谓词做 GeoPandas 空间连接,最后用地图和统计表双重验证结果。

只要这条主线建立起来,后续学习缓冲区、叠加分析、空间聚合、栅格矢量结合都会顺很多。对于 GIS 学生、空间数据分析师和入门 GIS 工程师来说,GeoPandas 最值得掌握的不是某一个孤立函数,而是一套可复现、可检查、可交付的空间数据处理流程。