znlgis 博客

GIS开发与技术分享

第十章:空间分析步骤详解

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_kdesklearn.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 聚类,识别空间热点和服务分区

下一章将介绍网络分析步骤:最短路径、服务区分析和地理编码。