如何使用GeoPandas统计多边形指定半径范围内的点数量
统计城市指定半径内公园数量的实现方案
你设想的「生成缓冲区-判断点是否落在缓冲区内」的思路是可行的,但首先要修正一个核心问题:你当前两个图层都是EPSG:4326(WGS84经纬度坐标系),坐标单位是「度」,直接传入数值做buffer得到的范围不是真实地理距离,误差会随纬度升高变大,必须先转成单位为米的投影坐标系再做计算。
具体实现步骤
1. 数据读取与坐标系预处理
先校验两个图层坐标系一致性,再转到研究区对应的米制投影坐标系(比如你给出的坐标范围<34-35E,32N>属于以色列区域,可直接用EPSG:2039以色列当地投影;如果是其他区域替换成对应UTM/本地投影即可)。
import geopandas as gpd import matplotlib.pyplot as plt # 读取原始shp文件 cities = gpd.read_file('geo_cities_f.shp') parks = gpd.read_file('geo_parks_f.shp') # 校验两个图层坐标系是否一致 if cities.crs != parks.crs: raise ValueError("两个图层坐标系不匹配,请先做空间配准统一CRS") # 转换到米制投影坐标系,替换epsg编码为你研究区对应值 cities_proj = cities.to_crs(epsg=2039) parks_proj = parks.to_crs(epsg=2039)
2. 生成城市指定半径缓冲区
buffer参数直接传入真实搜索半径,单位为米,比如要统计1公里范围就传1000:
# 定义搜索半径,单位:米 search_radius = 1000 # 生成每个城市的缓冲区多边形 cities_buffer = cities_proj.copy() cities_buffer.geometry = cities_proj.geometry.buffer(search_radius)
3. 空间匹配统计公园数量
不用手写循环遍历,直接用geopandas内置的空间连接方法,效率远高于手写循环,还能自动处理空间关系判断:
# 空间连接:匹配所有落在城市缓冲区内的公园点 parks_in_range = gpd.sjoin( parks_proj, cities_buffer, how="inner", predicate="within" ) # 按城市维度统计公园数量,把city_name替换成你城市图层里的城市名称/ID字段即可 city_park_stat = parks_in_range.groupby("city_name").size().reset_index(name="park_count_in_radius") # 把统计结果合并回原始城市图层,没有匹配到公园的城市数量填充为0 cities_stat = cities_proj.merge(city_park_stat, on="city_name", how="left") cities_stat["park_count_in_radius"] = cities_stat["park_count_in_radius"].fillna(0).astype(int) # 如果要统计所有城市覆盖范围内的去重公园总数,直接取唯一公园ID的计数即可 # total_park = parks_in_range["park_id"].nunique()
4. (可选)结果可视化
用投影后的数据绘图比例更准确:
fig, ax = plt.subplots(figsize=(14,14)) cities_buffer.plot(ax=ax, color="#e6f3ff", edgecolor="#4080ff", alpha=0.5, label=f"{search_radius}m 城市缓冲区") cities_proj.plot(ax=ax, color="#4080ff", edgecolor="black", label="城市建成区边界") parks_proj.plot(ax=ax, color="red", markersize=12, label="公园点位") ax.legend() plt.show()
注意事项
- 禁止直接在EPSG:4326经纬度坐标系下做距离相关计算,你之前代码里写的
buffer(0.0004)对应的实际距离会随纬度波动,计算结果没有参考价值。 - 如果一个公园同时落在多个城市的缓冲区内,空间连接会给这个公园生成多条匹配记录,统计全域总公园数时记得按公园唯一ID去重。
- 如果你的数据量超过10万条,可以给图层建空间索引进一步提升计算速度,geopandas默认会自动创建索引,不需要额外操作。
内容的提问来源于stack exchange,提问作者ReyManzarek
相关产品推荐
相关产品推荐

