pandas df.apply含NaN条件判断失效问题排查与解决
问题产生原因
三种写法无法匹配NaN值的核心原因是空值判断逻辑全部存在错误,具体问题如下:
row['prop1']==np.nan判断完全无效:NaN的核心特性是和任何值做等值比较的结果都为False,包括NaN自身,执行np.nan == np.nan会直接返回False,该判断分支永远不会被触发。row['prop1']==None判断覆盖场景有限:pandas中数值型列的默认空值是np.nan而非Python原生的None,除非列是object类型,否则等值匹配None的结果同样为False,无法识别数值列的空值。not row['prop1']判断逻辑存在误判风险:该表达式除了会把NaN判定为真,还会将0、空字符串、布尔False这类合法非空值误判为需要替换的场景,且部分版本下对NaN做布尔转换会抛出警告,逻辑可靠性极差。
代码能正常识别超出quart95的异常值,是因为数值大小比较的逻辑本身没有问题,仅空值判断分支全部失效,导致NaN场景无法命中。
修正方案
首先提前计算两个固定值,避免在循环中重复计算浪费性能:
- prop1列的95分位值:
quart95 = df['prop1'].quantile(0.95) - prop1列的众数:注意
mode()方法返回的是包含所有众数的Series,通常取第一个即可:mode_val = df['prop1'].mode().iloc[0]
写法1:修正原apply逻辑
将错误的空值判断替换为pandas提供的通用空值检测方法pd.isna(),该方法可以兼容识别np.nan、None、pd.NA等所有pandas支持的空值类型,修正后代码如下:
import pandas as pd import numpy as np df['prop1'] = df.apply( lambda row: mode_val if (pd.isna(row['prop1']) or row['prop1'] > quart95) and row['prop2'] == 'some_value' else row['prop1'], axis=1 )
写法2:推荐的向量化实现(性能远高于apply)
逐行apply本质是Python层的循环,数据量较大时性能很差,更推荐用pandas原生的向量化操作实现,执行效率会有数量级提升:
# 构造需要替换值的布尔掩码 replace_mask = (pd.isna(df['prop1']) | (df['prop1'] > quart95)) & (df['prop2'] == 'some_value') # 定位对应位置批量替换为众数 df.loc[replace_mask, 'prop1'] = mode_val
注:不要用
np.isnan()做通用空值判断,该方法遇到字符串、时间等非数值类型的空值时会直接抛出报错,pd.isna()的兼容性更好。
内容的提问来源于stack exchange,提问作者Miguel Gómez
相关产品推荐
相关产品推荐

