Python用pandas清洗Excel表格里的空值怎么做

文章导读
pandas 清洗 Excel 空值,判断顺序比代码本身更重要:先弄清空值在表里以什么形式存在(真空单元格、空字符串、纯空格、还是「无」「NA」「-」这类占位符),再决定哪些列必须删行、哪些列适合填补。如果一上来就 df.dropna(),很可能把含占位符的行全部留下,或者因为某列混入空字符串导致数值列变成 object,后面统计全部失效。
📋 目录
  1. A 先确认当前场景和目标
  2. B 按这个顺序处理
  3. C 改完后怎么验证
  4. D 容易忽略的边界
A A

pandas 清洗 Excel 空值,判断顺序比代码本身更重要:先弄清空值在表里以什么形式存在(真空单元格、空字符串、纯空格、还是「无」「NA」「-」这类占位符),再决定哪些列必须删行、哪些列适合填补。如果一上来就 df.dropna(),很可能把含占位符的行全部留下,或者因为某列混入空字符串导致数值列变成 object,后面统计全部失效。

处理 Excel 空值的稳妥路径是:读入阶段用 read_excel 的 na_values 把占位符归一到 NaN,用 isna().sum() 按列统计缺口;关键列(主键、金额、日期)缺值优先删行,非关键列按业务语义填补;处理前复制一份 DataFrame,输出到新文件而不覆盖原表。验证看行数变化、各列空值计数和 dtype 是否符合预期。合并单元格、公式未重算、多 sheet 是常见盲区,需要单独确认。

先确认当前场景和目标

空值处理没有通用答案,先确认下面几件事,再动手写代码。

  • 空值比例和分布:是零星缺失,还是整列大面积空白。整列缺失通常说明列本身不该保留,而不是逐行填补。
  • 列的角色:主键、金额、日期这类列缺值会破坏后续聚合和关联,一般不做猜测性填补;备注、二级分类这类列可以用固定值或前值填充。
  • 数据的最终形态:结果要给人在 Excel 里看,还是导入数据库或参与计算。给计算用就要保证 dtype 正确;给人看则要避免把空值填成 0 造成误读。
  • 空值的真实形式:Excel 里的空白单元格和含空格的字符串在 pandas 眼里完全不同。可以先抽几行看 repr,确认是 NaN、'' 还是 ' '。
  • 是否存在合并单元格:pandas 读取合并区域时只有左上角保留值,其余读成 NaN,这类「空值」是表格结构造成的,不能靠填补解决。

如果这几个条件还没确认,建议先只做统计、不修改数据,把 df.isna().sum() 和各列 dtype 打印出来,再决定策略。

按这个顺序处理

推荐顺序是「读入归一 → 统计 → 按列决策 → 类型修正 → 写出」。每一步都可以单独跑、单独看结果。

Python用pandas清洗Excel表格里的空值怎么做
import pandas as pd

# 1. 读入时把常见占位符统一识别为 NaN,按实际表里的写法增删
na_tokens = ['', ' ', 'NA', 'N/A', '无', '-', '--', 'null']
df = pd.read_excel('src.xlsx', sheet_name='明细', na_values=na_tokens, keep_default_na=True)

# 2. 按列统计缺口,先看再改
print(df.shape)
print(df.isna().sum())
print(df.dtypes)

统计结果出来后,按列分配策略。关键列缺值直接删行,并指定 subset,避免因无关列空值误删:

key_cols = ['订单号', '金额', '下单日期']
df_clean = df.dropna(subset=key_cols).copy()

非关键列按语义填补,不要统一填 0 或统一填「未知」。分类列填固定值,数值列如果要填,用中位数而不是 0,前提是这一列确实参与计算:

df_clean['备注'] = df_clean['备注'].fillna('未填写')
df_clean['城市'] = df_clean['城市'].fillna(df_clean['城市'].mode().iloc[0])

如果表格是时间序列或按顺序记录的状态列,可以谨慎使用 ffill(),但要加 limit 限制连续填补长度,避免把长时间空白一次性填满:

Python用pandas清洗Excel表格里的空值怎么做
df_clean['状态'] = df_clean['状态'].ffill(limit=2)

最后处理类型问题。数值列里混入过空字符串会导致整列是 object,先用 to_numeric 强制转换,errors='coerce' 会把无法解析的值变成 NaN,转换完要再统计一次空值:

df_clean['金额'] = pd.to_numeric(df_clean['金额'], errors='coerce')
print(df_clean['金额'].isna().sum())

写出时另存新文件,不要覆盖原表,同时关闭索引列:

Python用pandas清洗Excel表格里的空值怎么做
df_clean.to_excel('src_clean.xlsx', index=False)

改完后怎么验证

验证不需要复杂工具,对比几个可观察的信号就够。

  1. 行数对比:记录处理前后的 df.shape,删除行数与 dropna 前后的差值应能对上;如果删掉的行数明显超出关键列空值数量,说明 subset 写错或读入时把正常值误判成了 NaN。
  2. 空值计数:处理后再跑一次 isna().sum(),目标列应为 0,被保留的列允许有非零值,但要在预期范围内。
  3. dtype 检查:金额、日期、ID 列处理完后应为数值或日期类型;如果仍是 object,多半还有残留的空白字符串或占位符。
  4. 抽样对照:用 df_clean.sample(5) 或按主键定位几行,回到原表核对,确认填补值没有覆盖掉原本有效的数据。
  5. 打开输出文件确认:to_excel 写出的 NaN 在 Excel 里显示为空单元格,填成 '' 也同样是空白,肉眼很难区分。需要区分时,可以在输出前把空值临时替换成明确标记再导出。

容易忽略的边界

以下几点在真实表格里经常导致结果和预期不一致,建议先在小样本上确认。

  • 多 sheet 和隐藏行:默认只读一个 sheet,其他 sheet 的空值不会被处理;隐藏行会被正常读入,判断数据量时不要按可见行估算。
  • 公式单元格:pandas 通过 openpyxl 读取时拿到的是缓存值,如果文件保存前未重算,可能读到空值或旧值。建议在 Excel 里另存为只含数值的副本再处理。
  • 合并单元格:合并区域只保留左上角的值,其余为 NaN。这类结构性问题应在原表拆分填充,而不是在 pandas 里 ffill 猜测。
  • 填补的副作用:用 0 填补金额会把缺失计入合计,用均值填补会改变分布。涉及统计口径的列,建议保留一列原始数据或记录填补标记,方便回退。
  • 大面积整列缺失:如果一列空值比例很高,直接填补等于编造数据,更稳妥的做法是整列删除或单独输出缺失清单,人工确认。
  • 回退准备:处理前保留原始 Excel 文件,代码里对 df 使用 .copy() 后再修改,输出写新文件名。这样一旦发现填补策略不合适,重跑即可,不必回溯。

如果表格规模较大或需要反复清洗,建议把读入参数、关键列名、填补规则抽成配置,而不是散落在脚本各处;这样换一张表时只需要改配置,判断逻辑本身不变。