使用 Python(特别是 pandas 的 read_excel() 函数)读取 Excel 文件时,处理各种错误值和空缺值是数据清洗的关键第一步。
1. Excel 中的错误类型和空缺类型
| 类型 | Excel 中的表现 | 示例/原因 |
|---|---|---|
| 空单元格 | 完全没有任何内容 | 未输入数据 |
| 公式错误值 | #DIV/0!, #N/A, #NAME?, #NULL!, #NUM!, #REF!, #VALUE! |
公式计算错误、引用失效等 |
| 表示为空字符串 | 一个单引号 ' 或公式 ="" |
用户手动输入或公式返回以表示"无" |
| 表示为文本的"空" | 字符串如 "null", "NULL", "NA", "N/A", "缺失" |
用户习惯性输入 |
| 数字格式的"空" | 数字如 -999, 0 |
有时被用作占位符或缺失值代码 |
2. pandas 默认读取行为
当使用 pd.read_excel('file.xlsx') 时,pandas 会按照一套默认规则来处理上述情况:
-
真正的空单元格:
- 默认转换为
NaN(Not a Number),这是 pandas 中标记缺失值的标准标量值。在 DataFrame 中显示为NaN。
- 默认转换为
-
Excel 公式错误值(如
#DIV/0!,#N/A):- 行为因 pandas 和引擎版本而异,但通常也会被转换为
NaN。- 现代版本的
openpyxl和xlrd引擎通常能很好地处理,将这些错误直接解析为NaN,这是最理想的情况。 - 在某些旧版本或特定环境下,这些错误值可能导致读取过程抛出异常,而不是安静地转换为
NaN。最佳实践是预先处理或之后检查。
- 现代版本的
- 行为因 pandas 和引擎版本而异,但通常也会被转换为
-
空字符串
"":- 默认被保留为 Python 的空字符串对象
"",不会被转换为NaN。 - 这意味着 DataFrame 可能会混合两种"空":
NaN(来自真正空单元格)和""(来自空字符串)。这在后续处理时需要特别注意,因为df['col'].isna()会过滤掉NaN,但不会过滤掉""。
- 默认被保留为 Python 的空字符串对象
-
文本字符串(如 "NULL", "NA", "N/A"):
- 默认被保留为普通的字符串
"NULL","NA","N/A"。它们不会被自动识别为缺失值。
- 默认被保留为普通的字符串
3. 主动控制和处理:read_excel() 的关键参数
na_values 参数
这是最重要的参数 ,用于指定哪些附加的字符串 应被识别为 NaN/缺失值。
-
作用 :提供一个列表,列表中的每个值在读取时都会被转换为
NaN。 -
示例 :
pythonimport pandas as pd # 将常见的表示"空"的字符串和数字都识别为 NaN df = pd.read_excel( 'data.xlsx', # 文件名使用英文单引号 na_values=['', '#N/A', '#N/A N/A', '#NA', '-1.#IND', '-1.#QNAN', '-NaN', '-nan', '1.#IND', '1.#QNAN', '<NA>', 'N/A', 'NA', 'NULL', 'NaN', 'n/a', 'nan', 'null', '缺失', -999, 0] )- 这样,Excel 中无论是真正的空单元格、还是用户输入的
"NA"、"NULL",甚至是占位数字-999或0,都会被统一转换为 pandas 的NaN,极大简化后续处理。
- 这样,Excel 中无论是真正的空单元格、还是用户输入的
keep_default_na 参数
这个参数与 na_values 配合使用,控制是否保留 pandas 默认的缺失值识别列表。
-
keep_default_na=True(默认值):- pandas 会使用其内置的长列表(包括空字符串
""、"#N/A"、"#N/A N/A"、"#NA"、"-1.#IND"、"-1.#QNAN"、"-NaN"、"-nan"、"1.#IND"、"1.#QNAN"、"<NA>"、"N/A"、"NA"、"NULL"、"NaN"、"n/a"、"nan"、"null")来识别缺失值。 - 再加上
na_values中指定的任何值。
- pandas 会使用其内置的长列表(包括空字符串
-
keep_default_na=False:- 只有
na_values参数中指定的值才会被识别为NaN。 - False: 关闭pandas 所有的默认缺失值识别。
- 真正的空单元格仍然会被转换为
NaN,不受此参数影响。 - 使用场景 :当用户想要完全自定义什么才算是缺失值时。例如,如果数据中合法地包含了
"NA"这个字符串(如国家代码)。
python# 只将我自定义的值视为缺失值,忽略pandas的所有默认设置 df = pd.read_excel( 'data.xlsx', keep_default_na=False, na_values=['自定义空', '无效值', -1] # 只有这三个和真正空单元格会是NaN ) - 只有
4. 读取后的检查和处理
-
检查缺失值:
python# 显示每列的缺失值总数 print(df.isna().sum()) # 显示整个DataFrame的缺失值热力图(用于可视化) import seaborn as sns sns.heatmap(df.isna(), cbar=False) -
处理混合的空字符串和 NaN :
如果读取时没有使用
na_values处理空字符串"",数据中就会混合了NaN和""。python# 方法一:将空字符串替换为 NaN(推荐,便于统一处理) df.replace('', pd.NA, inplace=True) # 对于字符串列,pd.NA 是新的缺失值标志 # 或者更通用的写法 df = df.replace('', np.nan) # 对于混合类型数据,np.nan 更通用 # 方法二:统一过滤(查找所有"空",包括NaN和空字符串) # isnan() 不认识字符串,所以需要组合条件 empty_mask = df['column_name'].isna() | (df['column_name'] == '') -
处理意外残留的错误值 :
极少数情况下,可能有错误值没被正确转换,在 DataFrame 中显示为字符串,如
'#DIV/0!'。python# 手动将它们替换为 NaN error_list = ['#DIV/0!', '#NAME?', '#NUM!', '#VALUE!', '#REF!', '#NULL!'] df = df.replace(error_list, np.nan)
最佳实践总结
- 显式优于隐式 :不要依赖默认行为。在读取 Excel 时,始终使用
na_values参数来明确指定哪些值应被视为缺失值。 - 理解
keep_default_na:判断是 扩充 默认列表(keep_default_na=True)还是 替换 (keep_default_na=False)。 - 读取后立即验证 :使用
df.info()和df.isna().sum()快速检查数据类型和缺失值情况。 - 统一"空"的表示 :确保 DataFrame 中只有一种表示缺失值的方式(通常是
NaN/pd.NA),而不是混合着NaN、""、"NULL"等。这为后续的填充、删除或计算操作扫清障碍。 - 注意数据类型 :强制转换错误值或占位数字(如
-999)为NaN后,相关列的数据类型可能会发生变化(例如从int64变为float64),这是正常现象,因为整数类型无法原生表示NaN。