关于python pandas追加写入excel崩溃的问题
前几天在抓数据时,为了防止中途中断造成数据丢失将数据一次性写入excel改为了每一页写入一次。本来以为改动不大,结果发现每次到4000条时就会无法读写。于是就做了几个测试:
# -*- coding: utf-8 -*-
import pandas as pd
import os
import time
file = "append_test.xlsx"
# 初始化文件
if not os.path.exists(file):
pd.DataFrame(columns=[
"caseCode", "custNo", "custName",
"overDuePay", "overDuePayPrin",
"channelCustNo", "overDueDays", "contacts"
]).to_excel(file, index=False)
total_start = time.time()
for i in range(6000):
# 每次生成1000行
df = pd.DataFrame({
"caseCode": range(i * 10, (i + 1) * 10),
"custNo": "1234567890",
"custName": "哈哈哈",
"overDuePay": 35,
"overDuePayPrin": 3456.78,
"channelCustNo": "HZD0003",
"overDueDays": 55,
"contacts": "张三 13111223344 XX,李四 13111223344 XX,王五 13111223344 XX,"
})
write_start = time.time()
# 追加写
with pd.ExcelWriter(
file,
engine="openpyxl",
mode="a",
if_sheet_exists="overlay"
) as writer:
sheet = writer.sheets["Sheet1"]
df.to_excel(
writer,
index=False,
header=False,
startrow=sheet.max_row
)
write_cost = time.time() - write_start
print(
f"第{i + 1}次写入完成 | "
f"写入行数: {len(df)} | "
f"耗时: {write_cost:.4f}s"
)
total_cost = time.time() - total_start
print(f"\n全部完成,总耗时: {total_cost:.2f}s")
程序在本机运行起来后,到400行左右并没崩溃,但是发现了一个现象,就是用的时间越来越长。从开始的很短,到2秒左右:第1次写入完成 | 写入行数: 10 | 耗时: 0.0490s
第2次写入完成 | 写入行数: 10 | 耗时: 0.0453s
第3次写入完成 | 写入行数: 10 | 耗时: 0.0484s
第4次写入完成 | 写入行数: 10 | 耗时: 0.0453s
第5次写入完成 | 写入行数: 10 | 耗时: 0.0487s
第6次写入完成 | 写入行数: 10 | 耗时: 0.0430s
第7次写入完成 | 写入行数: 10 | 耗时: 0.0336s
第8次写入完成 | 写入行数: 10 | 耗时: 0.0477s
第9次写入完成 | 写入行数: 10 | 耗时: 0.0490s
第10次写入完成 | 写入行数: 10 | 耗时: 0.0580s
…
第866次写入完成 | 写入行数: 10 | 耗时: 2.5864s
第867次写入完成 | 写入行数: 10 | 耗时: 2.5987s
第868次写入完成 | 写入行数: 10 | 耗时: 2.6189s
第869次写入完成 | 写入行数: 10 | 耗时: 2.7824s
第870次写入完成 | 写入行数: 10 | 耗时: 2.6807s
第871次写入完成 | 写入行数: 10 | 耗时: 2.4617s
第872次写入完成 | 写入行数: 10 | 耗时: 1.7832s
看样子还要增长下去。
好奇心驱使就查了一下Pandas + openpyxl 的追加写原理:
- 读取整个工作表到内存(解析XML)
- 在内存中构建新的DataFrame
- 将整个工作表重新写入XML(即使只加1行)
- 替换原有 sheet1.xml
特点:效率低,数据量大时很慢
有没有替代方案呢,查了一番,发现用csv速度和效率更高,而且读写稳定:
# -*- coding: utf-8 -*-
import pandas as pd
import os
import time
file = "append_test.csv"
# 如果存在先删除
if os.path.exists(file):
os.remove(file)
# 模拟 4000 次追加写
for i in range(4000):
df = pd.DataFrame({
"caseCode": range(i * 1000, (i + 1) * 1000),
"custNo": "1234567890",
"custName": "哈哈哈",
"overDuePay": 35,
"overDuePayPrin": 3456.78,
"channelCustNo": "HZD0003",
"overDueDays": 55,
"contacts": "张三 13111223344 XX,李四 13111223344 XX,王五 13111223344 XX,",
})
start = time.time()
# 追加写关键参数
df.to_csv(
file,
mode="a",
header=not os.path.exists(file),
index=False,
encoding="utf-8-sig"
)
print(f"第{i+1}次追加完成,耗时: {time.time() - start:.4f}s")
这个的运行结果:
第1次追加完成,耗时: 0.0371s
第2次追加完成,耗时: 0.0070s
第3次追加完成,耗时: 0.0040s
第4次追加完成,耗时: 0.0045s
第5次追加完成,耗时: 0.0040s
…
第3995次追加完成,耗时: 0.0069s
第3996次追加完成,耗时: 0.0076s
第3997次追加完成,耗时: 0.0072s
第3998次追加完成,耗时: 0.0101s
第3999次追加完成,耗时: 0.0112s
第4000次追加完成,耗时: 0.0099s
结论就是非必要不要使用excel!
更多推荐
所有评论(0)