Python 3.11 实现两步移动搜索法:GIS 可达性分析 5 行核心代码解析

📅 2026/7/11 9:16:06 👁️ 阅读次数 📝 编程学习
Python 3.11 实现两步移动搜索法:GIS 可达性分析 5 行核心代码解析

Python 3.11 实现两步移动搜索法:GIS 可达性分析 5 行核心代码解析

在城市规划与公共服务设施布局研究中,空间可达性分析一直是核心课题。而两步移动搜索法(2SFCA)作为该领域的经典算法,其Python实现却鲜有简洁明了的教程。本文将用最新Python 3.11特性,带你用5行核心代码完成2SFCA算法的地理数据处理全流程。

1. 环境配置与数据准备

首先确保安装以下库(Python 3.11+环境):

pip install geopandas pandas numpy shapely

典型输入数据应包含两个GeoDataFrame:

  • 需求点(如居民区):包含人口字段和几何点
  • 供给点(如医院):包含服务能力字段和几何点
import geopandas as gpd demand = gpd.read_file('population.shp') # 包含'population'字段 supply = gpd.read_file('hospitals.shp') # 包含'beds'字段

注意:几何列必须为Point类型,坐标系建议使用WGS84(EPSG:4326)或适合当地的距离计算投影。

2. 距离矩阵的高效计算

传统GIS教学常使用双重循环计算距离,但在Python中我们可以用向量化操作提升百倍性能:

from shapely.geometry import Point def calculate_distance_matrix(demand, supply, max_distance): # 生成坐标数组 demand_coords = np.array([[p.x, p.y] for p in demand.geometry]) supply_coords = np.array([[p.x, p.y] for p in supply.geometry]) # 使用scipy的cdist计算球面距离(单位:米) dist_matrix = cdist(demand_coords, supply_coords, metric='euclidean') return np.where(dist_matrix <= max_distance, dist_matrix, np.nan)

关键参数说明:

  • max_distance:搜索半径(根据研究场景设定,如1500米)
  • metric:可根据需要替换为'haversine'(球面距离)

3. 两步移动搜索法的核心实现

以下是2SFCA算法的浓缩实现,仅用5行代码完成计算:

def two_step_floating_catchment(demand, supply, max_distance): dist_matrix = calculate_distance_matrix(demand, supply, max_distance) # 第一步:计算每个供给点的供需比Rj supply['Rj'] = supply['beds'] / np.nansum( demand['population'][:, None] * (dist_matrix <= max_distance), axis=0) # 第二步:计算每个需求点的可达性Ai demand['Ai'] = np.nansum( supply['Rj'][None, :] * (dist_matrix <= max_distance), axis=1) return demand

算法对应数学公式:

  1. 供需比计算:$R_j = \frac{S_j}{\sum_{k \in {d_{kj} \leq d_0}} P_k}$
  2. 可达性计算:$A_i = \sum_{j \in {d_{ij} \leq d_0}} R_j$

4. 高级优化与可视化

对于大规模数据,可采用以下优化策略:

空间索引加速

from geopandas.sindex import SpatialIndex supply_sindex = SpatialIndex(supply.geometry) # 在距离计算前先进行粗略筛选 candidates = list(supply_sindex.intersection(demand.geometry[i].bounds))

并行计算优化(Python 3.11新增特性):

from concurrent.futures import ThreadPoolExecutor def parallel_2sfca(chunk): return two_step_floating_catchment(chunk, supply, max_distance) with ThreadPoolExecutor() as executor: results = list(executor.map(parallel_2sfca, np.array_split(demand, 4)))

可视化示例(使用matplotlib):

import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(10, 8)) demand.plot(column='Ai', legend=True, ax=ax, cmap='RdYlGn', scheme='quantiles') supply.plot(ax=ax, color='black', markersize=5) plt.title('医疗服务可达性分析')

5. 实际应用中的注意事项

参数敏感性分析

参数典型值影响分析
搜索半径500-3000米值越小,可达性差异越显著
距离衰减函数线性/高斯决定边界效应强度
服务能力指标床位数/医生数反映不同资源类型

常见问题排查

  1. 结果全为NaN:检查坐标系是否一致
  2. 计算时间过长:尝试使用Dask加速
  3. 可达性值异常:检查输入数据的数值范围

在最近的城市更新项目中,这套代码帮助我们在15分钟内完成了20万+居民点的可达性评估。相比传统GIS软件,Python实现的优势在于可以灵活嵌入到自动化分析流程中,特别是当需要定期更新评估或进行多情景对比时。