
dropna 默认只删整行,但实际常要按列或设阈值
默认 df.dropna() 会删掉只要含任意 NaN 的整行,这在真实数据中太激进——比如你只想剔除 "email" 列为空的记录,其他字段哪怕全是空也不动。这时候必须显式指定 subset 参数:
-
df.dropna(subset=["email"]):仅当"email"列为NaN时才删该行 -
df.dropna(thresh=3):保留至少有 3 个非空值的行(适合宽表中容忍部分字段缺失) -
df.dropna(axis=1, how="all"):删掉整列全为NaN的列,不是默认行为
注意:how="any"(默认)和 how="all" 控制的是“一行/一列中多少个空值触发删除”,别和 thresh 混用;二者互斥。
fillna 填什么,取决于字段语义而非统一用 0 或均值
用 df.fillna(0) 填数值列看似简单,但填到 "price" 列可能合理,填到 "category"(字符串列)就直接报错;填到 "signup_date"(时间列)更会把 NaN 变成 0 这个非法日期。正确做法是分列处理:
-
df["price"].fillna(df["price"].median(), inplace=True):对偏态价格用中位数,比均值抗异常值 -
df["category"].fillna("unknown"):分类字段填占位符,后续可做pd.get_dummies(..., dummy_na=True) -
df["signup_date"].fillna(pd.NaT):时间列保持NaT类型,别用字符串或数字硬塞
批量填不同值?用字典:df.fillna({"price": df.price.median(), "category": "unknown"}),比链式调用清晰。
立即学习“Python免费学习笔记(深入)”;
inplace=True 是陷阱,多数时候该用赋值
dropna 和 fillna 默认返回新 DataFrame,不修改原对象。很多人加 inplace=True 图省事,但问题不少:
- 链式操作失效:
df.dropna().fillna(0)在inplace=True下无法连写 - 调试困难:原
df被静默修改,中间状态无法检查 - Pandas 2.0+ 已弃用
inplace对fillna的支持(警告),未来会彻底移除
安全写法始终是显式赋值:df = df.dropna(subset=["email"]) 或 df_clean = df.fillna({...})。内存多开一份拷贝,远比调试半天找不出哪步改了原数据划算。
缺失值模式本身就有信息,别急着删或填
比如电商订单表中,"discount_code" 大量为空,可能说明“未使用优惠券”是常态;若空值集中在某几天,可能是上游系统那几天故障。直接 dropna 或统一填 "none" 就丢掉了这个信号。
建议先探查:df.isnull().sum() / len(df) 看各列缺失率;再用 df[df["discount_code"].isnull()]["order_date"].dt.date.value_counts().head() 查空值的时间分布。真正需要干预的,往往是缺失率过高(>30%)且无业务解释的列,或者影响关键模型训练的字段。


















