pandas遍历DataFrame按SheetNo写入xlsx多表时旧表被覆盖怎么解决
问题根因
你当前代码无法实现分表存储、出现旧数据被覆盖的核心原因有两点:
- 逻辑位置错误:你把
pd.ExcelWriter初始化、文件保存操作放在了遍历循环内部,每一轮循环都会重新生成一个空白的output.xlsx文件覆盖上一轮的写入结果,最终文件只会保留最后一次循环写入的内容。 - 代码存在多处API/拼写错误:包括库名
opnepyxl拼写错误、遍历方法iterrows漏写括号、ExcelWriter类名大小写错误、文件后缀xlsx拼写错误;且循环中取出的data是单行Series对象,并非按SheetNo聚合的子数据集,逐行写入本身也不符合分表批量存储的需求。
修正方案
推荐实现(性能最优)
不要逐行遍历DataFrame,直接利用pandas内置的分组能力,按SheetNo字段聚合后批量写入对应工作表,代码简洁、运行效率远高于逐行遍历,也不会出现覆盖问题:
import pandas as pd # 初始化写入器,放在循环外,用上下文管理器自动处理保存/关闭逻辑 with pd.ExcelWriter("output.xlsx", engine="openpyxl") as writer: # 按SheetNo分组,遍历每个分组写入对应工作表 for sheet_id, sheet_data in df.groupby("SheetNo"): # 写入时关闭行索引输出,工作表名转成字符串避免类型报错 sheet_data.to_excel(writer, sheet_name=str(sheet_id), index=False)
这个写法不需要额外导入dataframe_to_rows,pandas的to_excel方法已经封装了完整的表格写入逻辑。
特殊场景适配
如果需要往已经存在的Excel文件中追加新工作表,只需要修改ExcelWriter的初始化参数即可:
with pd.ExcelWriter( "output.xlsx", engine="openpyxl", mode="a", # 追加模式,不覆盖原有文件 if_sheet_exists="replace" # 同名工作表处理规则:replace=覆盖/overlay=追加数据/error=抛错 ) as writer: # 后续写入逻辑和上面一致
原遍历写法的修正(不推荐)
如果你一定要保留逐行遍历的逻辑,除了把Writer初始化移到循环外,还需要记录每个工作表的已写入行位置,避免写入同Sheet时覆盖之前的行,参考代码如下:
import pandas as pd from openpyxl.utils.dataframe import dataframe_to_rows writer = pd.ExcelWriter("output.xlsx", engine="openpyxl") # 记录每个sheet已经写入到第几行 sheet_row_cursor = {} for _, row_data in df.iterrows(): target_sheet = str(row_data["SheetNo"]) # 工作表不存在时先创建,写入表头,行初始位置设为1(openpyxl行号从1开始) if target_sheet not in writer.sheets: # 先把列名写入第一行 pd.DataFrame([row_data.to_dict()]).head(0).to_excel(writer, sheet_name=target_sheet, index=False) sheet_row_cursor[target_sheet] = 1 # 从当前行光标的下一行开始写入单行数据,不写表头和索引 row_data.to_frame().T.to_excel( writer, sheet_name=target_sheet, index=False, header=False, startrow=sheet_row_cursor[target_sheet] + 1 ) # 更新行光标 sheet_row_cursor[target_sheet] += 1 writer.close()
这个写法逻辑冗余、性能很差,仅作为原逻辑的修正参考,日常使用优先选分组批量写入的方案。
内容的提问来源于stack exchange,提问作者Rob John
相关产品推荐
相关产品推荐

