You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取GeoDataFrame的Voronoi面积?关联初始点与多边形方法

高效匹配Voronoi多边形与初始点并计算面积

问题说明

用Shapely生成Voronoi图时,输出的多边形顺序和初始点顺序不对应,直接按顺序给GeoDataFrame赋值面积会出错。现有代码直接将voronoi_diagram输出的多边形面积按列表顺序赋值,但数据量达数百万级,逐点判断"点是否在多边形内"的方式效率极低,需要更高效的方案,同时减少不必要的格式转换。

当前问题代码:

# gdf = is a GeoDataFrame
minx, miny, maxx, maxy = gdf.total_bounds
bound = Polygon([(minx, miny),
                    (maxx, miny),
                    (maxx, maxy),
                    (minx, maxy)])
points = MultiPoint(gdf.geometry.to_list())
parcels = voronoi_diagram(points , envelope=bound)
areas = [p.area for p in parcels]
gdf['area'] = areas

解决方案

方案一:基于Scipy Voronoi的索引映射(百万级数据首选)

Shapely的voronoi_diagram底层依赖Scipy的Voronoi实现,可直接通过索引映射关联初始点与对应多边形,时间复杂度O(n),无需逐点判断:

from scipy.spatial import Voronoi
import numpy as np
from shapely.geometry import Polygon

# 提取与gdf行顺序一致的坐标数组
coords = np.array([(p.x, p.y) for p in gdf.geometry])
vor = Voronoi(coords)

# 构建边界多边形
minx, miny, maxx, maxy = gdf.total_bounds
bound_poly = Polygon([(minx, miny), (maxx, miny), (maxx, maxy), (minx, maxy)])

areas = []
for i in range(len(coords)):
    # 获取当前点对应的Voronoi区域索引
    region_idx = vor.point_region[i]
    region = vor.regions[region_idx]
    
    # 处理无效区域(边界外或无顶点的情况)
    if not region or -1 in region:
        poly_coords = [vor.vertices[j] for j in region if j != -1]
        if poly_coords:
            vor_poly = Polygon(poly_coords)
            # 裁剪到边界内计算面积
            clipped_poly = vor_poly.intersection(bound_poly)
            areas.append(clipped_poly.area)
        else:
            areas.append(0.0)
    else:
        # 构建有效Voronoi多边形并计算面积
        vor_poly = Polygon([vor.vertices[j] for j in region])
        areas.append(vor_poly.area)

# 赋值回GeoDataFrame
gdf['area'] = areas

方案二:基于Shapely空间索引的批量匹配

如果不想引入Scipy,可利用Shapely的STRtree构建空间索引,将查询复杂度降至O(n log n):

from shapely.strtree import STRtree

points = MultiPoint(gdf.geometry.to_list())
parcels = list(voronoi_diagram(points, envelope=bound))

# 构建多边形空间索引
tree = STRtree(parcels)
# 批量查询每个点对应的包含它的多边形
matches = tree.query(gdf.geometry, predicate='contains')

# 整理点与多边形的对应关系(Voronoi特性保证一个点对应唯一多边形)
point_to_poly = {match[1]: match[0] for match in matches}
# 按原始点顺序提取面积
areas = [parcels[point_to_poly[i]].area for i in range(len(gdf))]

gdf['area'] = areas

内容的提问来源于stack exchange,提问作者Giacomo Catenazzi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 14:01:05