Python缺失值处理案例有哪些?

wen python案例 1

Python缺失值处理案例全解析:从基础到实战的7大策略

目录导读

  1. 为什么缺失值处理如此重要?
  2. 简单删除法 —— 适用场景与风险
  3. 均值/中位数/众数填充 —— 数值型特征的首选
  4. 前向/后向填充 —— 时间序列数据的利器
  5. 插值法 —— 平滑填补缺失点
  6. KNN填充 —— 基于相似样本的智能填补
  7. 模型预测填充 —— 利用随机森林/LR填补
  8. 多元缺失模式下的组合策略
  9. 实战问答环节
  10. 总结与最佳实践

为什么缺失值处理如此重要?

在数据科学项目中,原始数据几乎总包含缺失值,无论是传感器故障、用户拒绝填写,还是数据合并导致的空字段,缺失值若不处理,会直接导致:

  • 机器学习模型无法训练(如sklearn报错)
  • 统计偏差(如均值被拉低)
  • 信息丢失(删除法可能移除有价值样本)

核心原则:没有万能的缺失值处理方法,必须根据数据特点、业务含义、缺失比例来选择。


案例一:简单删除法

适用场景:缺失比例极低(<5%)、样本量充足、缺失完全随机(MCAR)

import pandas as pd
df = pd.DataFrame({'A': [1, 2, None, 4], 'B': [None, 2, 3, 4]})
# 删除包含任何缺失的行
df_drop_row = df.dropna()  # 仅保留第2行(索引1)
# 删除完全缺失的行
df_drop_all = df.dropna(how='all')
# 删除指定列有缺失的行
df_drop_subset = df.dropna(subset=['A'])

风险提示:当缺失非随机(MNAR)时,删除法会引入选择偏差。“收入”字段缺失的人可能本身就是高收入群体。


案例二:均值/中位数/众数填充

最常用的基础方法,适用于数值型特征。

# 均值填充
df['age'].fillna(df['age'].mean(), inplace=True)
# 中位数填充(对异常值更鲁棒)
df['age'].fillna(df['age'].median(), inplace=True)
# 众数填充(分类变量)
df['gender'].fillna(df['gender'].mode()[0], inplace=True)

进阶案例:按分组填充(如按学历分组填充收入)

df['income'] = df.groupby('education')['income'].transform(lambda x: x.fillna(x.median()))

优缺点:简单快速,但会扭曲数据分布,降低方差。


案例三:前向/后向填充(ffill/bfill)

时间序列数据的标配,利用时间连续性填补。

# 前向填充:用上一个有效值填补
df['temperature'].fillna(method='ffill', inplace=True)
# 后向填充:用下一个有效值填补
df['temperature'].fillna(method='bfill', inplace=True)
# 限制填充步数
df['price'].fillna(method='ffill', limit=2)  # 最多向前填充2步

真实案例:股票价格缺失(如周末无交易),用前一个交易日收盘价填充最合理。


案例四:插值法

比前向填充更平滑,支持线性、多项式、样条插值。

import numpy as np
from scipy import interpolate
# 线性插值
df['value'] = df['value'].interpolate(method='linear')
# 时间索引插值(要求索引为datetime)
df['value'] = df['value'].interpolate(method='time')
# 多项式插值(order=2 二次插值)
df['value'] = df['value'].interpolate(method='polynomial', order=2)

注意:插值法假设缺失值与前后值存在函数关系,不适合离散类别变量。


案例五:KNN填充(基于相似样本)

原理:找到缺失样本的k个最近邻,用它们的均值/众数填补。

from sklearn.impute import KNNImputer
import numpy as np
X = np.array([[1, 2, np.nan],
              [3, 4, 5],
              [7, 8, 9],
              [np.nan, 5, 6]])
imputer = KNNImputer(n_neighbors=2)  # 使用2个邻居
X_filled = imputer.fit_transform(X)

优势:能利用多维信息,比单变量填充更准确。缺点:计算成本高,对于高维稀疏数据效果差。


案例六:模型预测填充

最强大的方法,将缺失列作为目标变量,其他列作为特征训练模型进行预测。

from sklearn.ensemble import RandomForestRegressor
# 假设'age'有缺失
train = df[df['age'].notna()]
test = df[df['age'].isna()]
X_train = train.drop(['age', 'id'], axis=1)
y_train = train['age']
X_test = test.drop(['age', 'id'], axis=1)
model = RandomForestRegressor()
model.fit(X_train, y_train)
predicted = model.predict(X_test)
test['age'] = predicted  # 填充回去

陷阱:如果其他特征也有缺失需要先处理(可用简单方法处理),且注意避免数据泄露。


案例七:多元缺失模式下的组合策略

真实场景中往往多种缺失并存,需要分层处理:

  1. 第一步:删除缺失率>70%的列(信息量太低)
  2. 第二步:对缺失率5%-30%的列用模型填充
  3. 第三步:对缺失率<5%的列用中位数/众数填充
  4. 第四步:若仍有缺失,用KNN兜底
# 统计缺失率
missing_rate = df.isnull().mean()
# 列处理
df.drop(columns=missing_rate[missing_rate>0.7].index, inplace=True)
# 分层填充逻辑(伪代码)
for col in df.columns:
    if 0.05 < missing_rate[col] < 0.3:
        # 模型填充
    elif missing_rate[col] <= 0.05:
        # 简单填充

实战问答环节

Q1:什么时候绝对不能使用均值填充? A:当数据分布严重偏态(如收入呈幂律分布),均值会严重扭曲数据,此时用中位数更合适,分类变量(如性别)应该用众数。

Q2:缺失比例达到40%,该选什么方法? A:首选模型预测填充或KNN填充,删除法会损失太多样本,简单填充会引入偏差,如果特征间关联性强,模型预测效果会很好。

Q3:时间序列数据中连续缺失5个点,怎么处理? A:用插值法(线性或样条)比ffill更平滑,如果有季节性模式,可以考虑周期插值,或者用ARIMA模型预测填充。

Q4:如何评估填充效果? A:可以人为构造缺失(从完整数据中随机删除一些值),然后用你的方法填充,对比原始真实值,计算MAE或RMSE,也可以观察填充前后的分布是否相似(KS检验)。

Q5:sklearn和pandas的填充有什么区别? A:pandas的fillna直接操作DataFrame,适合规则简单的填充;sklearn的SimpleImputer/KNNImputer集成在sklearn pipeline中,适合机器学习模型流程。


总结与最佳实践

方法 适用场景 优点 缺点
删除法 缺失极少,随机缺失 简单快速 损失样本,引入偏倚
均值/中位数 数值型,缺失率低 易实现 降低方差,扭曲分布
前向/后向 时间序列 时序逻辑正确 不适用于无时序数据
插值法 连续变量,顺序相关 平滑自然 假设隐含函数关系
KNN填充 多维关联 利用样本相似性 计算成本高
模型填充 高缺失率,强关联 准确度高 易过拟合,需避免数据泄露

最终建议

  1. 先可视化缺失模式(seaborn的热力图或缺失矩阵)
  2. 检查缺失原因:是随机缺失(MCAR)还是有系统原因(MNAR)?
  3. 对每种方法做交叉验证评估
  4. 保存填充逻辑(如均值值、插值参数)用于新数据

缺失值处理没有银弹,但掌握了上述7个案例和取舍原则,你已经具备了解决90%以上缺失问题的能力。最好的缺失值处理,是尽量减少缺失本身(如优化数据采集流程)。

(如需更完整的代码和数据集,可访问真实数据科学竞赛平台Kaggle的缺失值处理教程模块)

标签: 插值方法

抱歉,评论功能暂时关闭!