9.1 缺失值(NaN/Inf)处理
NumPy缺失值处理教程:检测、填充与删除NaN/Inf详解
本教程详细讲解NumPy中缺失值(NaN/Inf)的处理方法,包括生成与检测、多种填充策略(如均值、中位数、固定值)、删除技术(按行或按列)以及传播规则。适合初学者和高级用户学习,提升数据预处理能力。
NumPy缺失值处理全面指南
在数据科学和机器学习中,缺失值是常见的问题。NumPy作为Python中强大的数值计算库,提供了多种工具来处理缺失值,特别是NaN(Not a Number)和Inf(Infinity)。本教程将详细介绍如何生成、检测、填充、删除缺失值,并解释其传播规则,帮助新人轻松上手。
1. 缺失值的生成
1.1 NaN的生成
NaN表示无效或未定义的数字,通常在运算中意外产生或人为设置。在NumPy中,生成NaN的方法包括:
- 使用
np.nan常量直接创建,例如:arr = np.array([1, 2, np.nan, 4])。 - 通过某些数学运算,如除以零(在浮点数中会产生NaN),例如:
result = 0.0 / 0.0会得到NaN。 - 使用函数如
np.sqrt(-1)在实数域中产生NaN。
示例代码:
import numpy as np
# 生成包含NaN的数组
nan_arr = np.array([1.0, np.nan, 3.0, 4.0])
print("NaN数组:", nan_arr)
# 通过运算生成NaN
temp = np.array([1.0, 0.0])
print("除以零结果:", temp[1] / 0.0) # 输出inf,但0/0会生成NaN
1.2 Inf的生成
Inf表示无穷大,通常由除以零或溢出运算产生。例如:
arr = np.array([1.0, 0.0]),然后arr[1] / 0.0会得到inf(正无穷)或-inf(负无穷)。- 使用
np.inf常量,例如:inf_arr = np.array([1, np.inf, 3])。
示例:
# 生成包含Inf的数组
inf_arr = np.array([1.0, np.inf, -np.inf, 4.0])
print("Inf数组:", inf_arr)
2. 缺失值的检测
NumPy提供了专门函数来检测NaN和Inf值,这对于数据清洗至关重要。
2.1 np.isnan()函数
检测数组中的NaN值,返回一个布尔数组,其中True表示对应位置是NaN。
arr = np.array([1.0, np.nan, 3.0, np.inf])
print("检测NaN:", np.isnan(arr)) # 输出:[False, True, False, False]
2.2 np.isinf()函数
检测数组中的Inf值(包括正无穷和负无穷)。
print("检测Inf:", np.isinf(arr)) # 输出:[False, False, False, True]
2.3 np.isfinite()函数
检测数组中的有限值(即非NaN和非Inf),返回布尔数组。
print("检测有限值:", np.isfinite(arr)) # 输出:[True, False, True, False]
这些函数支持数组操作,可以高效处理大规模数据。
3. 缺失值填充
处理缺失值时,填充是常见策略,NumPy提供了多种方法,但需注意使用忽略NaN的统计函数。
3.1 均值填充
使用np.nanmean()计算忽略NaN的均值,然后用该值填充NaN。np.nanmean()会自动跳过NaN进行计算。
arr = np.array([1.0, np.nan, 3.0, 4.0, np.nan])
mean_val = np.nanmean(arr) # 计算均值,忽略NaN
print("忽略NaN的均值:", mean_val)
# 使用np.where填充
filled_arr = np.where(np.isnan(arr), mean_val, arr)
print("均值填充后数组:", filled_arr)
3.2 中位数填充
类似地,使用np.nanmedian()计算中位数并填充。
median_val = np.nanmedian(arr)
print("忽略NaN的中位数:", median_val)
filled_arr_median = np.where(np.isnan(arr), median_val, arr)
print("中位数填充后数组:", filled_arr_median)
3.3 固定值填充
用特定值(如0、-1或自定义值)替换所有NaN。这种方法简单直接,但可能引入偏差。
arr[np.isnan(arr)] = 0 # 将NaN替换为0
print("固定值填充后数组:", arr)
3.4 插值填充
对于序列数据,可以使用插值方法,如线性插值。NumPy没有内置的NaN插值函数,但可以结合其他库或手动实现。以下是一个简单示例,使用前后值的平均值填充NaN(假设数据有序)。
arr = np.array([1.0, np.nan, 3.0, np.nan, 5.0])
# 手动插值:用前一个非NaN值填充(简单方法)
for i in range(len(arr)):
if np.isnan(arr[i]):
# 查找前一个和后一个非NaN值,这里简化处理
prev_val = arr[i-1] if i>0 and not np.isnan(arr[i-1]) else None
next_val = arr[i+1] if i<len(arr)-1 and not np.isnan(arr[i+1]) else None
if prev_val is not None and next_val is not None:
arr[i] = (prev_val + next_val) / 2 # 线性插值
elif prev_val is not None:
arr[i] = prev_val # 用前值填充
elif next_val is not None:
arr[i] = next_val # 用后值填充
print("插值填充后数组:", arr)
在实际应用中,建议使用pandas库的fillna()方法进行更复杂的插值。
4. 缺失值删除
如果缺失值比例较高或影响分析,删除可能是更好的选择。NumPy允许按行或按列删除包含NaN的数据。
4.1 按行删除
删除任何包含NaN的行。使用np.any()结合np.isnan()和轴参数实现。
arr = np.array([[1.0, 2.0, np.nan],
[4.0, 5.0, 6.0],
[np.nan, 8.0, 9.0]])
# 检测每行是否有NaN
rows_with_nan = np.any(np.isnan(arr), axis=1)
print("行包含NaN:", rows_with_nan) # 输出:[True, False, True]
# 删除包含NaN的行
cleaned_rows = arr[~rows_with_nan]
print("按行删除后数组:", cleaned_rows)
4.2 按列删除
删除任何包含NaN的列。类似地,使用轴参数调整。
cols_with_nan = np.any(np.isnan(arr), axis=0)
print("列包含NaN:", cols_with_nan) # 输出:[True, False, True]
cleaned_cols = arr[:, ~cols_with_nan]
print("按列删除后数组:", cleaned_cols)
删除操作会减少数据量,需谨慎使用,避免丢失重要信息。
5. 缺失值传播规则
在NumPy运算中,NaN和Inf有特定的传播行为,了解这些规则有助于避免意外错误。
5.1 NaN传播规则
- 算术运算:任何涉及NaN的运算结果通常为NaN。例如:
np.nan + 1返回NaN,np.nan * 2返回NaN。 - 比较运算:NaN不等于任何值,包括它自己。因此,
np.nan == np.nan返回False,np.nan != np.nan返回True。使用np.isnan()进行检测。 - 统计函数:标准统计函数如
np.sum()、np.mean()在遇到NaN时会返回NaN或错误。因此,应使用nan版本,如np.nansum()、np.nanmean(),这些函数忽略NaN进行计算。
示例:
a = np.array([1.0, np.nan, 3.0])
print("总和(忽略NaN):", np.nansum(a)) # 输出4.0
print("总和(包含NaN):", np.sum(a)) # 输出nan
5.2 Inf传播规则
- Inf在运算中通常按数学规则传播,例如
np.inf + 1返回inf,1 / np.inf返回0。 - 与NaN类似,Inf在某些统计函数中可能被忽略或导致错误,需注意处理。
示例:
b = np.array([np.inf, 2.0, 3.0])
print("Inf数组总和:", np.sum(b)) # 输出inf
总结
NumPy提供了强大的工具来处理缺失值(NaN/Inf),从生成和检测到填充、删除和传播规则。关键点包括:
- 使用
np.nan和np.inf生成缺失值,通过运算如除以零引入。 - 检测函数:
np.isnan()、np.isinf()、np.isfinite()高效识别缺失值。 - 填充策略:均值、中位数、固定值或插值填充,使用
nan版本统计函数避免错误。 - 删除方法:按行或按列删除包含NaN的数据,使用布尔索引。
- 传播规则:NaN在运算中传播为NaN,Inf按数学规则传播,理解这些有助于数据清洗。
对于更复杂的缺失值处理,可以考虑结合pandas、scikit-learn等库。本教程旨在帮助新人快速掌握NumPy缺失值处理基础,提升数据预处理技能。实践时,多尝试代码示例,加深理解。