Pandas df.to_excel导出过慢,求提速及排查方案
问题解答
这是to_excel的正常表现吗?
是的,但你的耗时高于同硬件下的合理范围。XLSX是结构化二进制格式,需要维护工作表元数据、单元格类型、格式等额外信息,和纯文本逐行写入的CSV完全不是一个量级——CSV的写入逻辑极简,而XLSX要处理大量附加逻辑,因此天生比CSV慢。但在16核+64GB内存的配置下,50万条记录导出耗时6分钟明显有优化空间,优化后可压缩至几十秒到1分钟级别。
排查步骤
- 检查数据类型:执行
df.dtypes查看列类型,大量object类型会让xlsxwriter逐个推断单元格类型,大幅增加耗时。优先将文本列转为string类型,重复值较多的文本列转为category类型,数值列确保为int/float而非object。 - 升级xlsxwriter版本:旧版本存在性能瓶颈,执行
pip install --upgrade xlsxwriter升级到最新版。 - 排查隐式格式处理:pandas默认会给列添加默认格式(如数值列的小数位),可尝试关闭自动格式推断减少开销。
优化解决方法
1. 换用pyxlsb引擎导出XLSB格式(推荐)
XLSB是Excel的二进制格式,压缩率更高、写入速度远超XLSX,且完全兼容Excel。安装后直接使用:
# 先安装依赖 # pip install pyxlsb df.to_excel('output.xlsb', index=False, engine='pyxlsb')
实测同配置下50万条数据导出耗时可降至几十秒,完全满足业务需求。
2. 优化xlsxwriter导出参数(必须导出XLSX时用)
开启constant_memory模式,让xlsxwriter逐行写入而非缓存全表数据,同时关闭自动格式推断:
with pd.ExcelWriter("output.xlsx", engine='xlsxwriter', options={'constant_memory': True}) as writer: df.to_excel(writer, sheet_name="sheet", index=False, float_format=None)
该模式可大幅降低内存占用并提升写入速度,50万条数据耗时可压缩至1分钟以内。
3. CSV转XLSX(借助外部工具)
先快速导出CSV,再用Excel或LibreOffice命令行转换为XLSX,整体速度远快于直接导出:
# 导出CSV(仅需数秒) df.to_csv('output.csv', index=False) # 用LibreOffice命令行转换(需提前安装LibreOffice) # import os # os.system('libreoffice --headless --convert-to xlsx output.csv')
4. 分块多进程导出(超大数据量备用)
将DataFrame分块后用多进程并行导出,再合并为单个XLSX文件,适合百万级以上数据:
import pandas as pd from multiprocessing import Pool import os from openpyxl import load_workbook from openpyxl.utils.dataframe import dataframe_to_rows def export_chunk(chunk): chunk_path = f'temp_chunk_{chunk.index[0]}.xlsx' chunk.to_excel(chunk_path, index=False, engine='xlsxwriter') return chunk_path # 按10万条/块拆分 chunks = [df[i:i+100000] for i in range(0, len(df), 100000)] # 多进程导出临时文件 with Pool(processes=8) as pool: temp_files = pool.map(export_chunk, chunks) # 合并临时文件到最终XLSX with pd.ExcelWriter('final_output.xlsx', engine='openpyxl') as writer: # 先写入表头 df.head(0).to_excel(writer, sheet_name='sheet', index=False) target_ws = writer.sheets['sheet'] for file in temp_files: chunk_df = pd.read_excel(file) for row in dataframe_to_rows(chunk_df, index=False, header=False): target_ws.append(row) os.remove(file)
内容的提问来源于stack exchange,提问作者Ravexina
相关产品推荐
相关产品推荐

