Python 数据清洗中缺失值的处理策略

1次阅读

缺失值处理需先判断类型与业务含义,避免盲目填充;数值列优先中位数或分组填充,类别列查分布再处理;时间列慎填;删除需限定subset和how;imputer须fit_transform与transform分离;缺失本身可作特征;关键在业务确认。

Python 数据清洗中缺失值的处理策略

pandas.DataFrame.fillna() 填什么,得先看缺失值类型和业务逻辑

直接 fillna(0)fillna("未知") 是最常见也最容易翻车的操作。缺失不等于零,也不等于空字符串——比如销售额为 NaN,填 0 会把“未上报”扭曲成“卖了零元”,后续算平均值、做分组统计全偏了。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 先用 df.isna().sum() 看哪些列缺失多,再用 df[col].dtype 判断是数值型还是类别型
  • 数值列优先考虑中位数(抗异常值)或按分组填充,比如 df.groupby("region")["sales"].transform("median")
  • 类别列别硬填 "other",先查下 df[col].value_counts(dropna=False),确认 NaN 是否真代表“未填写”,还是系统漏传
  • 时间列慎用 fillna(pd.timestamp("1970-01-01")),下游可能报 OutOfBoundsDatetime

dropna() 不是删得越狠越好,得盯住 howsubset

默认 df.dropna() 会删掉任何含 NaN 的整行,但实际中往往只要求关键字段不为空。比如用户表里 emailphone 允许缺一个,但 user_id 必须有;盲目删行可能干掉 30% 有效数据。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 明确主键/必要字段,用 subset=["user_id", "reg_date"] 限定检查范围
  • 别依赖默认 how="any",该用 how="all" 时就用——比如某行所有特征列全是 NaN 才值得删
  • 删之前先 df.dropna(..., inplace=False) 并保存原 shape,对比删了多少,心里有数
  • 注意 axis=1 删列的风险:一列缺失率 95%,删它可能让模型少一个强特征

sklearn.impute 做训练/预测一致性时,fit_transform()transform() 必须分开

在建模流程里,用 SimpleImputer 对训练集 fit_transform() 后,测试集必须只调 transform()。如果对测试集也 fit_transform(),相当于用了两套统计量(比如训练集均值 vs 测试集均值),模型上线后结果就不可复现。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 永远把 imputer 当作模型一部分,和 StandardScaler 一样存起来:joblib.dump(imputer, "imputer.pkl")
  • 别在 pd.DataFrame 上直接用 SimpleImputer,它默认输出 numpy.ndarray;加 keep_empty_features=True 和手动重建列名更稳
  • 类别型列别乱用 strategy="most_frequent"——如果某类在训练集里没出现过,测试集突然来了个新类,most_frequent 就没意义了
  • 时间序列场景下,IterativeImputer 容易过拟合,小数据集上不如前向填充 method="ffill"

缺失值标记本身可能是信号,别急着抹掉 NaN

有些字段的缺失不是脏数据,而是业务事实。比如信贷审批中 credit_score 缺失,可能代表用户拒绝授权查询;电商订单中 coupon_code 缺失,大概率是自然流量而非投放渠道。把这些当成普通缺失去填,反而丢掉了关键区分维度。

实操建议:

立即学习Python免费学习笔记(深入)”;

  • 新增二值列显式记录缺失状态,比如 df["credit_score_is_missing"] = df["credit_score"].isna()
  • NaN 当作一个合法类别编码进模型(尤其树模型),比填均值更合理
  • 警惕 df.replace({np.nan: "MISSING"}) 这种操作——字符串 "MISSING" 和真正缺失语义不同,且后续 isna() 就失效了
  • 数据库导出时若用 NULL 表示缺失,python 读进来是 NaN,但 excel 导入可能变成空字符串,得统一用 pd.read_csv(..., keep_default_na=False, na_values=["", "NULL", "N/A"])

缺失值处理最麻烦的从来不是代码怎么写,而是得反复跑回业务方确认:“这个空,到底是没填,还是不能填,还是不该填”。代码能填的只是 NaN,填不了上下文。

text=ZqhQzanResources