You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas异常值处理:置为NaN与直接删除的差异原因解析

Pandas分位数筛选两种写法的差异原因

两种写法结果不同的核心原因是:传入df[]的筛选条件结构完全不同,触发了pandas完全不同的索引逻辑。


第一种写法将异常值置为NaN的原理

你第一种写法用的筛选条件是(df < ub) & (df > lb):

  • 首先lb = df.quantile(0.01)、ub = df.quantile(0.99)的返回值是Series类型,索引为原DataFrame的列名(你的测试数据里只有calories一列,所以这个Series长度为1,索引是['calories'])。
  • 当整个DataFrame和这个Series做大小比较时,pandas会按列名对齐做广播运算,最终返回一个和原DataFrame形状完全一致的布尔DataFrame,每个单元格的值对应当前位置的数值是否在分位数范围内。
  • Pandas的索引规则里,如果传入df[]的是同形状的布尔DataFrame,不会做行删除,而是执行逐单元格的掩码逻辑:值为True的位置保留原数值,值为False的位置填充NaN。这就是你看到异常值被替换为空值的原因,本质是单元格级别的值替换,不是行筛选。

你可以自行打印验证条件的结构:

cond1 = (df < ub) & (df > lb)
print(type(cond1))  # <class 'pandas.core.frame.DataFrame'>
print(cond1.shape)  # (19, 1),和原df形状完全一致

第二种写法直接删除异常行的原理

你第二种写法用的筛选条件是(df["calories"] < q_hi) & (df["calories"] > q_low):

  • 这里q_low = df["calories"].quantile(0.01)、q_hi = df["calories"].quantile(0.99)的返回值是标量数值,不是Series。
  • 整个比较逻辑是在单列Series上执行的,最终返回一个长度和原DataFrame行数一致的一维布尔Series,每个位置对应当前行的calories值是否在分位数范围内。
  • Pandas的索引规则里,如果传入df[]的是长度和行数匹配的一维布尔序列,会执行行级筛选:值为True对应的整行保留,值为False对应的行直接丢弃。这就是异常行被直接删除的原因。

同样可以打印验证条件结构:

cond2 = (df["calories"] < q_hi) & (df["calories"] > q_low)
print(type(cond2))  # <class 'pandas.core.series.Series'>
print(len(cond2))   # 19,和原df行数一致

两种操作的功能差异总结

  • 第一种是单元格级掩码操作:会保留原数据的所有行,仅把不符合条件的单元格替换为NaN,如果是多列DataFrame,会自动按每列各自的分位数判断,逐列替换不符合条件的值。
  • 第二种是行级筛选操作:不会保留不符合条件的行,只要指定列的数值不满足阈值,整行都会被剔除,适合直接过滤异常样本的场景。

内容的提问来源于stack exchange,提问作者Shooting Stars

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 13:03:21