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

如何在Pandas中高效聚合多列,快速生成点集凸包

问题描述

我有一个存储对象ID及对应单个X、Y坐标的DataFrame,结构如下:

IDXY
100
113
125
271
285
297

无法保证ID或X/Y的顺序,也无法在上游调整该关联。最终目标是获取这些点的凸包(convex hull),当前做法是先将X/Y分组聚合为列表,再打包为元组列表,转换为Shapely的MultiPoint后计算凸包,代码如下:

import shapely.geometry as shGeom
sf = df.groupby("ID").agg({"X": list, "Y": list})
# 我希望后续保留该坐标集合,存储为MultiPoint也可以。
# 测试发现,由于内存压力,存储MultiPoint作为中间步骤比存储元组列表更慢
sf["coordinates"] = shapeFrame[["Y", "X"]].apply(lambda x: [(a,b) for a, b in zip(x[0], x[1])], axis= 1)
# 下面的"hull"列是最终目标列
sf["hull"] = sf["coordinates"].apply(lambda x: shGeom.MultiPoint(x).convex_hull)

但该方法需对百万行级DataFrame多次遍历,尤其是打包步骤速度极慢。请问是否有减少数据遍历次数的优化方案?后续会使用GeoPandas,但在将X/Y转换为Point或MultiPolygon前无可用几何列,无法避开该慢步骤。


优化方案

方案1:用Numpy向量化聚合,跳过Python循环打包

利用Numpy数组的C级操作替代Python列表推导,彻底避免低效的坐标打包循环:

import numpy as np
import shapely.geometry as shGeom

# 按ID分组,直接聚合为Numpy数组(比Python列表更高效)
sf = df.groupby("ID").agg({"X": np.array, "Y": np.array})

# 直接拼接X/Y数组为坐标矩阵,生成MultiPoint并计算凸包
sf["hull"] = sf.apply(
    lambda row: shGeom.MultiPoint(np.column_stack((row["X"], row["Y"]))).convex_hull,
    axis=1
)

# 若需保留原始坐标集合,可存储Numpy数组或MultiPoint
sf["coordinates"] = sf.apply(lambda row: np.column_stack((row["X"], row["Y"])), axis=1)
# sf["multi_point"] = sf.apply(lambda row: shGeom.MultiPoint(np.column_stack((row["X"], row["Y"]))), axis=1)

核心优势:Numpy数组操作是底层C实现,比Python级别的zip+列表推导快数倍,大幅减少遍历耗时。


方案2:GeoPandas向量化生成Point,直接分组求凸包

提前用GeoPandas的向量化API生成单个Point几何列,再按ID聚合为MultiPoint计算凸包,全程避免手动打包坐标:

import geopandas as gpd
from shapely.geometry import Point

# 向量化生成Point列(速度远快于循环apply)
df["geometry"] = gpd.points_from_xy(df["X"], df["Y"])

# 按ID分组,直接聚合为MultiPoint并计算凸包
sf = df.groupby("ID").agg(
    hull=("geometry", lambda points: shGeom.MultiPoint(points).convex_hull),
    multi_point=("geometry", lambda points: shGeom.MultiPoint(points))
)

核心优势:gpd.points_from_xy是GeoPandas专门优化的向量化方法,生成几何列的效率极高;后续分组聚合直接基于几何对象操作,完全跳过手动坐标打包步骤。


方案3:并行计算加速(超大规模数据场景)

如果数据量达到千万级,可结合swifter库自动实现并行化apply,进一步利用多核CPU资源:

import swifter

# 基于方案1的代码,用swifter加速apply操作
sf["hull"] = sf.swifter.apply(
    lambda row: shGeom.MultiPoint(np.column_stack((row["X"], row["Y"]))).convex_hull,
    axis=1
)

注意:并行计算会占用更多CPU资源,适合在多核服务器上使用。

内容的提问来源于stack exchange,提问作者Philip Kahn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 02:40:32