跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

pandas 如何处理 pd.NA 与 np.nan 的混合运算行为

pd.NA在二元运算中具有“传染性”,只要参与运算的一方是pd.NA,结果即为pd.NA;而np.nan在算术和比较中返回np.nan,且np.nan==np.nan恒为False,pd.NA==pd.NA返回pd.NA。 pd.NA 和 np.nan 混用时,运算结果会变成 pd.NA 直接说结论:
pd.NA
在几乎所有二元运算(
&
、
|
、
==
、
!=
、
+
、
>
等)中都会“传染”——只要参与运算的一方是
pd.NA
,结果就返回
pd.NA
,而不是
np.nan
。而
np.nan
虽然也传播,但只在算术和比较中返回
np.nan
,且
np.nan == np.nan
永远为
False
,而
pd.NA == pd.NA
返回的是
pd.NA
(三值逻辑),不是
True
也不是
False
。
True & pd.NA → pd.NA
;
True & np.nan → np.nan
(但注意:布尔上下文中
np.nan
会被当作
True
,引发 隐式转换 错误)
1 + pd.NA → pd.NA
;
1 + np.nan → np.nan
pd.NA == "x" → pd.NA
;
np.nan == "x" → False
(这是关键差异:后者返回布尔值,前者返回缺失) 混合列运算(如
df["a"].astype("Int64") + df["b"].astype("float64")
)会自动将结果转为
Float64
(nullable float),
pd.NA
保持为
pd.NA
,
np.nan
会被统一转为
pd.NA
(前提是 pandas ≥ 1.2.0) 为什么不能直接用 isna() 判断混合缺失?
pd.isna()
对
pd.NA
和
np.nan
都返回
True
,看起来没问题——但陷阱在于:当列类型是
object
时,
pd.isna()
可能误判
None
或字符串
"NA"
;更严重的是,
fillna()
或
dropna()
在含混合缺失的 nullable 列(如
"Int64"
)中行为一致,但在普通
float64
列里遇到
pd.NA
会直接报错:
TypeError: cannot convert NA to numeric
。 ✅ 安全做法:先统一缺失表示再操作 —— 用
df = df.convert_dtypes(dtype_backend="pyarrow")
(pandas ≥ 2.0)或显式
astype
转为 nullable 类型 ❌ 危险操作:对
float64
列调用
.astype("Int64")
—— 若含
np.nan
,会静默转成
pd.NA
;但若含
None
,可能抛
ValueError
⚠️ 注意:
df.eq(np.nan)
永远返回全
False
;而
df.eq(pd.NA)
返回全
pd.NA
—— 别用
==
去筛缺失值 如何安全地做缺失值填充或条件过滤? 核心原则:别让
pd.NA
和
np.nan
共存于同一列;一旦混合,优先升格为 nullable 类型并用
pd.NA
作为唯一缺失标记。 填充前先归一化:
df.replace([np.nan, None, "N/A", ""], pd.NA).convert_dtypes()
布尔索引必须用
.fillna(False)
或
.fillna(True)
转成纯布尔才能用于
.loc
:
df.loc[df["flag"].fillna(False)]
插值(
interpolate()
)不支持
pd.NA
—— 它只处理
np.nan
;所以含
pd.NA
的列需先
df["col"].replace(pd.NA, np.nan)
再插值(但会丢失整数类型) 聚合函数 如
sum()
、
mean()
对
pd.NA
默认跳过(类似
skipna=True
),但
min()
/
max()
在全
pd.NA
时返回
pd.NA
,而全
np.nan
时返回
np.nan
升级与兼容性:哪些版本能稳住?
pd.NA
自 pandas 1.0.0 引入,但直到 1.5.x 才稳定三值逻辑;2.0+ 默认启用
dtype_backend="numpy_nullable"
,混合缺失行为更可预测。如果你还在用 1.3.x 或更低版本,
pd.NA
在某些聚合或 join 中可能意外退化为
object
或报
NotImplementedError
。 ✅ 推荐最低版本:
pandas>=2.0.3
(修复了
pd.NA
在
groupby().agg()
中的传播 bug) ❌ 1.0–1.4.x:
pd.NA
在
merge()
中可能导致右表 key 列类型崩成
object
? 检查当前行为:
pd.array([1, pd.NA, 3], dtype="Int64").sum()
应返回
4
;若返回
np.nan
,说明底层仍走旧逻辑 真正麻烦的不是
pd.NA
本身,而是它和
np.nan
在同一 DataFrame 里共存时,你根本不知道下一次
.dtypes
或
.apply()
会触发哪条隐式转换路径。统一、尽早、强制转换,比事后 debug 快十倍。

相关文章