np.nan 是 NumPy 中遵循 IEEE 754 标准的浮点型特殊值,类型为 float,参与运算结果恒为 np.nan,不等于自身,须用 np.isnan() 检测,不可用 == 或 in 判断。

np.nan 是什么?不是 None,也不是字符串
np.nan 是 NumPy 中一个具体的 float 类型值,不是 Python 原生的 None,也不是字符串 "NaN"。它来自 IEEE 754 浮点标准——当浮点数的指数全为 1 且尾数非零时,就被解释为 NaN。这意味着:
• type(np.nan) == float,能参与数值计算(比如加减乘除),但结果恒为 np.nan
• np.nan == np.nan 返回 False,必须用 np.isnan() 判断
• None 和 np.nan 混在同一个数组里会触发类型提升(如转成 object),后续 np.isnan() 会报错
为什么任何运算遇到 np.nan 都变成 np.nan?
这不是 NumPy 的“bug”,而是 IEEE 754 标准强制要求的行为:NaN 表示“未定义的结果”,例如 0/0、inf - inf、sqrt(-1)(在实数域)。一旦引入 NaN,整个计算链就失去确定性语义,所以标准规定:
• np.nan + 1 → np.nan
• np.nan * 0 → np.nan(注意:不是 0!)
• np.nan > 5 → False(比较运算全部返回 False,连 != 都不例外)
• 这个特性让 NaN 具有“传染性”,对调试很友好——只要结果是 np.nan,说明上游某处已经失守
怎么安全地检测和替换 np.nan?别用 == 或 in
常见错误是写 a == np.nan 或 np.nan in a,这两者永远得不到正确结果。
• 必须用 np.isnan(a) 检测,它返回布尔数组,支持标量、一维/二维数组
• 替换推荐用 np.where() 或直接索引赋值:
mask = np.isnan(a)<br>a[mask] = 0 # 直接原地改<br># 或<br>a = np.where(np.isnan(a), 0, a)
• 注意:
pd.DataFrame.fillna() 在底层也依赖 np.isnan(),但 pandas 对 object 列更宽容;NumPy 数组若含 None,先得统一转成 float64 再处理np.nan 和 NaN、NAN、np.NaN 有什么区别?
它们本质相同,但用法有约定:
• np.nan 是唯一推荐写法,小写、无括号、无引号
• np.NaN 和 np.NAN 是别名,存在只为兼容旧代码,官方文档明确建议“use nan instead of NAN”
• float('nan') 等价于 np.nan,但多一次解析开销,无必要不这么写
• 字符串 "NaN" 是纯文本,跟数值 NaN 完全无关,混入数组会导致 dtype 变成 object,后续所有 np.isnan() 调用都会抛 TypeError
NaN 的“传染性”和不可比较性,是设计使然,不是缺陷。真正容易出问题的地方,往往不在生成 NaN,而在于忘了它不能用 == 判断、不能出现在布尔索引条件里、也不能和 None 混用——这些地方一踩就静默失败。










