使用 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
。 - 示例:
import 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"
这个字符串(如国家代码)。
# 只将我自定义的值视为缺失值,忽略pandas的所有默认设置 df = pd.read_excel( ‘data.xlsx‘, keep_default_na=False, na_values=[‘自定义空‘, ‘无效值‘, -1] # 只有这三个和真正空单元格会是NaN )
- 只有
4. 读取后的检查和处理
检查缺失值:
# 显示每列的缺失值总数 print(df.isna().sum()) # 显示整个DataFrame的缺失值热力图(用于可视化) import seaborn as sns sns.heatmap(df.isna(), cbar=False)
处理混合的空字符串和 NaN:
如果读取时没有使用na_values
处理空字符串""
,数据中就会混合了NaN
和""
。# 方法一:将空字符串替换为 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!‘
。# 手动将它们替换为 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
。