【实战教程】用GeoPandas征服空间数据:空间连接与地理计算全面指南
引言
在地理信息系统(GIS)领域,空间连接和地理计算是处理地理数据的核心能力。GeoPandas作为Python生态系统中最强大的地理数据分析库,提供了丰富的工具和方法来执行这些操作。本文将深入探讨GeoPandas中的空间连接和地理计算功能,通过实际案例讲解如何应用这些技术解决实际问题。
1. 准备工作:环境配置
首先,确保安装了必要的库:
# 安装必要的库
!pip install geopandas matplotlib contextily rtree shapely
# 导入库
import geopandas as gpd
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import contextily as ctx
from shapely.geometry import Point, LineString, Polygon
2. 空间连接基础概念
2.1 什么是空间连接?
空间连接是根据地理对象之间的空间关系合并数据集的操作。与传统数据库连接使用共同的键值不同,空间连接使用几何关系(如相交、包含、覆盖)作为连接条件。
2.2 空间连接的类型
GeoPandas提供了多种空间连接方法:
- 左连接(left join): 保留左侧DataFrame的所有记录
- 右连接(right join): 保留右侧DataFrame的所有记录
- 内连接(inner join): 仅保留两侧都满足空间关系的记录
2.3 常见空间关系
GeoPandas支持以下空间关系类型:
intersects
: 两个几何对象有任何交集contains
: 一个几何对象完全包含另一个within
: 一个几何对象完全在另一个内部touches
: 两个几何对象的边界相接触但内部不相交crosses
: 两个几何对象有部分但不完全重叠overlaps
: 两个几何对象有部分重叠且维度相同
3. 实际案例:城市POI与行政区划分析
3.1 加载数据
让我们加载一些示例数据:
# 加载行政区划数据
districts = gpd.read_file("districts.geojson")
# 创建POI点数据
poi_data = {
'name': ['咖啡店A', '餐厅B', '商场C', '学校D', '医院E', '公园F', '图书馆G', '超市H'],
'type': ['餐饮', '餐饮', '购物', '教育', '医疗', '休闲', '文化', '购物'],
'latitude': [39.91, 39.92, 39.93, 39.89, 39.91, 39.88, 39.90, 39.94],
'longitude': [116.41, 116.42, 116.39, 116.38, 116.44, 116.43, 116.41, 116.40]
}
# 创建点几何
geometry = [Point(xy) for xy in zip(poi_data['longitude'], poi_data['latitude'])]
pois = gpd.GeoDataFrame(poi_data, geometry=geometry, crs="EPSG:4326")
3.2 点与多边形的空间连接
我们将POI点与行政区划进行空间连接,确定每个POI点位于哪个行政区内:
# 确保坐标系统一致
districts = districts.to_crs(pois.crs)
# 执行空间连接 - 点位于哪个区域
joined_data = gpd.sjoin(pois, districts, how="left", predicate="within")
print(f"连接后的数据包含 {
len(joined_data)} 行,其中包括点位信息和所在区域")
3.3 结果可视化
# 绘制底图
fig, ax = plt.subplots(figsize=(12, 10))
# 绘制区域边界
districts.boundary.plot(ax=ax, color='black', linewidth=1)
# 使用分类变量绘制不同类型的POI
pois.plot(ax=ax, column='type', cmap='viridis',
legend=True, markersize=100, categorical=True)
# 添加标题
plt.title('POI分布与行政区划', fontsize=15)
# 添加背景底图
ctx.add_basemap(ax, crs=pois.crs.to_string(), source=ctx.providers.CartoDB.Positron)
plt.tight_layout()
plt.show()
4. 高级空间连接操作
4.1 不同谓词的空间连接
我们可以使用不同的空间关系谓词来执行空间连接:
# 使用不同空间关系进行连接
within_join = gpd.sjoin(pois, districts, how="inner", predicate="within")
intersects_join = gpd.sjoin(pois, districts, how="inner", predicate="intersects")
print(f"within连接结果: {
len(within_join)} 行")
print(f"intersects连接结果: {
len(intersects_join)} 行")
# 对于点数据,"within"和"intersects"通常产生相同结果
# 但对于线或面数据则不同
4.2 空间连接与属性筛选结合
我们可以将空间连接与常规数据筛选结合使用:
# 筛选特定类型的POI并确定它们所在的行政区
restaurant_pois = pois[pois['type'] == '餐饮']
restaurant_districts = gpd.sjoin(restaurant_pois, districts, how="left", predicate="within")
# 统计每个行政区内餐饮POI的数量
poi_count_by_district = restaurant_districts.groupby('district_name').size()
print("各行政区餐饮POI数量统计:")
print(poi_count_by_district)
5. 地理计算核心操作
5.1 几何操作:缓冲区分析
缓冲区分析是地理空间分析中最常用的操作之一,用于创建围绕几何要素的区域:
# 为每个POI创建500米缓冲区
# 首先将数据转换为投影坐标系统以使用米为单位
pois_projected = pois.to_crs(epsg=3857) # Web Mercator投影
pois_buffered = pois_projected.copy()
pois_buffered['geometry'] = pois_projected.buffer(500) # 500米缓冲区
# 转回原始坐标系进行显示
pois_buffered = pois_buffered.to_crs(pois.crs)
# 绘制缓冲区
fig, ax = plt.subplots(figsize=(12, 10))
districts.boundary.plot(ax=ax, color='black', linewidth=1)
pois_buffered.plot(ax=ax, alpha=0.5, column='type', categorical=True)
pois.plot(ax=ax, color='red', markersize=20