pandas DataFrame高度碎片化PerformanceWarning原因及解决方案咨询
问题1:
copy()缓解DataFrame碎片化的原理 pandas的DataFrame底层采用列式存储,每一列对应一块独立的Numpy数组内存。当你频繁调用insert、直接赋值新增列(比如df['id'] = xxx)或者逐块追加数据时,会不断申请新的离散内存块存储新增的列数据,这些分散不连续的内存块就会导致DataFrame碎片化,后续计算时需要遍历多个内存块,性能会大幅下降。copy()执行深拷贝时,会预先申请一块连续的完整内存空间,把原DataFrame所有列的数据按顺序拷贝到这块连续内存中,同时释放原来的零散内存块,最终得到的新DataFrame所有列的内存地址是连续的,自然就解决了碎片化问题。
问题2:规避该性能警告的其他方案
- 避免在循环中对单个小DataFrame新增列,统一在合并后操作
你可以先把所有文件读取到列表,合并成大表之后再新增id列,对应file标识提前收集即可,整个流程只执行1次新增列操作,不会频繁触发insert:
dfs = [] id_list = [] for file in files: df = pd.read_pickle(file) dfs.append(df) id_list.extend([file] * len(df)) dfs = pd.concat(dfs, ignore_index=True) dfs['id'] = id_list
- 用
assign方法替代直接赋值新增列assign方法会返回一个全新的DataFrame,不会修改原内存布局,能大幅降低碎片化概率:
df = pd.read_pickle(file).assign(id=file)
- 读取真实数据集的pickle后先执行一次拷贝
你的测试数据集生成时就是连续内存存储的,所以没有告警,而真实数据集的pickle文件在存储时本身就已经是碎片化状态,读取后自然会触发告警,读完单个文件先做一次拷贝即可:
df = pd.read_pickle(file).copy() df['id'] = file
- 升级pandas到2.0及以上版本
pandas 2.0重构了内部内存管理逻辑,对concat的性能和碎片化问题做了大量优化,很多1.x版本会触发的告警在2.0+版本不会出现。 - 大宽表场景下改用PyArrow作为存储后端
如果你的表列数极多,可以在pandas中开启PyArrow后端,其列式存储的内存布局更紧凑,能大幅降低碎片化的出现概率。
内容的提问来源于stack exchange,提问作者Chung-Kan Huang
相关产品推荐
相关产品推荐

