必须用 np.isnan() 检测 nan,因 np.nan != np.nan;填充优先用 np.where() 避免 np.nan_to_num() 误处理 inf;删除用布尔索引而非 np.delete();整数数组需转 float 才能存 nan。

用 np.isnan() 定位 NaN,别直接用 == np.nan
NumPy 中 np.nan 不等于自身,所以 a == np.nan 全返回 False,根本筛不出缺失值。必须用 np.isnan(a) 得到布尔掩码。这个判断开销极小,是后续所有操作的前提。
常见错误:写 if a[i] == np.nan: 或 a[a == np.nan] = 0 —— 这些完全无效,数组不变,还可能掩盖逻辑问题。
-
np.isnan()支持标量、1D/2D 数组,返回同形状布尔数组 - 对
object类型数组(比如混了字符串和数字),np.isnan()会报TypeError,需先转成数值类型或用pandas.isna() - 注意浮点精度:
np.float32和np.float64的 NaN 都能被正确识别
填充 NaN:优先用 np.where(),避免 np.nan_to_num() 误填
np.nan_to_num() 看似方便,但它默认把 NaN 换成 0.0,把 inf 换成极大值——很多场景你只想要处理 NaN,不碰无穷值,也不希望零值污染统计分布。
更可控的做法是用 np.where() 结合掩码:
mask = np.isnan(a) a_filled = np.where(mask, 0, a) # 填 0 a_filled = np.where(mask, np.mean(a[~mask]), a) # 填均值(需确保有非 NaN)
- 填均值/中位数时,务必先用
a[~mask]排除 NaN,否则np.mean(a)仍返回nan - 多维数组填同一值:
np.where自动广播,无需循环 - 若要按行/列分别填均值,得用
axis=参数配合np.nanmean(),再用np.where替换
删除含 NaN 的行或列:用 np.all() 或 np.any() 控制严格度
删除操作本质是布尔索引,关键在如何构造保留掩码。常用组合:
- 删掉**任意位置有 NaN 的行**:
mask_row = ~np.any(np.isnan(a), axis=1)→a[mask_row] - 删掉**整行全为 NaN 的行**:
mask_row = np.any(~np.isnan(a), axis=1)(即“至少有一个非 NaN”) - 列方向同理,把
axis=1换成axis=0
注意:np.delete() 是复制后删除,效率低于布尔索引;且它不支持按条件删除,必须先算出索引位置,多一步易错。
性能提示:对大数组,np.any() 在找到第一个 True 就短路,比 np.all() 略快;但实际差异微小,优先选语义清晰的写法。
dtype 影响很大:整数数组存不了 NaN,提前转 float
NumPy 的 int 类型数组无法容纳 np.nan(赋值会变成 0 或引发错误)。一旦数据里可能出现缺失,初始化就得用 float 类型:
a = np.array([1, 2, 3], dtype=float) # OK a[1] = np.nan # OK <p>b = np.array([1, 2, 3], dtype=int) # 不 OK b[1] = np.nan # 变成 0,且无警告</p>
- 读 CSV 或外部数据后,检查
a.dtype;若为int但业务含缺失,立刻a = a.astype(float) -
np.nan在float32和float64中行为一致,但float32精度低,某些计算(如方差)可能因舍入放大误差 - 如果必须保持整数语义(如 ID 列),缺失值应设为特定哨兵值(如
-1),并全程避开np.isnan()
真正麻烦的不是怎么填或删,而是 dtype 错了之后,NaN 要么静默消失,要么报错中断流程——这种问题往往在线上跑了一周才暴露。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











