按城市过滤DataFrame数据并导入带格式Excel模板时,仅首个城市生效的问题排查
按城市过滤DataFrame数据并导入带格式Excel模板时,仅首个城市生效的问题排查
看起来你已经搭好了核心的数据过滤逻辑,但遇到了后续城市无法正确写入Excel模板的问题,我帮你梳理下代码里的几个关键问题,以及对应的修复方案:
一、核心问题分析
你的代码里有几个细节错误,导致只有第一个城市能正常生成文件,后续城市复用了错误的状态或者计算逻辑:
last_row变量未正确初始化与重置
每次处理新城市时,你需要重新从模板的Ind工作表中计算最后一行的位置,而不是沿用之前循环的last_row值。当前代码里last_row在第一次循环后会保留上一次的结果,导致后续写入位置错误,甚至可能跳过写入。拼写错误导致的逻辑异常
- 原DataFrame里的列是
County,但代码里写的是df_city['Country'].unique(),这会导致KeyError(除非你实际数据里有Country列),如果是笔误的话需要修正。 - 写入单元格时的参数错误:
sheet.cell(rows=last_row+index,column=col,value=value)里的rows应该是row,这个拼写错误会导致写入失败。
- 原DataFrame里的列是
模板数据写入逻辑顺序错误
你在循环写入模板数据的同时,反复设置sheet.cell(row=2,column=2,value=accountname),这会覆盖之前的设置,而且应该在写入数据前先处理这类固定值。vote_startdate变量未定义
代码里使用了vote_startdate但没有看到定义,这会导致运行报错,需要补充这个变量的定义。
二、修复后的完整代码
我把这些问题都修正了,你可以参考下面的代码:
import pandas as pd from openpyxl import load_workbook # 补充定义vote_startdate,这里假设你有一个datetime对象,可根据实际情况修改 from datetime import datetime vote_startdate = datetime.now() df = pd.DataFrame({ 'State': ['Colorado', 'Colorado', 'Colorado', 'Colorado'], 'County': ['Denver', 'El Paso', 'Larimar', 'Larimar'], 'City': ['Denver', 'Colorado Springs', 'Fort Collins', 'Loveland'] }) for city_name in df['City'].unique(): df_city = df[df['City'] == city_name] # 修正County的拼写错误 for val in df_city['County'].unique(): accountname = val # 创建模板DataFrame,修正Country为County template = pd.DataFrame(columns=['State','County','City','Pincode','Corporater','Population']) template['State'] = df_city['State'] template['County'] = df_city['County'] template['City'] = df_city['City'] template['Pincode'] = '' template['Corporater'] = 'Mr.' template['Population'] = '' template = template.reset_index(drop=True) # 加上drop=True避免保留原索引列 # 每次处理新城市时,重新加载干净的模板文件 workbook = load_workbook('Master.xlsm', keep_vba=True) sheet = workbook['Ind'] # 计算Ind工作表中第6列(Population)最后一个非空行的位置 last_row = 0 for row in range(sheet.max_row, 0, -1): if sheet.cell(row=row, column=6).value is not None: last_row = row break # 从下一行开始写入数据 start_row = last_row + 1 # 先设置固定值 sheet.cell(row=2, column=2, value=accountname) title1 = f"{vote_startdate.strftime('%d%d%y')}" # 这里可以根据需要设置title1的位置,比如sheet.cell(row=?, column=?, value=title1) # 写入模板数据 for index, row in template.iterrows(): # 从第2列开始写入(对应State列) for col_idx, value in enumerate(row, start=2): # 修正rows为row,计算当前写入的行号:start_row + index sheet.cell(row=start_row + index, column=col_idx, value=value) # 删除多余行(如果需要保留113行的话) if start_row + len(template) < 113: num_rows_to_delete = 113 - (start_row + len(template)) sheet.delete_rows(start_row + len(template), num_rows_to_delete) # 处理Rule工作表 sheet_rule = workbook['Rule'] sheet_rule.cell(row=3, column=2, value=vote_startdate.strftime("%b%y")) # 处理Front Page工作表 sheet_front = workbook['Front Page'] sheet_front.cell(row=5, column=2, value=accountname) # 修正输出文件名的语法错误(多了一个}) output_filename = f'{city_name[0]}_{accountname}.xlsm' workbook.save(output_filename)
三、关键修改点说明
- 重置
last_row计算:每次加载模板后,重新计算Ind工作表的最后非空行,确保从正确的位置开始写入数据。 - 修正拼写错误:把
Country改为County,rows改为row,修复文件名的语法错误。 - 调整写入顺序:先设置固定值(比如
accountname),再写入数据,避免重复覆盖。 - 明确索引处理:
reset_index(drop=True)避免把原索引列写入Excel。 - 每次重新加载模板:确保每个城市处理的都是干净的原始模板,不会被之前的修改影响。
备注:内容来源于stack exchange,提问作者Sandeep Moholkar
相关产品推荐
相关产品推荐

