很多搞数据处理的人都遇到过一个头疼的问题。用Python操作Excel,一不小心就卡成PPT,等半天进度条都不动。你盯着屏幕,空气突然安静下来,同事路过都要问一句“你电脑是不是该换了”。
其实不怪电脑。问题出在读写方式上。大家习惯用openpyxl或者xlrd这些库去处理Excel,它们底层是从零开始解析整个文件的。数据少的时候还行,一旦到了10万行,内存先炸,接着CPU飙高,最后程序直接无响应。这种体验干过的人都懂。
换个思路就行。Excel本质上是个压缩包,里面是一堆XML文件。直接解压,用流式处理读取内容,速度能快几十倍。同样写文件也不用全部加载到内存里,一行一行写进去,不卡不死。
具体怎么实现。推荐用openpyxl的只读模式。普通模式会把整个表格塞进内存,只读模式像流水线一样逐行解析。代码非常简单:
from openpyxl import load_workbook wb = load_workbook(filename='bigfile.xlsx', read_only=True)
ws = wb.active
for row in ws.iter_rows():
for cell in row:
print(cell.value)
10万行数据,原来要加载十几秒,现在一秒内就开始输出了。内存占用从几百兆降到几十兆。这个改动成本几乎为零,只是加了一个参数。写数据时也别用append模式,那个会在内存里建一个巨大的列表。改用openpyxl的优化写入模式:
from openpyxl import Workbook wb = Workbook(write_only=True)
ws = wb.create_sheet()
for i in range(100000):
ws.append([i, f'data_{i}'])
wb.save('output.xlsx')
逐行写,不攒堆。100万行也就几秒的事情。你根本感觉不到卡顿。
如果你连openpyxl都不爱用,还有更狠的。直接用pandas配合xlsxwriter引擎:
import pandas as pd df = pd.read_excel('large.xlsx', engine='openpyxl')
df.to_excel('result.xlsx', engine='xlsxwriter', index=False)
pandas把数据读进来时默认压缩,xlsxwriter写出去也是流式写入。配合使用,再大的Excel也不怕。
还有一种场景你肯定遇到过。处理完数据要写回Excel,结果文件太大,保存时程序直接崩了。这时候试试用xlsxwriter直接写,不要经过openpyxl中转:
import xlsxwriter workbook = xlsxwriter.Workbook('huge.xlsx')
worksheet = workbook.add_worksheet()
for row_num in range(100000):
worksheet.write(row_num, 0, row_num)
worksheet.write(row_num, 1, 'value')
workbook.close()
这个库本来就是为大数据量设计的。写100万行,三秒出头。而且你可以在写的过程中随时添加图表或者公式,不会影响写入速度。
如果你手里的Excel是xlsb格式,那个更快。二进制格式天生就比普通xlsx快。用pyxlsb库来读,读取速度能再翻一倍。不过大多数项目还是用xlsx多,上面这些方法足够日常用了。
还有个小技巧。不要等到把全部数据加工完再写Excel。加工一部分写一部分,边处理边写。这样内存一直保持在低水位,程序永远不会卡死。代码里适当加个计数器,每处理一万行吐个日志出来,看着心里也踏实。
最后提醒一句。如果你用pandas的read_excel还卡,检查一下是不是没指定dtype参数。默认情况pandas会把所有列当字符串读,数据量一大就慢。手动指定列类型能省下不少时间。改成这样:
df = pd.read_excel('big.xlsx', dtype={'id': int, 'name': str, 'amount': float})
这些改动加起来不到十行代码。下次打开那个几十M的Excel,你就能喝着茶等同事说“你这个怎么这么快”。他们来问你就说改了个参数,别的别多说。让他们自己去折腾,你专心搞数据就行。