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

Pandas GroupBy性能问题求助:大内存工作站处理千万级数据集慢于R

优化Pandas千万级数据集GroupBy性能的实用方案

我太懂这种糟心的感觉了——手里握着190G内存的工作站,处理770万条数据的GroupBy居然慢到离谱,而同逻辑的R代码不到1小时就跑完了,换谁都得挠头。结合你的数据集结构(2个ID列、typeid、日期列+3-5个分类列),给你几个针对性的优化方案,亲测能大幅提升速度:

1. 先给数据“瘦个身”——优化数据类型是基础

Pandas默认的object类型(字符串)和大整数类型会吃掉大量内存,而且GroupBy时的计算效率极低,先把能转的列都转成高效类型:

  • ID列(ID1、ID2):如果是整数类型,用pd.to_numeric(..., downcast='integer')转成最小能容纳的整数类型(比如int32甚至int16,只要数值范围够);如果是字符串但重复率高(毕竟是GroupBy键,肯定有大量重复),直接转成category类型,内存能省一大半。
  • 分类列(typeid、cat1/cat2/cat3):毫不犹豫转成category!Pandas对category类型的GroupBy有专门优化,尤其是基数不高的分类列,不仅内存占用骤降,计算速度能提升好几倍。
  • date_列:务必转成datetime64类型,别留成字符串,日期类型的GroupBy效率比字符串高太多。

举个实操代码片段:

# 批量转换分类列
cat_cols = ['typeid', 'cat1', 'cat2', 'cat3']
df[cat_cols] = df[cat_cols].astype('category')

# 压缩ID列内存
df['ID1'] = pd.to_numeric(df['ID1'], downcast='integer')
df['ID2'] = pd.to_numeric(df['ID2'], downcast='integer')

# 标准化日期列
df['date_'] = pd.to_datetime(df['date_'])

2. 调整GroupBy的参数,避免做无用功

加上observed=True(针对分类列)

如果你的GroupBy键包含category类型列,默认情况下Pandas会计算所有可能的类别组合(哪怕数据里不存在),加上observed=True会只计算实际存在的组合,能大幅减少计算量:

# 替换成你的聚合规则
agg_rules = {
    'agg_col1': ['sum', 'mean'],
    'agg_col2': 'max'
}

result = df.groupby(
    ['ID1', 'ID2', 'typeid', 'date_', 'cat1', 'cat2', 'cat3'],
    observed=True
).agg(agg_rules)

提前排序+关闭GroupBy内排序

如果你的最终结果不需要严格排序,先对GroupBy键排序,然后在GroupBy时加sort=False——Pandas对有序数据的GroupBy有优化,能避免重复排序的开销:

# 先按GroupBy键排序
df = df.sort_values(['ID1', 'ID2', 'typeid', 'date_', 'cat1', 'cat2', 'cat3'])
# 关闭GroupBy内的自动排序
result = df.groupby(..., sort=False, observed=True).agg(agg_rules)

明确指定聚合规则,别让Pandas瞎猜

不要用groupby().sum()这种全列聚合,而是用字典形式明确指定要聚合的列和方式,避免Pandas对所有列做不必要的计算:

# 只聚合你需要的列,减少计算量
agg_rules = {
    'sales': 'sum',
    'user_count': 'mean',
    'order_id': 'nunique'
}
result = df.groupby(..., observed=True).agg(agg_rules)

3. 换用并行计算引擎,榨干工作站性能

单线程的Pandas在千万级数据面前确实乏力,试试这些和Pandas语法兼容的并行引擎:

Dask Pandas——零学习成本的并行工具

Dask会把数据分成小块,利用多CPU核心并行计算,语法和Pandas几乎完全一致,适合你的大内存工作站:

import dask.dataframe as dd

# 读取数据时直接指定高效类型,避免后续转换
ddf = dd.read_csv(
    'your_data.csv',
    dtype={
        'ID1': 'int32',
        'ID2': 'int32',
        'typeid': 'category',
        'cat1': 'category',
        'cat2': 'category',
        'cat3': 'category'
    },
    parse_dates=['date_']
)

# 执行GroupBy(和Pandas语法一样)
result_ddf = ddf.groupby(
    ['ID1', 'ID2', 'typeid', 'date_', 'cat1', 'cat2', 'cat3'],
    observed=True
).agg(agg_rules)

# 触发实际计算,得到Pandas DataFrame
result = result_ddf.compute()

Dask的并行计算能把GroupBy时间压缩到原来的几分之一,尤其是当你的工作站有多核心CPU时,效果更明显。

PySpark——如果数据接近内存极限

如果3000万条数据加上聚合后内存压力大,PySpark可以用磁盘缓存+分布式计算,不过学习成本比Dask高一点,但性能也很强。如果Dask能解决问题,优先选Dask,毕竟和Pandas的语法更贴近。

4. 删掉无关列,减少计算负担

在GroupBy之前,先把不需要的列全部删掉!比如你只需要聚合3-5个数值列,那把其他无关列drop掉,既能减少内存占用,又能降低计算量:

# 只保留GroupBy键和需要聚合的列
keep_cols = ['ID1', 'ID2', 'typeid', 'date_', 'cat1', 'cat2', 'cat3'] + ['agg_col1', 'agg_col2', 'agg_col3']
df = df[keep_cols]

5. 对比R的实现,排查逻辑差异

很多时候R的快是因为用了data.table而不是base R的group_by,data.table的GroupBy是高度优化的。你可以检查下自己的Pandas代码是不是做了额外操作,比如用了groupby().apply()(apply是Pandas里最慢的操作之一,能不用就不用),或者保留了不必要的多级索引,这些都会拖慢速度。

按上面的步骤优化下来,应该能把Pandas的GroupBy速度提升到和R差不多的水平,先从数据类型和GroupBy参数调整入手,这是最容易见效的!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:21:28