如何设计Python数据结构实现50GB级数据集按多字段去重计数
解决方案
针对你的需求,分两种适用场景给出数据结构/存储方案:
场景1:去重后的唯一键数量可完全载入内存
这是性能最高的方案,适合分组后唯一记录数在十万到百万级、可以完全放进内存的情况。
- 核心设计:把
(Group, A1, A2)三个字段组成的元组作为字典的键,键对应的值就是计数Count。Python中元组是不可变可哈希类型,天然适合作为字典的唯一键。
代码示例:
from collections import defaultdict # 初始化统计容器 counter = defaultdict(int) # 新增条目的方法,实际使用时可以逐行读取大文件解析出三个字段后调用该方法 def add_entry(group, a1, a2): key = (group, a1, a2) counter[key] += 1 # 样例数据测试 add_entry(1, 'AAA', 3) add_entry(1, 'AAA', 3) add_entry(1, 'TTTT', 4) add_entry(2, 'GG', 2) add_entry(2, 'GG', 2) # 输出结果 print("Group\tA1\tA2\tCount") for (g, a1, a2), cnt in counter.items(): print(f"{g}\t{a1}\t{a2}\t{cnt}")
场景2:去重后的唯一键数量极多,无法全部载入内存(适配50GB大文件场景)
如果分组后的唯一记录数超过千万级、内存放不下,不要用纯内存结构避免OOM,改用嵌入式数据库SQLite做外存统计:
- 核心设计:创建统计表时给
Group、A1、A2三个字段加联合唯一约束,用SQL的UPSERT能力实现重复条目自动计数+1,无需把全量数据载入内存,逐条处理逐条写入数据库即可,内存占用仅维持在KB级。
代码示例:
import sqlite3 # 初始化数据库,文件不存在会自动创建 conn = sqlite3.connect('data_stats.db') cursor = conn.cursor() # 创建表并设置联合主键作为唯一约束 cursor.execute(''' CREATE TABLE IF NOT EXISTS group_stats ( group_id INTEGER, a1 TEXT, a2 INTEGER, count INTEGER DEFAULT 1, PRIMARY KEY (group_id, a1, a2) ) ''') conn.commit() def add_entry(group, a1, a2): # 冲突时自动累加计数,不新增重复行 cursor.execute(''' INSERT INTO group_stats (group_id, a1, a2) VALUES (?, ?, ?) ON CONFLICT(group_id, a1, a2) DO UPDATE SET count = count + 1 ''', (group, a1, a2)) conn.commit() # 处理完成后可通过以下方法获取全量统计结果 def get_all_stats(): cursor.execute('SELECT group_id, a1, a2, count FROM group_stats') return cursor.fetchall() # 所有数据处理完成后关闭连接 # conn.close()
内容的提问来源于stack exchange,提问作者The Nightman
相关产品推荐
相关产品推荐

