df.where()是元素级筛选,保留满足条件的值、不满足的置为NaN;与布尔索引df[cond]相反,后者返回满足条件的整行。

直接说结论: df.where() 不是“用条件筛选行”,而是“保留满足条件的值,把不满足的替换成 other(默认 NaN)”。它操作的是元素级,不是行/列筛选——这点搞错就全乱了。
为什么 df.where() 和布尔索引看起来像但行为相反?
很多人以为 df.where(cond) 等价于 df[cond],其实完全相反:df.where() 是“留真去假”,df[cond] 是“取真行”。比如 df['A'] > 5 为 True 的位置,df.where() 会保留原值;为 False 的位置,会被替换成 other 或 NaN。
- 常见错误现象:写
df.where(df.A > 5)想过滤出 A>5 的行,结果得到一个大部分是NaN的 DataFrame,只在 A>5 的位置有原值 - 使用场景:清洗数据时“只保留可信范围内的值”,比如温度列只留 0–40℃ 之间的数,其余设为缺失:
df['temp'].where((df['temp'] >= 0) & (df['temp'] - 注意
&要括号包裹,否则报ValueError: The truth value of a Series is ambiguous
other 参数怎么填才不踩坑?
other 可以是标量、Series、DataFrame,甚至函数返回值,但形状必须能广播(broadcast)对齐。最常踩的坑是类型隐式转换和缺失值传播。
- 填标量(如
-1、0)最安全,所有不满足条件的位置统一替换 - 填 Series(如
df['B'])时,会按列对齐:df.where(cond, df.B)表示“每列中不满足 cond 的位置,用df.B对应行的值来填”——不是用整列B去填整列,而是按行索引对齐 - 填
None或不传,等价于np.nan;但传字符串'missing'会导致整列 dtype 变成object,后续数值计算会报错 - 性能影响:用函数(如
lambda x: x.mean())作other不被支持,会报TypeError;想动态生成需先算好再传
和 numpy.where、mask 有什么区别?
df.where() 是 pandas 层封装,语义更贴近“条件保留”;np.where() 是三元运算,df.mask() 是它的逻辑反面(“掩掉真值,换 other”)。
-
df.where(cond, other)≡np.where(cond, df, other),但 pandas 版自动对齐索引,numpy 版要自己确保 shape 一致 -
df.mask(~cond, other)和df.where(cond, other)效果一样,但可读性差,别这么写 - 兼容性注意:老版本 pandas(other 是 DataFrame 时广播规则较松,新版本严格按索引对齐,若索引不一致会报
ValueError: Can not align boolean indexer with boolean indexer - 小技巧:想实现“条件填充”,比如“空值且满足某条件时才用均值填”,得组合用:
df['col'].where(df['col'].notna() | ~condition, df['col'].mean())
真正容易被忽略的是索引对齐这个隐式行为——你以为传了个 Series 就按位置填,其实它先按 index 匹配,index 不一致就会静默填充 NaN 或报错。调试时建议先检查 df.index.equals(other.index)。









