今天用一个真实案例,带大家用python实战一下不规则的excel数据,怎么一步一步用 Python 把它"驯服"。
例如下表的excel(20260309.xlsx),结构大致如下:

目标输出:每位老师对应教授了哪些不重复科目,格式如下:

这种表格的挑战在于:每个年级的科目数量不同、表头与年级合并在同一行 ,没有统一的固定格式,无法直接用 pd.read_excel 加表头一步读取。
思路分析
拿到这类"不规则"Excel,核心思路是逐行解析:
-
遇到"一年级/二年级/三年级"→ 读取该行第2列起的科目名,存入
current_subjects -
遇到含"班"字或"高三"的行 → 按列位置将教师姓名与
current_subjects对应 -
用
defaultdict(set)存储结果,set自动去重(同一老师教多个班的同一科目只记录一次)
完整代码解析
1. 数据读取
import pandas as pd
from collections import defaultdict
def read_excel_data(file_path):
"""读取Excel文件,返回原始DataFrame"""
df = pd.read_excel(file_path, header=None)
return df
使用 header=None 是关键。因为表格没有统一表头行,直接读取全部原始数据,保留每一行的原始结构。
2. 核心解析逻辑
def parse_teacher_subject_mapping(df):
teacher_subject_map = defaultdict(set)
current_subjects = []
for _, row in df.iterrows():
col0 = str(row[0]).strip() if pd.notna(row[0]) else ""
col1 = str(row[1]).strip() if pd.notna(row[1]) else ""
# 年级行:同时也是科目表头行
if col0 in ["一年级", "二年级", "三年级"]:
current_subjects = []
for i in range(2, len(row)):
subject = str(row[i]).strip() if pd.notna(row[i]) else ""
current_subjects.append(subject)
continue
# 班级数据行:含"班"字或为"高三"
if col1 and ("班" in col1 or col1 == "高三"):
for i, subject in enumerate(current_subjects):
col_index = i + 2
if col_index >= len(row):
break
teacher = str(row[col_index]).strip() if pd.notna(row[col_index]) else ""
if teacher and teacher != "nan" and subject and subject != "nan":
teacher_subject_map[teacher].add(subject)
return teacher_subject_map
几个细节值得关注:
-
pd.notna()判空 :Excel 空白单元格读取后是NaN,必须先判断再str()转换,否则会出现字符串"nan" -
set去重 :同一老师在多个班教同一科目,用set只记录一次 -
列位置对齐 :科目从第2列开始,班级数据也从第2列开始,通过
col_index = i + 2保证对齐
3. 结果格式化与输出
def format_result(teacher_subject_map):
rows = []
for teacher, subjects in sorted(teacher_subject_map.items()):
subject_str = ",".join(sorted(subjects))
rows.append({"老师名字": teacher, "结果": subject_str})
return pd.DataFrame(rows)
def save_result(result_df, output_path):
result_df.to_excel(output_path, index=False)
对教师姓名和科目名称都进行了排序(sorted()),让输出结果稳定可预期,而不是依赖字典遍历的随机顺序。
通过上面的代码,就可以完美解决这种问题!!
运行结果

代码总结
| 技术点 | 用途 |
|---|---|
pd.read_excel(header=None) |
读取无固定表头的 Excel |
pd.notna() |
安全处理空白单元格 |
defaultdict(set) |
自动去重的多值映射 |
iterrows() |
逐行遍历,适合结构不规则的数据 |
sorted() |
让输出结果稳定有序 |
举一反三
这套"逐行解析 + 状态机"的思路,适用于大量现实中的不规则表格场景:
-
多门店销售汇总:每个门店一个小表头,数据分段存放
-
项目周报:每周一个标题行,内容逐行展开
-
混合语言报表:中英文表头混合,列数不固定
核心思路不变:识别"分隔标志行",动态更新当前上下文,逐行提取数据。
代码已整理为完整可运行脚本
analyze_teacher_subjects.py,直接放到 Excel 同级目录执行即可。有问题欢迎留言交流!