第十章:空间分析步骤详解
10.1 概述
空间分析步骤(前缀 analysis)提供高级 GIS 空间分析功能,共 4 个步骤:
| 步骤 ID | 名称 | 主要功能 | 依赖包 |
|---|---|---|---|
analysis.voronoi |
泰森多边形 | 基于点生成 Voronoi 图 | scipy + shapely |
analysis.heatmap |
核密度热力图 | 点要素的核密度估计 | scipy + matplotlib |
analysis.interpolate |
空间插值 | 离散点数据插值为栅格 | scipy |
analysis.cluster |
空间聚类 | DBSCAN/KMeans 聚类 | scikit-learn |
安装依赖:使用空间分析步骤前需安装 analysis 可选依赖:
pip install -e ".[analysis]"
10.2 analysis.voronoi
功能说明
根据输入点要素集生成泰森多边形(Voronoi 图/Thiessen Polygons)。每个多边形代表距离对应输入点最近的区域。
底层使用 scipy 的 Voronoi 算法 + shapely 的几何操作。
参数说明
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
input |
ref | ✅ | — | 输入点 GeoDataFrame |
clip |
ref | ❌ | None | 裁剪范围(Polygon GeoDataFrame),无限延伸的 Voronoi 边会被裁剪 |
tolerance |
float | ❌ | 0.0 | 输入点的坐标精度阈值,过近的点可能导致数值问题 |
使用示例
# 基本泰森多边形
- id: load-stations
use: io.read_vector
params:
path: "data/weather_stations.shp"
- id: voronoi
use: analysis.voronoi
params:
input: $load-stations
# 裁剪到研究区域内
- id: load-boundary
use: io.read_vector
params:
path: "data/boundary.geojson"
- id: voronoi-clipped
use: analysis.voronoi
params:
input: $load-stations
clip: $load-boundary
典型应用场景
- 气象站服务区划分:每个气象站负责覆盖其最近的区域
- 设施服务区分析:学校、医院、超市等设施的理论服务区
- 地质分析:基于控制点的区域划分
- 坐标系注意:建议使用投影坐标系,地理坐标系下泰森多边形的”最近”基于欧氏距离而非球面距离
# 完整示例(含投影)
steps:
- id: load-facilities
use: io.read_vector
params:
path: "data/hospitals.shp"
- id: proj-facilities
use: vector.reproject
params:
input: $load-facilities
target_crs: "EPSG:3857"
- id: load-city
use: io.read_vector
params:
path: "data/city_boundary.geojson"
- id: proj-city
use: vector.reproject
params:
input: $load-city
target_crs: "EPSG:3857"
- id: voronoi
use: analysis.voronoi
params:
input: $proj-facilities
clip: $proj-city
- id: save
use: io.write_vector
params:
input: $voronoi
path: "output/hospital_service_areas.geojson"
10.3 analysis.heatmap
功能说明
使用核密度估计(KDE,Kernel Density Estimation)生成点要素的热力图栅格。
底层使用 scipy 的 gaussian_kde 或 sklearn.neighbors.KernelDensity。
参数说明
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
input |
ref | ✅ | — | 输入点 GeoDataFrame |
bandwidth |
float | ❌ | 自动(Scott 法则) | KDE 带宽,影响平滑程度 |
resolution |
int | ❌ | 100 | 输出栅格的像素分辨率(每边像素数) |
weight_field |
str | ❌ | None | 权重字段名称(不指定则每点权重相同) |
bbox |
list | ❌ | 自动计算 | 输出范围 [minx, miny, maxx, maxy] |
使用示例
# 基本热力图(事故点密度分析)
- id: load-accidents
use: io.read_vector
params:
path: "data/traffic_accidents.shp"
- id: heatmap
use: analysis.heatmap
params:
input: $load-accidents
bandwidth: 500 # 500 米平滑半径(投影坐标系)
resolution: 200 # 200×200 像素
# 加权热力图(按事故严重程度加权)
- id: heatmap-weighted
use: analysis.heatmap
params:
input: $load-accidents
bandwidth: 500
resolution: 200
weight_field: "severity" # 字段值越大,该点对热力图贡献越大
# 保存热力图为 GeoTIFF
- id: save-heatmap
use: io.write_raster
params:
input: $heatmap
path: "output/accident_heatmap.tif"
带宽选择建议
带宽(bandwidth)控制核密度的平滑程度:
- 过小:热力图过于”尖锐”,出现很多孤立高峰
- 过大:热力图过于”模糊”,失去细节
- 推荐:以研究区域的合理影响范围作为参考(步行可达距离、视觉感知范围等)
10.4 analysis.interpolate
功能说明
将离散的点数据(带属性值)插值为连续的栅格面,支持多种插值方法。
参数说明
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
input |
ref | ✅ | — | 输入点 GeoDataFrame(必须有属性值字段) |
field |
str | ✅ | — | 用于插值的数值属性字段名 |
method |
str | ❌ | "idw" |
插值方法:idw(反距离加权)/linear(线性)/nearest(最近邻)/cubic(三次样条) |
resolution |
int | ❌ | 100 | 输出栅格分辨率 |
power |
float | ❌ | 2.0 | IDW 的距离幂次(仅用于 idw 方法) |
bbox |
list | ❌ | 自动 | 输出范围 |
插值方法对比
| 方法 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
idw |
距离加权平均 | 直观,不外推超范围值 | 受幂次参数影响大 | 通用,推荐首选 |
linear |
三角网线性插值(Delaunay) | 快速,无参数 | 只在三角网内插值 | 均匀分布的采样点 |
nearest |
最近邻 | 极快 | 不平滑,呈阶梯状 | 分类数据、调试 |
cubic |
三次样条 | 平滑 | 可能外推异常值 | 高质量连续数据 |
使用示例
# IDW 插值(降雨量空间分布)
- id: load-rainfall
use: io.read_vector
params:
path: "data/rain_stations.shp"
- id: interpolate-rain
use: analysis.interpolate
params:
input: $load-rainfall
field: "rainfall_mm"
method: idw
resolution: 200
power: 2.0
# 线性插值(温度分布)
- id: interpolate-temp
use: analysis.interpolate
params:
input: $load-stations
field: "temperature"
method: linear
resolution: 150
# 裁剪到研究区域
- id: clip-interpolated
use: raster.clip
params:
input: $interpolate-rain
mask: $load-boundary
# 保存插值结果
- id: save-interpolated
use: io.write_raster
params:
input: $clip-interpolated
path: "output/rainfall_interpolated.tif"
典型应用场景
- 气象要素空间分布:温度、降水、风速的面状分布
- 地下水位:监测井数据插值
- 污染物浓度:环境监测点数据空间化
- 土壤属性:采样点数据插值为土壤图
10.5 analysis.cluster
功能说明
对点要素进行空间聚类分析,将地理位置相近的点归为同一簇,并将聚类标签写回属性。
参数说明
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
input |
ref | ✅ | — | 输入点 GeoDataFrame |
method |
str | ❌ | "dbscan" |
聚类算法:dbscan / kmeans |
eps |
float | ❌ | 500.0 | DBSCAN 邻域半径(仅用于 dbscan,单位与 CRS 一致) |
min_samples |
int | ❌ | 5 | DBSCAN 最小邻域点数(仅用于 dbscan) |
n_clusters |
int | ❌ | 5 | KMeans 簇数量(仅用于 kmeans) |
output_field |
str | ❌ | "cluster_id" |
聚类标签输出字段名 |
DBSCAN vs KMeans
| 维度 | DBSCAN | KMeans |
|---|---|---|
| 原理 | 基于密度,自动发现簇数量 | 基于距离,需预先指定簇数量 |
| 簇形状 | 任意形状 | 球形(凸形) |
| 噪声处理 | 将低密度点标记为 -1(噪声) | 所有点都属于某个簇 |
| 参数 | eps(邻域半径)+ min_samples |
n_clusters(簇数量) |
| 适用场景 | 发现自然聚集的热点区域 | 将数据等分为若干组 |
使用示例
# DBSCAN 聚类(犯罪热点识别)
- id: load-crimes
use: io.read_vector
params:
path: "data/crime_points.shp"
- id: proj-crimes
use: vector.reproject
params:
input: $load-crimes
target_crs: "EPSG:3857"
- id: cluster-crimes
use: analysis.cluster
params:
input: $proj-crimes
method: dbscan
eps: 300 # 300 米内的事件归为同一簇
min_samples: 5 # 至少 5 个事件才形成热点
output_field: "hotspot_id"
# 过滤掉噪声点(cluster_id == -1 为 DBSCAN 噪声)
- id: filter-clusters
use: vector.query
params:
input: $cluster-crimes
expr: "hotspot_id >= 0"
# KMeans 聚类(将设施分配到 N 个服务分区)
- id: cluster-facilities
use: analysis.cluster
params:
input: $load-facilities
method: kmeans
n_clusters: 5
output_field: "zone_id"
# 融合同簇点,计算各簇范围
- id: dissolve-clusters
use: vector.dissolve
params:
input: $cluster-crimes
by: "hotspot_id"
- id: save
use: io.write_vector
params:
input: $cluster-crimes
path: "output/crime_clusters.geojson"
10.6 综合示例:公共设施密度分析
name: 公共设施密度分析
description: 对城市 POI 数据进行聚类和核密度分析,识别服务热点
variables:
poi_path: "data/poi.shp"
boundary_path: "data/city.geojson"
cluster_eps: 200 # 聚类半径 200 米
cluster_min: 3 # 最少 3 个点形成簇
heatmap_bw: 500 # 热力图带宽 500 米
steps:
- id: load-poi
use: io.read_vector
params:
path: ${poi_path}
- id: load-city
use: io.read_vector
params:
path: ${boundary_path}
# 投影到 EPSG:3857
- id: proj-poi
use: vector.reproject
params:
input: $load-poi
target_crs: "EPSG:3857"
- id: proj-city
use: vector.reproject
params:
input: $load-city
target_crs: "EPSG:3857"
# 裁剪到城区内
- id: clip-poi
use: vector.clip
params:
input: $proj-poi
clip: $proj-city
# DBSCAN 聚类
- id: cluster
use: analysis.cluster
params:
input: $clip-poi
method: dbscan
eps: ${cluster_eps}
min_samples: ${cluster_min}
output_field: "cluster_id"
# 核密度热力图
- id: heatmap
use: analysis.heatmap
params:
input: $clip-poi
bandwidth: ${heatmap_bw}
resolution: 300
# 泰森多边形(若为设施类 POI)
- id: voronoi
use: analysis.voronoi
params:
input: $clip-poi
clip: $proj-city
on_error: skip # 点数过少时可能失败,跳过
# 保存结果
- id: save-clusters
use: io.write_vector
params:
input: $cluster
path: "output/poi_clusters.geojson"
- id: save-heatmap
use: io.write_raster
params:
input: $heatmap
path: "output/poi_heatmap.tif"
- id: save-voronoi
use: io.write_vector
params:
input: $voronoi
path: "output/poi_voronoi.geojson"
on_error: skip
outputs:
clusters: $save-clusters
heatmap: $save-heatmap
10.7 小结
本章介绍了 GeoPipeAgent 的 4 个空间分析步骤(需 [analysis] 依赖):
analysis.voronoi:泰森多边形,基于点集划分最近服务区analysis.heatmap:核密度热力图,适合点密度可视化和分析analysis.interpolate:空间插值(IDW/线性/最近邻/三次样条),适合气象、环境数据空间化analysis.cluster:DBSCAN/KMeans 聚类,识别空间热点和服务分区
下一章将介绍网络分析步骤:最短路径、服务区分析和地理编码。