复刻pandas groupby实现字典分组,寻求性能优化并对比pandas效率
字典分组优化与效率对比建议
问题背景
给定字典d(各键对应列表长度一致,且d['A']已按升序排列),需按指定键'A'执行分组操作,生成双层字典。输入示例:
d = { 'A' : [0, 0, 1, 1], 'B' : [1, 2, 4, 3], 'C' : [None, 0, None, 1] }
期望输出:
dd[0] = {'B' : [1, 2], 'C' : [None, 0]} dd[1] = {'B' : [4, 3], 'C' : [None, 1]}
实际场景中字典包含36个键,每个键对应约10^6个元素,需优化分组方法(如多进程),同时对比现有自定义方法与pandas等价实现的执行效率。
现有实现的问题与修正
1. 自定义实现的逻辑缺陷
原自定义代码使用集合推导生成结果,会导致输出结构不符合预期,且存在不必要的集合转换开销,修正后的代码如下:
from collections import defaultdict def dict_groupby(d, key): grouped = defaultdict(list) # 预计算非分组键,避免循环内重复计算 other_keys = [k for k in d if k != key] for i, v in enumerate(d[key]): # 改用字典推导生成对应键值对 grouped[v].append({k: d[k][i] for k in other_keys}) return dict(grouped) dd = dict_groupby(d, 'A') print(dd)
2. pandas实现的补充说明
原pandas代码生成的是{分组键: 子DataFrame}的结构,若要转换为目标双层字典,需额外处理:
import pandas as pd from itertools import chain # 将字典转为DataFrame df = pd.DataFrame(d) grouped = df.groupby('A') # 转换为嵌套列表的字典结构 dd = {k: v.to_dict('list') for k, v in grouped} print(dd)
优化方案与效率分析
1. 利用有序分组的批量切片优化(推荐)
由于d['A']已升序排列,无需逐个元素遍历分组,可直接定位每个分组的起止索引,批量切片生成子列表,大幅降低循环次数:
def optimized_dict_groupby(d, key): # 定位所有分组的起止索引 groups = [] a_vals = d[key] current_val = a_vals[0] start_idx = 0 for idx in range(1, len(a_vals)): if a_vals[idx] != current_val: groups.append((current_val, start_idx, idx)) current_val = a_vals[idx] start_idx = idx groups.append((current_val, start_idx, len(a_vals))) # 批量切片生成结果 other_keys = [k for k in d if k != key] result = {} for val, start, end in groups: result[val] = {k: d[k][start:end] for k in other_keys} return result
优势:遍历次数从106次降至分组数(远小于106),内存开销低(Python切片为浅拷贝,无需复制大量元素),性能比原自定义实现提升数倍。
2. 多进程优化的适用性分析
本场景属于内存/IO密集型任务,多进程会带来进程间数据传输的额外开销(如大列表的跨进程复制),反而可能降低效率。仅当分组数极多且单个分组数据量极大时,可尝试按分组拆分任务,使用multiprocessing.Pool处理,但收益有限,不推荐作为首选方案。
3. 与pandas实现的效率对比
- 性能:pandas的
groupby基于C扩展实现,10^6行数据下,纯计算速度略优于优化后的自定义实现,但字典转DataFrame、DataFrame转字典的步骤会产生额外开销。 - 内存:pandas会将数据转为二维数组存储,36列×10^6行的场景下,内存占用远高于纯字典实现。
- 结论:内存充足时选pandas追求极致性能;内存紧张时,优化后的自定义实现是更优选择。
4. 其他细节优化
- 提前预计算
other_keys,避免循环内重复遍历字典键 - 对于超大规模数据,可改用
numpy数组存储,切片和分组操作的效率会进一步提升
内容的提问来源于stack exchange,提问作者trmgn094
相关产品推荐
相关产品推荐

