fillna和dropna无优劣之分,只看业务逻辑是否强制要求删除(如主键为空、时间列缺失)或安全填充(按类型分治:数值用中位数、分类用unknown、时间用NaT),禁用inplace,空值本身可能是关键业务信号。

fillna 和 dropna 没有“哪个更好”,只有“哪个更合适”——选错会导致信息丢失、类型错误或后续报错,比如把 pd.NaT 强行填成 0,或者用 df.dropna() 一键删掉 30% 样本却没意识到。
什么时候必须用 dropna 而不是填?
删不是懒,是业务逻辑强制要求:
-
dropna(subset=["user_id"]):主键列为空,整条记录无法关联,留着反而污染 join 结果 -
dropna(thresh=len(df.columns)-1):宽表中允许最多一列缺失,但少于该阈值的行已不可信 -
dropna(axis=1, how="all"):某列全为NaN,说明上游根本没传这个字段,不是缺失,是废弃 - 时间序列中
timestamp列缺失:没法排序、没法 resample,填pd.NaT也无济于事,不如删
什么时候硬填 fillna 反而埋雷?
填不是补,是做假设;填错等于给模型喂错信号:
- 对
"category"列用fillna(0)→ 报TypeError: cannot convert float NaN to integer,字符串列不能填数字 - 对
"price"列用fillna(df.price.mean())→ 若含异常高价(如 99999),均值被拉高,填出来全是偏高的假数据 - 对
"signup_date"列用fillna("1970-01-01")→ 类型变成 object,后续.dt.month直接炸 - 批量填时写
df.fillna({"A": 0, "B": 0})却忘了"B"是日期列 → 填完df.B.dtype变成object,静默损坏
fillna 安全填法:按列类型+语义分治
别图省事用统一值,先看列类型再决定填什么:
立即学习“Python免费学习笔记(深入)”;
- 数值列(连续):
df["revenue"].fillna(df.revenue.median(), inplace=False),中位数比均值抗异常点 - 分类列(object):
df["region"].fillna("unknown"),后续可用pd.get_dummies(..., dummy_na=True)单独编码空值 - 时间列(datetime64):
df["event_time"].fillna(pd.NaT),保持 dtype 不变,支持所有.dt操作 - 布尔列:
df["is_premium"].fillna(False),需确认业务上“空”是否等价于“否” - 批量操作推荐字典:
df = df.fillna({"revenue": df.revenue.median(), "region": "unknown", "event_time": pd.NaT})
inplace=True 是过时陷阱,现在该彻底停用
Pandas 2.0+ 已移除 fillna 的 inplace 支持(只警告),dropna 的 inplace 也标记为 deprecated。继续用会遇到:
- 链式调用断裂:
df.dropna().fillna(0)在inplace=True下直接报错 - 调试失焦:你改了哪一步?原 df 被谁覆盖?中间态完全不可追溯
- 函数式习惯断裂:pandas 设计哲学是 immutable,默认返回新对象,强行就地修改违背底层逻辑
正确姿势永远是显式赋值:df = df.dropna(subset=["email"]) 或 df_clean = df.fillna({...})。
真正容易被忽略的,是缺失值本身携带的业务信号——比如 "coupon_code" 列 82% 为空,不是要急着填 "none",而是该查上游:是不是优惠系统只在大促期间开启?这时候空值率反而是关键特征。


















