Pandas df.loc方法过慢:十万级数据分组赋值优化求助
嘿,我太懂你遇到的这个性能糟心事了!10万行的DataFrame用循环+df.loc来赋值,完全是把Pandas的核心优势给浪费了——Pandas天生就是为向量化批量操作设计的,逐组逐行的loc访问会触发无数次索引查找和内存操作,速度慢到离谱简直是必然结果。
问题根源
你之前的思路是分组后用循环+df.loc统计次数,这种方式属于逐元素的“标量操作”。Pandas在处理这类操作时,没法利用底层的C语言优化,每一次loc访问都要单独处理,大数据量下直接拉胯。
最优解决方案:用GroupBy内置聚合函数
直接用groupby搭配.size()或者.count()(如果有专门的下载记录列的话),这是Pandas内部高度优化的向量化操作,速度能提升几个数量级。
最小可复现示例
先构造一个模拟10万行的测试数据集:
import pandas as pd import numpy as np # 生成10万行测试数据 np.random.seed(42) users = np.random.randint(1, 1000, size=100000) docs = np.random.randint(1, 500, size=100000) df = pd.DataFrame({'user': users, 'document': docs})
原来的慢方法(不推荐)
假设你之前的代码大概是这样的(注释掉后速度变快,确认是loc的锅):
# 初始化统计列 df['download_count'] = 1 # 慢到离谱的循环+loc赋值 for (user, doc), group in df.groupby(['user', 'document']): df.loc[(df['user'] == user) & (df['document'] == doc), 'download_count'] = len(group)
高效替代方案(推荐)
直接用groupby的.transform('size'),这是最简洁且高效的写法:
# 一行代码搞定分组统计并映射回原DataFrame df['download_count'] = df.groupby(['user', 'document'])['user'].transform('size') # 如果有专门的下载记录列(比如'download_time'),可以用count更精准: # df['download_count'] = df.groupby(['user', 'document'])['download_time'].transform('count')
要是你只需要单独的统计结果(不需要合并回原DataFrame),直接用.size()就能得到分组计数的Series:
counts = df.groupby(['user', 'document']).size()
这两种方法都是完全向量化的,运行时间会从原来的几十秒甚至几分钟,压缩到几百毫秒以内。
其他备选方案
如果需要把统计结果整理成宽表格式,可以用pivot_table:
count_table = df.pivot_table(index='user', columns='document', values='user', aggfunc='size', fill_value=0)
或者用pd.value_counts直接得到所有组合的计数:
count_series = df.value_counts(subset=['user', 'document'])
关键提醒
在Pandas里处理大数据时,永远优先用内置的向量化方法,避免写循环逐行/逐组操作。GroupBy的transform、agg、size这些方法都是底层优化过的,性能碾压手动循环+loc。
内容的提问来源于stack exchange,提问作者LetMeSOThat4U

