上周帮朋友处理一份销售报表,他从财务那边拿到 Excel,想用 pandas 读进来做个分析。一跑 pd.read_excel(),好家伙,右边多了一排 Unnamed: 0、Unnamed: 1、Unnamed: 2……
到底发生了什么?
先还原一下他的操作,他拿到的 Excel 长这样:
A B C D1 (空行)2 (空行)3 日期 产品 数量 金额4 2026-01-01 A产品 10 5005 2026-01-02 B产品 20 800
前 2 行有空行,表头在第 3 行。
他直接跑了下面的代码:
import pandas as pddf = pd.read_excel("销售报表.xlsx")print(df.head())
结果输出:
Unnamed: 0 Unnamed: 1 Unnamed: 2 Unnamed: 30 NaN NaN NaN NaN1 NaN NaN NaN NaN2 日期 产品 数量 金额3 2026-01-01 A产品 10 5004 2026-01-02 B产品 20 800
一排 Unnamed,数据还往下错位了两行。
为什么炸了?
问题出在 pd.read_excel() 的默认行为:它默认从第 0 行(第一行)开始读,把第一行当作表头。
但你的 Excel 文件,表头可能不在第一行。
常见原因有三种:
① 表头前面有空行
财务/HR 导出的 Excel 经常在顶部留一两行空行,甚至写个标题"XX报表"在第一行,表头在第二行或第三行。
② 有合并单元格
表头区域合并了单元格,pandas 只认第一个单元格的位置,其余列就变成了 Unnamed。
③ 有隐藏的空列
Excel 右边有几列看起来是空的,但 pandas 也会给它们编号:Unnamed: 4、Unnamed: 5……
核心原因就一句话:pandas 默认把第一行当表头,表头前面多出来的行它不认识,就全标成 Unnamed。
怎么修?
方法一:指定 header 行号(最常用)
告诉 pandas 表头在第几行(从 0 开始计数):
# 表头在第 3 行(Excel 里的第 3 行,pandas 索引为 2)df = pd.read_excel("销售报表.xlsx", header=2)
如果表头在第 2 行,就写 header=1,以此类推。
方法二:跳过前面的空行
用 skiprows 跳过前面不需要的行:
# 跳过前 2 行(第 0、1 行),从第 2 行开始读df = pd.read_excel("销售报表.xlsx", skiprows=2)
skiprows 还支持更灵活的写法:
# 跳过前 3 行 + 第 5 行(索引 4)df = pd.read_excel("销售报表.xlsx", skiprows=[0, 1, 2, 4])
方法三:读完再清理(兜底方案)
如果你不确定表头在哪,先读进来看看:
df = pd.read_excel("销售报表.xlsx", header=None)print(df.head(10)) # 先看看前 10 行长什么样
header=None 不设表头,所有行都是数据。看完结构后,再用 header=N 正确读取。
方法四:处理合并单元格
合并单元格是 Unnamed 的重灾区,读完后可以这样清理:
df = pd.read_excel("销售报表.xlsx", header=1)# 方法 A:直接删掉 Unnamed 列df = df.loc[:, ~df.columns.str.contains("^Unnamed")]# 方法 B:用第一行数据替换表头(如果表头在数据里)df.columns = df.iloc[0]df = df[1:]
防坑清单
以后读 Excel 之前,先过一遍:
| 检查项 | 怎么查 |
|---|
| 表头在第几行? | 用 Excel 打开,数一下 |
| 有没有合并单元格? | 选中表头区域,看有没有"合并后居中" |
| 前面有没有空行/标题行? | 直接看 |
| 右边有没有空列? | 滚到最右边看看 |
一句话总结:读 Excel 之前,先用 header=None 看一眼结构,再决定参数,别上来就 pd.read_excel() 。
说到底还是一句话,pandas 不是读不了你的 Excel,是它不知道你的表头在哪。
评论区聊聊:你被 Unnamed 坑过几次?最离谱的是哪种情况?
Python/ML/DL/大模型都折腾过,坑也踩了不少。