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

pandas GroupBy.agg是否高效?求大规模数据集分组计算优化方案

问题:Pandas大数据集分组聚合性能优化

我的Pandas数据处理任务如下:

  1. 将DataFrame的V列拆分为数值部分V_u与限定符V_c(仅包含<、>或=);
  2. 按S、M分组后完成以下聚合操作:
    • 计算V_u的均值V_mean、样本量V_N、样本标准差V_sample_sd
    • 生成分组内唯一ID的逗号分隔列表
    • 找出V_c中出现最频繁的限定符V_mean_c
    • 对V_mean应用与M映射的函数得到TV_mean
    • 给V_mean和TV_mean添加对应限定符V_mean_c

目前已实现的方案:

  • 拆分V列时,用map+循环的方式比apply更高效;
  • 分组聚合使用GroupBy.agg,但在45万条记录的数据集上耗时约1分钟,后续要处理更大数据集,急需更高效的优化方案,测试过其他方案但性能更差。

优化方案

一、用内置矢量化聚合替代自定义函数

GroupBy.agg里的自定义函数是性能杀手,尽量用Pandas内置的矢量化方法:

  1. 统计类指标直接调用内置方法,避免重复分组:
    # 先计算基础统计量
    stats_df = df.groupby(['S', 'M']).agg(
        V_mean=('V_u', 'mean'),
        V_N=('V_u', 'count'),
        V_sample_sd=('V_u', 'std', ddof=1)  # ddof=1对应样本标准差
    ).reset_index()
    
  2. 最频繁限定符V_mean_c,利用value_counts默认降序的特性,取第一个结果:
    mode_c = df.groupby(['S', 'M'])['V_c'].apply(lambda x: x.value_counts().index[0]).reset_index(name='V_mean_c')
    stats_df = stats_df.merge(mode_c, on=['S', 'M'], how='left')
    

二、开启PyArrow分组引擎(Pandas 2.0+)

如果你的Pandas版本在2.0及以上,用PyArrow作为分组引擎能显著提速:

# 分组时指定engine参数
df.groupby(['S', 'M'], engine='pyarrow').agg(...)

先确保装了PyArrow:pip install pyarrow

三、优化唯一ID的拼接逻辑

ID拼接是常见性能瓶颈,尽量减少循环操作:

  1. 先对ID去重,再用str.cat矢量化拼接:
    # 先去重避免重复ID,再分组拼接
    unique_ids = df.drop_duplicates(['S', 'M', 'ID']).groupby(['S', 'M'])['ID'].apply(lambda x: ','.join(x.astype(str))).reset_index(name='unique_ids')
    stats_df = stats_df.merge(unique_ids, on=['S', 'M'], how='left')
    
  2. 如果ID是数值型,提前转成字符串,减少分组内的类型转换开销。

四、预映射M对应的函数,减少分组内计算

如果M的取值有限,先把M对应的函数结果预计算好,再做分组聚合,避免在分组内重复调用函数:

# 假设M_to_func是存储M与对应函数的字典
# 提前计算映射后的值,再结合V_mean得到TV_mean
stats_df['TV_mean'] = stats_df['M'].map(M_to_func) * stats_df['V_mean']

把函数调用从分组内转移到全局矢量化操作,能大幅降低计算耗时。

五、用Dask处理超大规模数据

如果数据集大到单机Pandas扛不住,试试Dask DataFrame,它兼容Pandas API,能利用多核心甚至集群资源并行计算:

import dask.dataframe as dd

# 读取大文件为Dask DataFrame
ddf = dd.read_csv('your_large_data.csv')
# 拆分V列(用矢量化的str.extract)
ddf[['V_c', 'V_u']] = ddf['V'].str.extract(r'([<>]?=?)(\d+\.?\d*)', expand=True)
ddf['V_u'] = ddf['V_u'].astype(float)
# 分组聚合,最后用compute()触发计算
result = ddf.groupby(['S', 'M']).agg({
    'V_u': ['mean', 'count', 'std'],
    'ID': lambda x: x.unique().str.cat(sep=','),
    'V_c': lambda x: x.value_counts().index[0]
}).compute()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 12:21:29