第12章:集合运算与几何操作
几何集合运算是空间分析中的基础操作,类似于数学中的集合论。通过合并、求交、求差等运算,我们可以从已有的几何对象中生成新的几何形状,实现复杂的空间分析任务。本章将全面介绍 GeoPandas 中的集合运算与几何操作方法。
12.1 集合运算概述 - 几何布尔运算
12.1.1 什么是几何集合运算
几何集合运算(Set-theoretic Operations),也称为几何布尔运算,是将数学集合论应用于几何对象的操作。它们将两个几何对象视为点集,并对这些点集进行集合运算。
基本的几何集合运算包括:
| 运算 | 符号 | 说明 |
|---|---|---|
| 合并(Union) | A ∪ B | 所有属于 A 或 B 的点 |
| 交集(Intersection) | A ∩ B | 所有同时属于 A 和 B 的点 |
| 差集(Difference) | A \ B | 所有属于 A 但不属于 B 的点 |
| 对称差(Symmetric Difference) | A △ B | 属于 A 或 B,但不同时属于两者的点 |
12.1.2 集合运算在 GIS 中的应用
几何集合运算在 GIS 分析中有广泛的应用:
- 区域合并:将多个行政区合并为一个大区域
- 裁剪分析:用一个区域裁剪另一组数据
- 缓冲区分析:合并多个缓冲区以确定服务覆盖范围
- 冲突检测:计算两个区域的重叠部分
- 空间排除:从一个区域中排除特定的子区域
12.1.3 GeoPandas 中的集合运算方法
GeoPandas 提供了两个层级的集合运算方法:
逐元素操作(Element-wise):
| 方法 | 说明 |
|---|---|
union(other) |
两个 GeoSeries 逐元素合并 |
intersection(other) |
两个 GeoSeries 逐元素求交 |
difference(other) |
两个 GeoSeries 逐元素求差 |
symmetric_difference(other) |
两个 GeoSeries 逐元素对称差 |
聚合操作(Aggregate):
| 方法 | 说明 |
|---|---|
unary_union |
将一个 GeoSeries 中所有几何对象合并为一个 |
union_all() |
将一个 GeoSeries 中所有几何对象合并为一个 |
intersection_all() |
将一个 GeoSeries 中所有几何对象求交 |
12.2 union() - 几何合并
12.2.1 基本概念
union() 将两个几何对象合并为一个新的几何对象,结果包含两个原始几何对象的所有点。
12.2.2 两个 GeoSeries 逐元素合并
import geopandas as gpd
from shapely.geometry import Polygon, Point
# 创建两个 GeoSeries
gs1 = gpd.GeoSeries([
Polygon([(0, 0), (2, 0), (2, 2), (0, 2)]),
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
])
gs2 = gpd.GeoSeries([
Polygon([(1, 1), (3, 1), (3, 3), (1, 3)]),
Polygon([(0.5, 0.5), (1.5, 0.5), (1.5, 1.5), (0.5, 1.5)]),
])
# 逐元素合并
result = gs1.union(gs2)
print(result)
print(f"第一个合并结果面积: {result.iloc[0].area}")
print(f"第一个合并结果类型: {result.iloc[0].geom_type}")
12.2.3 GeoSeries 与单个几何对象合并
# 将所有几何对象与一个公共区域合并
common_area = Polygon([(1, 0), (3, 0), (3, 2), (1, 2)])
result = gs1.union(common_area)
print(result)
12.2.4 合并结果的几何类型
合并操作的结果类型取决于输入几何对象的关系:
| 输入关系 | 结果类型 |
|---|---|
| 两个重叠的多边形 | Polygon |
| 两个不重叠的多边形 | MultiPolygon |
| 多边形与内部线 | Polygon(线被忽略) |
| 两条相交的线 | MultiLineString |
| 两个相同的几何对象 | 与输入相同的几何对象 |
from shapely.geometry import Polygon
# 重叠的多边形 → Polygon
poly_a = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
poly_b = Polygon([(1, 1), (3, 1), (3, 3), (1, 3)])
gs = gpd.GeoSeries([poly_a])
result = gs.union(poly_b)
print(f"重叠多边形合并: {result.iloc[0].geom_type}") # Polygon
# 不重叠的多边形 → MultiPolygon
poly_c = Polygon([(5, 5), (7, 5), (7, 7), (5, 7)])
result2 = gs.union(poly_c)
print(f"分离多边形合并: {result2.iloc[0].geom_type}") # MultiPolygon
12.3 intersection() - 几何求交
12.3.1 基本概念
intersection() 计算两个几何对象的交集,结果只包含同时属于两个几何对象的点。
12.3.2 代码示例
import geopandas as gpd
from shapely.geometry import Polygon, LineString
# 两个重叠的多边形
poly_a = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
poly_b = Polygon([(1, 1), (3, 1), (3, 3), (1, 3)])
gs = gpd.GeoSeries([poly_a])
result = gs.intersection(poly_b)
print(f"交集类型: {result.iloc[0].geom_type}") # Polygon
print(f"交集面积: {result.iloc[0].area}") # 1.0
# 交集是 (1,1)-(2,1)-(2,2)-(1,2) 的正方形
12.3.3 不同类型几何对象的交集
# 多边形与线的交集
poly = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
line = LineString([(-1, 1), (3, 1)]) # 穿过多边形的线
gs = gpd.GeoSeries([poly])
result = gs.intersection(line)
print(f"多边形与线交集: {result.iloc[0]}")
# LineString [(0, 1), (2, 1)] - 线在多边形内的部分
# 不相交的几何对象 → 空几何
poly2 = Polygon([(5, 5), (6, 5), (6, 6), (5, 6)])
result2 = gs.intersection(poly2)
print(f"空交集: {result2.iloc[0].is_empty}") # True
12.3.4 交集的维度降低
两个几何对象的交集可能比原始几何对象的维度低:
| 输入 | 可能的交集维度 |
|---|---|
| 面 ∩ 面 | 面、线、点、空 |
| 面 ∩ 线 | 线、点、空 |
| 线 ∩ 线 | 线、点、空 |
| 面 ∩ 点 | 点、空 |
12.3.5 实际应用:区域裁剪
import geopandas as gpd
from shapely.geometry import box
# 读取全国数据
land_use = gpd.read_file("land_use.shp")
# 定义研究区域
study_area = box(113.5, 22.0, 114.5, 23.0) # 珠三角区域
# 裁剪到研究区域
clipped = land_use.copy()
clipped['geometry'] = land_use.intersection(study_area)
# 移除空几何
clipped = clipped[~clipped.is_empty]
print(f"裁剪后要素数: {len(clipped)}")
12.4 difference() - 几何求差
12.4.1 基本概念
difference() 计算两个几何对象的差集,结果包含属于第一个几何对象但不属于第二个几何对象的点。
注意: 差集运算不是对称的,即 A.difference(B) ≠ B.difference(A)。
12.4.2 代码示例
import geopandas as gpd
from shapely.geometry import Polygon
# 两个重叠的多边形
poly_a = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
poly_b = Polygon([(1, 1), (3, 1), (3, 3), (1, 3)])
gs = gpd.GeoSeries([poly_a])
# A - B
diff_ab = gs.difference(poly_b)
print(f"A - B 面积: {diff_ab.iloc[0].area}") # 3.0
# B - A
gs2 = gpd.GeoSeries([poly_b])
diff_ba = gs2.difference(poly_a)
print(f"B - A 面积: {diff_ba.iloc[0].area}") # 3.0
# 验证:A的面积 = (A-B)面积 + (A∩B)面积
intersection_area = gs.intersection(poly_b).iloc[0].area
print(f"A面积 = {poly_a.area}, (A-B) + (A∩B) = {diff_ab.iloc[0].area + intersection_area}")
12.4.3 实际应用:排除区域
import geopandas as gpd
# 从城市区域中排除公园和水域
city_area = gpd.read_file("city_boundary.shp").geometry.iloc[0]
parks = gpd.read_file("parks.shp")
water = gpd.read_file("water_bodies.shp")
# 合并所有需要排除的区域
excluded = parks.union_all().union(water.union_all())
# 从城市区域中减去排除区域
buildable_area = gpd.GeoSeries([city_area]).difference(excluded)
print(f"可建设面积: {buildable_area.iloc[0].area:.2f}")
12.4.4 擦除操作(Erase)
在传统 GIS 软件中,差集运算常被称为”擦除”(Erase)操作。GeoPandas 的 overlay 函数支持此操作:
# 使用 overlay 进行擦除
result = gpd.overlay(gdf1, gdf2, how='difference')
12.5 symmetric_difference() - 对称差
12.5.1 基本概念
symmetric_difference() 计算两个几何对象的对称差,结果包含属于 A 或 B,但不同时属于两者的点。
A.symmetric_difference(B) = (A ∪ B) - (A ∩ B)
= (A - B) ∪ (B - A)
12.5.2 代码示例
import geopandas as gpd
from shapely.geometry import Polygon
poly_a = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
poly_b = Polygon([(1, 1), (3, 1), (3, 3), (1, 3)])
gs = gpd.GeoSeries([poly_a])
result = gs.symmetric_difference(poly_b)
print(f"对称差面积: {result.iloc[0].area}") # 6.0
# A面积(4) + B面积(4) - 2×交集面积(1) = 6
print(f"对称差类型: {result.iloc[0].geom_type}") # MultiPolygon(两块不相连的区域)
12.5.3 对称差的性质
- 对称性:
A.symmetric_difference(B) == B.symmetric_difference(A) - 面积关系:
area(A △ B) = area(A) + area(B) - 2 × area(A ∩ B) - 等价表达:
A △ B = (A ∪ B) - (A ∩ B)
12.5.4 实际应用:变化检测
# 对比两个时期的城市建成区,找出变化区域
urban_2010 = gpd.read_file("urban_2010.shp").union_all()
urban_2020 = gpd.read_file("urban_2020.shp").union_all()
# 对称差即为变化区域(新增 + 减少)
changed_area = gpd.GeoSeries([urban_2010]).symmetric_difference(urban_2020)
# 分别计算新增和减少
newly_built = gpd.GeoSeries([urban_2020]).difference(urban_2010) # 新增区域
demolished = gpd.GeoSeries([urban_2010]).difference(urban_2020) # 减少区域
print(f"变化总面积: {changed_area.iloc[0].area:.2f}")
print(f"新增面积: {newly_built.iloc[0].area:.2f}")
print(f"减少面积: {demolished.iloc[0].area:.2f}")
12.6 snap() - 捕捉到几何
12.6.1 基本概念
snap() 方法将一个几何对象的顶点”捕捉”(snap)到另一个几何对象上最近的点,前提是两者的距离在指定的容差范围内。这在处理几何数据的微小不一致性时非常有用。
12.6.2 代码示例
import geopandas as gpd
from shapely.geometry import LineString, Point
# 两条几乎相连但有微小间隙的线
line_a = LineString([(0, 0), (1, 0)])
line_b = LineString([(1.01, 0), (2, 0)]) # 起点距离 line_a 终点 0.01
gs = gpd.GeoSeries([line_a])
# 将 line_a 捕捉到 line_b,容差 0.05
snapped = gs.snap(line_b, tolerance=0.05)
print(f"捕捉前终点: {list(line_a.coords)[-1]}")
print(f"捕捉后终点: {list(snapped.iloc[0].coords)[-1]}")
# 捕捉后 line_a 的终点会被移到 (1.01, 0)
12.6.3 实际应用
# 修复拓扑不一致:确保相邻多边形共享精确的边界
import geopandas as gpd
polygons = gpd.read_file("parcels.shp")
# 对于每对相邻多边形,将其捕捉到彼此
tolerance = 0.001 # 容差(与坐标系单位一致)
for i in range(len(polygons)):
for j in range(i + 1, len(polygons)):
if polygons.geometry.iloc[i].distance(polygons.geometry.iloc[j]) < tolerance:
# 将几何 i 捕捉到几何 j
polygons.geometry.iloc[i] = polygons.geometry.iloc[i].snap(
polygons.geometry.iloc[j], tolerance
)
12.6.4 注意事项
- 容差值应根据数据精度合理设置
- 过大的容差可能导致几何变形
snap()只移动在容差范围内的顶点
12.7 unary_union - 所有几何合并为一个
12.7.1 基本概念
unary_union 属性将一个 GeoSeries 中的所有几何对象合并为一个几何对象。这相当于对所有几何对象依次进行 union() 操作。
12.7.2 代码示例
import geopandas as gpd
from shapely.geometry import Polygon
# 创建多个多边形
gs = gpd.GeoSeries([
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
Polygon([(0.5, 0.5), (1.5, 0.5), (1.5, 1.5), (0.5, 1.5)]),
Polygon([(1, 1), (2, 1), (2, 2), (1, 2)]),
])
# 合并所有几何对象
merged = gs.unary_union
print(f"合并结果类型: {merged.geom_type}") # Polygon
print(f"合并结果面积: {merged.area}")
12.7.3 dissolve 操作
unary_union 常与 dissolve() 方法结合使用,按属性分组合并几何对象:
import geopandas as gpd
# 读取县级行政区数据
counties = gpd.read_file("counties.shp")
# 按省份名称分组合并,得到省级边界
provinces = counties.dissolve(by='province_name')
print(f"县级区域数: {len(counties)}")
print(f"省级区域数: {len(provinces)}")
12.7.4 注意事项
unary_union是一个属性(property),不是方法- 对于大量几何对象,
unary_union可能比较耗时 - 结果可能是 Polygon、MultiPolygon 或 GeometryCollection,取决于输入
12.8 union_all() 与 intersection_all() - 聚合运算
12.8.1 union_all() 方法
union_all() 是 unary_union 的方法版本,功能相同,但作为方法调用更加灵活。
import geopandas as gpd
from shapely.geometry import Polygon
gs = gpd.GeoSeries([
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
Polygon([(0.5, 0), (1.5, 0), (1.5, 1), (0.5, 1)]),
Polygon([(1, 0), (2, 0), (2, 1), (1, 1)]),
])
# 使用 union_all
merged = gs.union_all()
print(f"合并面积: {merged.area}") # 2.0
print(f"合并类型: {merged.geom_type}") # Polygon
12.8.2 intersection_all() 方法
intersection_all() 计算 GeoSeries 中所有几何对象的公共交集。
import geopandas as gpd
from shapely.geometry import Polygon
gs = gpd.GeoSeries([
Polygon([(0, 0), (2, 0), (2, 2), (0, 2)]),
Polygon([(0.5, 0.5), (2.5, 0.5), (2.5, 2.5), (0.5, 2.5)]),
Polygon([(1, 1), (3, 1), (3, 3), (1, 3)]),
])
# 计算所有几何对象的交集
common = gs.intersection_all()
print(f"公共区域面积: {common.area}") # 1.0
print(f"公共区域类型: {common.geom_type}") # Polygon
# 公共区域是 (1,1)-(2,1)-(2,2)-(1,2)
12.8.3 union_all vs unary_union
| 特性 | unary_union |
union_all() |
|---|---|---|
| 类型 | 属性 | 方法 |
| 调用方式 | gs.unary_union |
gs.union_all() |
| 功能 | 合并所有几何 | 合并所有几何 |
| 灵活性 | 无参数 | 可能有参数选项 |
| 推荐 | 传统用法 | 推荐用法 |
12.9 shared_paths() - 共享路径段
12.9.1 基本概念
shared_paths() 找出两个线性几何对象之间共享的路径段。返回的结果是一个 GeometryCollection,包含两类共享路径:
- 同方向共享的路径段
- 反方向共享的路径段
12.9.2 代码示例
import geopandas as gpd
from shapely.geometry import LineString, MultiLineString
# 两条部分重叠的线
line_a = LineString([(0, 0), (1, 0), (2, 0), (3, 0)])
line_b = LineString([(1, 0), (2, 0), (3, 0), (4, 0)])
gs = gpd.GeoSeries([line_a])
result = gs.shared_paths(line_b)
print(f"共享路径: {result.iloc[0]}")
# GeometryCollection,包含同方向和反方向的共享段
12.9.3 解读结果
from shapely.geometry import LineString
from shapely import shared_paths
line_a = LineString([(0, 0), (1, 0), (2, 0)])
line_b = LineString([(1, 0), (2, 0), (3, 0)])
result = shared_paths(line_a, line_b)
# result 是 GeometryCollection
# result.geoms[0]: 同方向共享段(MultiLineString)
# result.geoms[1]: 反方向共享段(MultiLineString)
print(f"同方向共享: {result.geoms[0]}")
print(f"反方向共享: {result.geoms[1]}")
12.9.4 实际应用
# 找出两条道路的共享路段
road_a = gpd.read_file("road_a.shp").geometry.iloc[0]
road_b = gpd.read_file("road_b.shp").geometry.iloc[0]
gs = gpd.GeoSeries([road_a])
shared = gs.shared_paths(road_b)
if not shared.iloc[0].is_empty:
print("两条道路有共享路段")
# 共享路段可能是同一条物理道路被两个数据源重复记录
12.10 shortest_line() - 最短连线
12.10.1 基本概念
shortest_line() 计算两个几何对象之间的最短连线。返回的是一条 LineString,其起点在第一个几何对象上,终点在第二个几何对象上。
12.10.2 代码示例
import geopandas as gpd
from shapely.geometry import Point, Polygon, LineString
# 点到多边形的最短连线
point = Point(5, 5)
poly = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
gs = gpd.GeoSeries([poly])
shortest = gs.shortest_line(point)
print(f"最短连线: {shortest.iloc[0]}")
print(f"最短距离: {shortest.iloc[0].length:.4f}") # 等于 distance()
12.10.3 多种几何类型
# 两条不相交的线之间的最短连线
line_a = LineString([(0, 0), (2, 0)])
line_b = LineString([(1, 1), (3, 1)])
gs = gpd.GeoSeries([line_a])
shortest = gs.shortest_line(line_b)
print(f"线到线最短连线: {shortest.iloc[0]}")
# LINESTRING (1 0, 1 1) - 垂直于两条线的连线
12.10.4 实际应用
# 为每个消防站找到最近的河流取水点
stations = gpd.read_file("fire_stations.shp")
rivers = gpd.read_file("rivers.shp")
# 合并所有河流为一个几何
all_rivers = rivers.union_all()
# 计算每个消防站到最近河流的最短连线
shortest_lines = stations.geometry.apply(
lambda pt: pt.shortest_line(all_rivers) if hasattr(pt, 'shortest_line')
else gpd.GeoSeries([pt]).shortest_line(all_rivers).iloc[0]
)
# 获取取水点(最短连线的终点)
water_access_points = shortest_lines.apply(
lambda line: Point(line.coords[-1])
)
12.11 project() 与 interpolate() - 线性参考
12.11.1 线性参考的概念
线性参考(Linear Referencing)是沿线性几何对象定位点的方法。它使用沿线距离而不是二维坐标来描述位置。
12.11.2 project() - 投影到线上
project() 计算一个点在线性几何对象上的投影位置,返回沿线距离。
import geopandas as gpd
from shapely.geometry import Point, LineString
# 创建线段
line = LineString([(0, 0), (10, 0)])
# 要投影的点
points = gpd.GeoSeries([
Point(3, 5), # 在线上方
Point(7, -3), # 在线下方
Point(-2, 1), # 在线起点之前
Point(12, 2), # 在线终点之后
])
gs_line = gpd.GeoSeries([line] * 4)
# 计算沿线距离
distances = gs_line.project(points)
print(distances)
# 0 3.0 (投影到 (3, 0),沿线距离 3)
# 1 7.0 (投影到 (7, 0),沿线距离 7)
# 2 0.0 (投影到起点 (0, 0),限制为 0)
# 3 10.0 (投影到终点 (10, 0),限制为 10)
# 归一化距离(0-1范围)
normalized = gs_line.project(points, normalized=True)
print(normalized)
# 0 0.3
# 1 0.7
# 2 0.0
# 3 1.0
12.11.3 interpolate() - 沿线插值
interpolate() 根据沿线距离在线性几何对象上找到对应的点。
import geopandas as gpd
from shapely.geometry import LineString
# 创建线段
line = LineString([(0, 0), (5, 0), (5, 5)])
gs = gpd.GeoSeries([line, line, line])
distances = gpd.array.GeometryDtype # 不同距离
# 沿线不同距离处插值
result = gs.interpolate([2.0, 5.0, 8.0])
print(result)
# 0 POINT (2 0) 距离 2: 在第一段上
# 1 POINT (5 0) 距离 5: 在转折点
# 2 POINT (5 3) 距离 8: 在第二段上
# 使用归一化距离
total_length = line.length # 10.0
result_norm = gs.interpolate([0.2, 0.5, 0.8], normalized=True)
print(result_norm)
12.11.4 project 与 interpolate 的互逆关系
from shapely.geometry import LineString, Point
line = LineString([(0, 0), (5, 0), (5, 5)])
# 从点投影得到距离
point = Point(3, 2)
distance = line.project(point)
print(f"投影距离: {distance}")
# 从距离反插值得到线上的点
projected_point = line.interpolate(distance)
print(f"线上投影点: {projected_point}")
# 这是 point 在 line 上的最近点
12.11.5 实际应用:里程标记
import geopandas as gpd
from shapely.geometry import LineString, Point
# 道路中心线
road = LineString([(0, 0), (100, 0), (100, 50), (200, 50)])
# 每隔 50 米设置一个里程标记
gs = gpd.GeoSeries([road])
total_length = road.length
markers = []
distance = 0
while distance <= total_length:
point = road.interpolate(distance)
markers.append({
'distance': distance,
'geometry': point
})
distance += 50
markers_gdf = gpd.GeoDataFrame(markers)
print(f"共设置 {len(markers_gdf)} 个里程标记")
12.12 集合运算的对齐机制
12.12.1 align 参数
与空间谓词类似,集合运算方法也支持 align 参数来控制两个 GeoSeries 之间的索引对齐行为。
import geopandas as gpd
from shapely.geometry import Polygon
# 不同索引的 GeoSeries
gs1 = gpd.GeoSeries(
[Polygon([(0,0),(2,0),(2,2),(0,2)])],
index=[0]
)
gs2 = gpd.GeoSeries(
[Polygon([(1,1),(3,1),(3,3),(1,3)])],
index=[1]
)
# align=True(默认)
result_aligned = gs1.intersection(gs2, align=True)
print(f"对齐后结果长度: {len(result_aligned)}")
# 索引 0 和 1 都会出现,不匹配的变为 NaN
# align=False
result_positional = gs1.intersection(gs2, align=False)
print(f"按位置结果: {result_positional.iloc[0]}")
# 按位置配对:gs1[位置0] ∩ gs2[位置0]
12.12.2 最佳实践
- 当两个 GeoSeries 索引相同时,
align参数无影响 - 当与单个几何对象操作时,
align参数无影响 - 建议在进行集合运算前先确认索引是否一致
12.13 性能考虑
12.13.1 大数据集的性能优化
几何集合运算在大数据集上可能比较耗时。以下是一些优化建议:
使用空间索引预筛选
import geopandas as gpd
from shapely.geometry import Polygon
# 而不是对所有要素进行集合运算,先用空间索引筛选
gdf = gpd.read_file("large_dataset.shp")
clip_area = Polygon([(...)])
# 先筛选可能相交的要素
possible_idx = gdf.sindex.query(clip_area, predicate='intersects')
candidates = gdf.iloc[possible_idx]
# 只对候选要素进行精确运算
result = candidates.intersection(clip_area)
分批处理
import numpy as np
# 对于大型 unary_union,可以分批处理
def batch_union(geometries, batch_size=1000):
"""分批合并几何对象"""
batches = [geometries[i:i+batch_size]
for i in range(0, len(geometries), batch_size)]
partial_unions = [gpd.GeoSeries(batch).union_all()
for batch in batches]
return gpd.GeoSeries(partial_unions).union_all()
12.13.2 常见性能陷阱
| 问题 | 说明 | 解决方案 |
|---|---|---|
| 大规模 unary_union | 数万个几何对象合并很慢 | 分批合并 |
| 逐行循环运算 | Python 循环慢 | 使用向量化操作 |
| 无空间索引 | 暴力搜索所有几何对象 | 使用 sindex 预筛选 |
| 复杂几何 | 高顶点数几何运算慢 | 先简化再运算 |
12.13.3 overlay vs 手动集合运算
GeoPandas 的 overlay() 函数封装了常用的集合运算,并自动处理属性合并:
import geopandas as gpd
gdf1 = gpd.read_file("layer1.shp")
gdf2 = gpd.read_file("layer2.shp")
# overlay 支持的运算类型
result_union = gpd.overlay(gdf1, gdf2, how='union')
result_intersection = gpd.overlay(gdf1, gdf2, how='intersection')
result_difference = gpd.overlay(gdf1, gdf2, how='difference')
result_sym_diff = gpd.overlay(gdf1, gdf2, how='symmetric_difference')
result_identity = gpd.overlay(gdf1, gdf2, how='identity')
overlay() 的优势:
- 自动处理属性列的合并
- 自动处理空间索引优化
- API 更简洁
12.14 本章小结
本章全面介绍了 GeoPandas 中的集合运算与几何操作方法。主要内容回顾:
核心集合运算
| 运算 | 方法 | 说明 |
|---|---|---|
| 合并 | union() |
A ∪ B |
| 交集 | intersection() |
A ∩ B |
| 差集 | difference() |
A \ B |
| 对称差 | symmetric_difference() |
A △ B |
聚合运算
| 方法 | 说明 |
|---|---|
unary_union |
合并所有几何为一个(属性) |
union_all() |
合并所有几何为一个(方法) |
intersection_all() |
求所有几何的公共交集 |
其他操作
| 方法 | 说明 |
|---|---|
snap() |
捕捉到另一个几何 |
shared_paths() |
查找共享路径段 |
shortest_line() |
计算最短连线 |
project() |
线性参考:投影距离 |
interpolate() |
线性参考:沿线插值 |
使用建议
- 选择合适的方法:简单运算用逐元素方法,批量运算用
overlay() - 注意对齐:两个 GeoSeries 操作时注意
align参数 - 性能优化:大数据集使用空间索引预筛选
- 结果验证:检查结果的几何类型和有效性
- 坐标系一致:确保参与运算的几何对象使用相同的坐标系
下一章我们将学习构造性几何操作,探索如何从已有几何对象中构造新的几何特征。