如何将多个大型DataFrame按name分组存入字典(禁止拼接)
多大型DataFrame按name分组合并为字典的最优实现
需求概述
有多个无法直接拼接的大型DataFrame,需将所有DataFrame中同一name的行合并,最终生成一个字典:键为唯一name值,值为对应name的所有记录组成的DataFrame(仅保留painting和price列)。
输入示例
DataFrame 1
| name | painting | price |
|---|---|---|
| paul | mona_lisa | 10 |
| chani | avignon | 14 |
| jessica | internationalblue | 9 |
| thufir | lastsupper | 12 |
| jessica | voyager | 11 |
| chani | venus | 7 |
DataFrame 2
| name | painting | price |
|---|---|---|
| paul | canneds_oup | 14 |
| paul | guernica | 19 |
| thufir | bedroom | 5 |
| thufir | starynight | 3 |
目标输出
concatenated_dictionary = { 'paul': pd.DataFrame(columns=['painting','price'], data=[['mona_lisa',10],['cannedsoup',14],['guernica',19]]), 'chani': pd.DataFrame(columns=['painting','price'], data=[['avignon',14],['voyager',11]]), 'jessica': pd.DataFrame(columns=['painting','price'], data=[['internationablue',9],['venus',7]]), 'thufir': pd.DataFrame(columns=['painting','price'], data=[['lastsupper',12],['bedroom',5],['starynight',3]]) }
现有实现(暴力法)
当前先分组再逐个追加,最后拼接,代码如下:
dfs = [v for k, v in temp.groupby('name')] iddic = {} for b in dfs: key = b['name'].iloc[0] try: iddic[key].append(b) except: iddic[key] = [b] # 后续单独循环拼接列表中的DataFrame for key in iddic: iddic[key] = pd.concat(iddic[key], ignore_index=True).drop('name', axis=1)
优化方案
方案1:分DataFrame分组合并(内存友好)
无需提前拼接所有大DataFrame,逐个处理每个输入DataFrame,分组后直接合并到结果字典,减少内存开销:
import pandas as pd input1 = pd.DataFrame(columns=['name','painting','price'], data =[['paul', 'mona_lisa', 10],['chani','avignon',14],['jessica','internationablue',9], ['thufir','lastsupper',12],['chani','voyager',11],['jessica','venus',7]]) input2 = pd.DataFrame(columns=['name','painting','price'], data =[['paul', 'cannedsoup', 14],['paul','guernica',19],['thufir','bedroom',5], ['thufir','starynight',3]]) result_dict = {} # 遍历所有输入DataFrame for df in [input1, input2]: # 按name分组处理每个子组 for name, group in df.groupby('name'): # 裁剪掉name列,重置索引 trimmed_group = group.drop('name', axis=1).reset_index(drop=True) if name in result_dict: # 已存在则追加合并 result_dict[name] = pd.concat([result_dict[name], trimmed_group], ignore_index=True) else: # 不存在则直接存入 result_dict[name] = trimmed_group
方案2:用defaultdict简化逻辑
借助collections.defaultdict自动处理不存在的键,代码更简洁:
from collections import defaultdict import pandas as pd # 初始化默认空DataFrame的字典 result_dict = defaultdict(lambda: pd.DataFrame(columns=['painting', 'price'])) for df in [input1, input2]: for name, group in df.groupby('name'): trimmed_group = group.drop('name', axis=1).reset_index(drop=True) result_dict[name] = pd.concat([result_dict[name], trimmed_group], ignore_index=True) # 可选:转为普通字典 result_dict = dict(result_dict)
方案3:极端大文件的逐块处理
如果DataFrame大到无法一次性加载,可采用逐块读取(如读取CSV时用chunksize)的方式处理:
import pandas as pd from collections import defaultdict result_dict = defaultdict(lambda: pd.DataFrame(columns=['painting', 'price'])) # 逐块读取大型CSV文件 for chunk in pd.read_csv('your_large_file.csv', chunksize=10000): for name, group in chunk.groupby('name'): trimmed_group = group.drop('name', axis=1).reset_index(drop=True) result_dict[name] = pd.concat([result_dict[name], trimmed_group], ignore_index=True) result_dict = dict(result_dict)
优化优势
- 避免拼接所有大DataFrame,大幅降低内存占用
- 分组后直接处理列,减少后续冗余操作
- 逻辑清晰,代码更简洁易维护
内容的提问来源于stack exchange,提问作者gustavjaune
相关产品推荐
相关产品推荐

