统计1.6亿行2列DataFrame价格频次的内存问题解决方案
1.6亿行价格频次统计低内存实现方案
核心思路
全程避免把1.6亿行全量数据一次性加载到内存,从读取、计算两个环节压缩内存占用,最终得到按频次降序排列的统计结果。
方案1:分块流式统计(无额外依赖,纯Python+pandas可实现)
- 读取阶段只加载必要列:统计价格频次完全不需要用到「材料名称」字段,读文件时通过
usecols参数指定仅读取价格列,直接砍掉一半以上的内存占用。 - 提前做类型压缩:价格字段如果是整数美元直接转
int32类型,如果保留两位小数就乘100转成存美分的int32类型,比默认的float64省75%内存;绝对不要把价格存成字符串/object类型,内存占用会翻10倍以上。 - 分块累加计数:把数据源拆成每块100万-500万行(根据本机内存调整块大小)逐块读取,每块单独做频次统计后累加到全局计数器,当前块处理完立刻释放内存,不会出现内存占满崩溃的问题。
参考代码:
import pandas as pd from collections import Counter import gc # 初始化全局计数器 price_counter = Counter() # 分块读取,仅加载价格列,chunksize可根据机器内存调整 chunk_reader = pd.read_csv( "你的数据源路径.csv", usecols=["价格"], chunksize=3_000_000 ) for chunk in chunk_reader: # 压缩字段类型降低内存 chunk["价格"] = pd.to_numeric(chunk["价格"], downcast="integer") # 统计当前块频次并更新全局结果 chunk_count = chunk["价格"].value_counts().to_dict() price_counter.update(chunk_count) # 手动释放当前块内存 del chunk gc.collect() # 转成DataFrame并按频次降序排序 freq_result = pd.DataFrame( price_counter.items(), columns=["价格", "出现频次"] ).sort_values(by="出现频次", ascending=False, ignore_index=True)
方案2:用DuckDB/Polars做列式计算(代码更简单,性能更高)
如果不想自己写分块逻辑,直接用面向分析的列式计算引擎即可,引擎会自动做流式计算和内存优化,不需要手动管理内存,16G内存的普通笔记本就能轻松跑1.6亿行数据的分组统计,代码量更少:
import duckdb # 可以直接对接本地文件,也可以对接已经加载到内存的pandas DataFrame,自动做内存优化 conn = duckdb.connect() freq_result = conn.execute(""" SELECT 价格, COUNT(*) AS 出现频次 FROM 你的内存DataFrame名 -- 也可以直接填文件路径,比如'./price_data.csv' GROUP BY 价格 ORDER BY 出现频次 DESC """).df()
结果实用性优化
针对248万条唯一价格结果实用性差的问题,算完频次后可以直接按需截断:
- 如果只关心高频价格,直接取Top N(比如Top1000)即可,248万条结果里绝大多数是出现次数极低的长尾价格;
- 截断后剩下的长尾价格可以单独汇总成「其他低频价格」项,统计总出现次数即可,不需要逐条展示。
避坑提醒
- 不要直接对1.6亿行的全量DataFrame调用
pandas.value_counts(),这个操作会把全量数据驻留内存做分组,内存峰值会达到原始数据大小的2-3倍,很容易触发内存不足报错; - 不要在统计阶段加载无关列,长文本类的字符串列是内存占用的核心大头。
内容的提问来源于stack exchange,提问作者AJ Jebelli
相关产品推荐
相关产品推荐

