如何优化Python编写的Excel指定行跨表迁移脚本运行效率
问题背景
正在开发Excel自动化处理程序,核心需求为检测Excel文件的指定列,将指定列为空的对应行移动到同一工作簿的Linkedin Only工作表中。目前基于openpyxl编写的初版代码运行效率较低,需要基于pandas或其他工具库实现更高性能的方案。
初版openpyxl实现代码如下:
import time start_time = time.perf_counter () import openpyxl wb = openpyxl.load_workbook("Test.xlsx") ws=wb.active mr,mc=ws.max_row,ws.max_column column_string=input("Enter Column Letter with Email (A or B or C or leave blank to skip editing):").upper() if len(column_string)>0: for cell in ws[column_string][1:]: if cell.value is None: ws_1=wb.create_sheet('Linkedin Only') for i in range (1, mr +1): for j in range (1, mc + 1): c = ws.cell(row = i, column = j) ws_1.cell(row = i, column = j).value = c.value break for cell in ws_1[column_string][1:]: if cell.value is not None: ws_1.delete_rows(cell.row) for cell in ws[column_string][1:]: if cell.value is None: ws.delete_rows(cell.row) wb.save("Test.xlsx") else: wb.save("Test.xlsx") end_time = time.perf_counter () print(end_time - start_time, "seconds")
初版代码性能瓶颈
- 全表数据复制用了逐行逐单元格的双层循环,openpyxl单单元格读写的IO开销极高,数据量过万时耗时会陡增
- 行删除操作逐行触发
delete_rows,每次删除都会重算整个工作表的行索引,不仅速度慢,还容易因为行号偏移出现漏删、错删的问题 - 对同一列做了3次全量遍历,存在大量冗余操作
高性能实现方案
根据是否需要保留原Excel的格式样式,可选择以下两种方案:
方案1:pandas批量处理(性能最优,适合无复杂格式的纯数据表格)
pandas基于数组做批量运算和读写,没有逐单元格操作的开销,万行级数据处理速度比初版openpyxl代码快50~200倍。
实现代码:
import time import pandas as pd from openpyxl import load_workbook start_time = time.perf_counter() file_path = "Test.xlsx" column_string = input("Enter Column Letter with Email (A or B or C or leave blank to skip editing):").upper() if len(column_string) > 0: # 读取活动工作表全量数据 active_ws_name = load_workbook(file_path, read_only=True).active.title df = pd.read_excel(file_path, sheet_name=active_ws_name, engine='openpyxl') # 列字母转pandas列索引(A对应0,B对应1以此类推) col_idx = ord(column_string) - ord('A') target_col = df.columns[col_idx] # 一次性拆分两组数据:原表保留非空行,新表存空值行 df_keep = df[df[target_col].notna()] df_move = df[df[target_col].isna()] # 写回文件,保留原工作簿其他工作表 with pd.ExcelWriter( file_path, engine='openpyxl', mode='a', if_sheet_exists='replace' ) as writer: df_keep.to_excel(writer, sheet_name=active_ws_name, index=False) df_move.to_excel(writer, sheet_name='Linkedin Only', index=False) end_time = time.perf_counter() print(end_time - start_time, "seconds")
注意:如果原工作表有复杂公式、合并单元格、自定义样式,不要用这个方案,pandas写入时会丢失这些格式。
方案2:优化版openpyxl实现(保留原格式,性能比初版高10~30倍)
核心优化点是取消逐单元格复制、逐行删除的逻辑,一次性把所有行读入内存筛选,再批量写回工作表,避免重复IO和行号重算开销。
实现代码:
import time from openpyxl import load_workbook start_time = time.perf_counter() wb = load_workbook("Test.xlsx") ws = wb.active mr, mc = ws.max_row, ws.max_column column_string = input("Enter Column Letter with Email (A or B or C or leave blank to skip editing):").upper() if len(column_string) > 0: # 一次性读入表头和所有行数据 header = [cell.value for cell in ws[1]] all_rows = list(ws.iter_rows(min_row=2, max_row=mr, max_col=mc, values_only=True)) col_idx = ord(column_string) - ord('A') # 一次性拆分数据 keep_rows = [] move_rows = [] for row in all_rows: if row[col_idx] is None: move_rows.append(row) else: keep_rows.append(row) # 删除原表旧数据 if mr > 1: ws.delete_rows(2, mr-1) # 创建/重置目标工作表 if 'Linkedin Only' in wb.sheetnames: del wb['Linkedin Only'] ws_1 = wb.create_sheet('Linkedin Only') # 批量写回两个工作表 ws.append(header) for row in keep_rows: ws.append(row) ws_1.append(header) for row in move_rows: ws_1.append(row) wb.save("Test.xlsx") end_time = time.perf_counter() print(end_time - start_time, "seconds")
方案选择建议
- 处理的是纯数据导出的表格,不需要保留样式、公式,优先选pandas方案,处理速度最快
- 需要保留原表的样式、公式、合并单元格等格式,选优化版openpyxl方案,兼容性更好
内容的提问来源于stack exchange,提问作者Amar Kanakamedala
相关产品推荐
相关产品推荐

