如何低内存占用将大型Polars DataFrame转换为字典?
问题解决思路与优化方案
先解决「迭代期间字典大小已更改」错误
你遇到的错误本质是在迭代字典对象的同时修改了它的结构。内层用partition_by(..., as_dict=True)生成的字典,在推导式迭代过程中可能因隐式操作触发结构变化,换用直接提取键值对的方式就能避免。
核心内存优化方案:流式分块处理(无需加载全量数据)
不要先把整个5.5GB Parquet加载到内存,用Polars的流式读取能力边读边处理,从根源减少内存占用:
import polars as pl import gc # 替换为你的唯一列名称 unique_col = "unique_col" my_dict = {} # 流式读取Parquet,按100万行分块处理 for chunk in pl.scan_parquet("你的文件路径.parquet").streaming().iter_batches(batch_size=1_000_000): # 对当前chunk按唯一列去重,保留最后一条记录 chunk_unique = chunk.unique(subset=[unique_col], keep="last") # 将其他列打包为struct,直接生成键值对字典 chunk_data = chunk_unique.select( unique_col, pl.struct(pl.exclude(unique_col)).alias("row_data") ).to_dict(as_series=False) # 合并到最终字典(后续chunk的重复值会覆盖前面的,符合keep='last'逻辑) my_dict.update(dict(zip(chunk_data[unique_col], chunk_data["row_data"]))) # 手动释放当前chunk的内存 del chunk, chunk_unique, chunk_data gc.collect()
方案优势:
- 无需加载全量数据到内存,每个chunk仅占用单批次数据的内存,远低于5.5GB
- 避免了多层
partition_by生成中间字典的内存开销 - 彻底规避字典迭代时的修改错误
备选优化:利用排序列加速查找(无需构建字典)
如果你的唯一列是已排序的,可以不用构建字典,直接利用Polars的排序索引做快速查找,进一步节省内存:
# 加载数据并标记唯一列为排序状态 df = pl.read_parquet("你的文件路径.parquet").set_sorted(unique_col) # 基于排序索引的快速查找 def get_row(unique_val): return df.filter(pl.col(unique_col) == unique_val).select(pl.exclude(unique_col)).to_dicts()[0]
Polars会对排序后的列自动启用二分查找,比普通过滤快一个数量级,且无需额外占用字典的内存。
对你原有代码的问题分析
- 先加载全量DataFrame到内存,再分块处理,本质还是占用了5.5GB内存,内存优化效果有限
- 多层
partition_by生成的中间字典(m和内层的分区字典)会额外占用大量内存 - 内层字典推导式可能因隐式操作触发字典结构修改,导致迭代错误
内容的提问来源于stack exchange,提问作者BovineScatologist
相关产品推荐
相关产品推荐

