应使用 np.isnan() 和 np.isinf() 检测 NaN/Inf,二者返回同形布尔数组;推荐用 np.where() 组合掩码替换或直接调用 np.nan_to_num() 统一处理,优先新建数组以避免副作用。

用 np.isnan() 和 np.isinf() 定位 NaN/Inf
直接用 == 或 is 判断 NaN 会失败,因为 np.nan != np.nan 是 True;Inf 同样不能靠比较运算符捕获。必须用 NumPy 提供的专用函数:np.isnan() 检测 NaN,np.isinf() 检测 ±Inf(包括 np.inf 和 -np.inf)。这两个函数返回布尔数组,形状与原数组一致,可直接用于索引。
注意:np.isinf() 不区分正负无穷,若需单独处理,可用 x == np.inf 或 x == -np.inf;但前提是已确认 x 是浮点类型(整数数组调用 np.isinf() 恒为 False)。
-
np.isnan()对非浮点类型(如 int、object)数组返回全 False,不报错但结果无意义 - 混合类型数组(如 dtype=object)中含 float NaN 时,
np.isnan()可能抛TypeError,应先转为 float:x.astype(float) - 对 Pandas Series 调用这些函数会触发隐式转换,但效率低,建议先用
.to_numpy()提取底层数组
用 np.where() 一次性替换 NaN 和 Inf
最常用且高效的方式是组合布尔掩码与 np.where()。例如把所有 NaN 和 Inf 替换为 0:
mask = np.isnan(x) | np.isinf(x) x_clean = np.where(mask, 0, x)
这比循环或多次 np.copyto() 快得多,且保持向量化。关键点在于:掩码必须是布尔数组,np.where() 的三个参数必须同形(广播允许)。
立即学习“Python免费学习笔记(深入)”;
- 若原数组是高维,
mask维度必须匹配;不要用np.any(mask)这类降维操作来构造条件 - 替换值可以是标量、同形数组,或支持广播的数组(如列向量替换某列中的 NaN)
- 避免写成
x[mask] = 0后再赋值回去——对视图(view)可能意外修改原数组,且无法链式使用
用 np.nan_to_num() 快速统一处理
如果目标只是把 NaN 替为 0、±Inf 替为极大/极小有限值(默认 np.finfo(float).max 和 .min),np.nan_to_num() 是最简方案:
x_clean = np.nan_to_num(x, nan=0.0, posinf=1e38, neginf=-1e38)
它内部做了类型检查和安全转换,比手写掩码更鲁棒,尤其适合预处理输入数据。但要注意:
- 默认行为对
posinf/neginf的替换值依赖当前浮点精度(np.finfo(x.dtype)),跨平台可能略有差异 - 不支持按条件差异化替换(比如只替 NaN 不动 Inf,或对不同列设不同替换值)
- 对复数数组也有效,但需显式指定
nan/posinf/neginf为复数,否则只处理实部
性能与内存:就地修改 vs 新建数组
多数场景推荐新建数组(如 np.where() 或 np.nan_to_num() 返回新副本),避免副作用。但若确定原数组可改且内存敏感,可用就地赋值:
mask = np.isnan(x) | np.isinf(x) x[mask] = 0 # 修改原数组
这种写法快且省内存,但有风险:
- 若
x是只读数组(x.flags.writeable = False),会抛ValueError: assignment destination is read-only - 若
x是其他数组的视图(如切片、转置),就地修改会影响源头 - 在函数中返回
x前未注明“此操作修改输入”,极易引发下游 bug
真正需要就地处理时,务必加注释并验证 x.flags.writeable;否则默认走安全路径——生成新数组。


















