4、数据清洗基础:缺失值处理、异常值检测、重复去重与噪声过滤

数据清洗是数据预处理中最耗时、最关键的环节。原始数据通常包含缺失值、异常值、重复记录和噪声,这些问题会直接导致模型训练偏差、过拟合或泛化能力下降。本章系统讲解四大清洗任务的核心方法与适用场景。

4.1 缺失值处理

缺失值指数据集中某个或某些字段为空(NaN、Null、None)。处理策略分为三类:删除、填充和插值。

4.1.1 缺失值处理策略对比

策略 方法 适用场景 注意事项
删除 删除含缺失值的行或列 缺失比例 < 5%,且缺失随机 删除过多会损失样本量,导致模型欠拟合
填充 均值/中位数/众数/常数/前向填充 缺失比例 5%~30%,数据分布稳定 均值填充会降低方差,影响模型对极端值的敏感度
插值 线性插值、多项式插值、KNN插值 时间序列或连续特征,缺失比例 > 30% 计算成本高,需验证插值合理性

4.1.2 填充与插值代码示例

import pandas as pd
import numpy as np

# 示例数据
df = pd.DataFrame({
    'A': [1, 2, np.nan, 4, 5],
    'B': [10, np.nan, 30, 40, np.nan],
    'C': [100, 200, 300, np.nan, 500]
})

# 均值填充
df['A'].fillna(df['A'].mean(), inplace=True)

# 前向填充(时间序列常用)
df['B'].fillna(method='ffill', inplace=True)

# 线性插值
df['C'].interpolate(method='linear', inplace=True)

print(df)
实践建议:对于分类特征,优先使用众数填充;对于数值特征且缺失比例较高时,KNN插值(k=5)通常比均值填充更稳健。

4.2 异常值检测与处理

异常值(Outlier)是显著偏离数据整体分布的观测值。异常值可能由测量误差、数据录入错误或真实稀有事件引起,需根据业务场景决定是否处理。

4.2.1 常用检测方法

  • Z-Score 方法:假设数据服从正态分布,Z-Score > 3 或 < -3 视为异常。
  • IQR 四分位距法:低于 Q1 - 1.5×IQR 或高于 Q3 + 1.5×IQR 视为异常。
  • 孤立森林(Isolation Forest):基于树模型,适合高维数据。
  • DBSCAN 聚类:基于密度,无法归入任何簇的点视为异常。

4.2.2 异常值处理策略

策略 操作 适用场景
删除 直接移除异常值所在行 异常值比例 < 1%,且确认是录入错误
截尾 将异常值替换为边界值(如 99% 分位数) 异常值比例 1%~5%,保留样本量
转换 对数变换、Box-Cox 变换压缩极端值 数据分布严重右偏,异常值来自真实长尾
标记 新增一列标记是否为异常值 异常值可能包含业务信号(如欺诈检测)
注意:不要盲目删除异常值。在金融风控、医疗诊断等场景中,异常值往往代表关键事件,标记后保留比删除更有价值。

4.3 重复数据去重

重复数据指完全一致或关键字段一致的多条记录。重复数据会导致模型对相同样本过度学习,造成过拟合和评估指标虚高。

4.3.1 去重策略

  • 完全去重:所有字段完全一致,直接删除保留一条。
  • 部分去重:指定关键字段(如用户ID+时间戳)去重,保留最新或最完整记录。
  • 模糊去重:使用编辑距离、Jaccard相似度等算法,合并相似记录。
# 完全去重
df.drop_duplicates(inplace=True)

# 部分去重:基于 'user_id' 和 'date' 去重,保留最后一条
df.drop_duplicates(subset=['user_id', 'date'], keep='last', inplace=True)

# 模糊去重示例(使用 recordlinkage 库)
import recordlinkage
indexer = recordlinkage.Index()
indexer.block('city')  # 按城市分块
pairs = indexer.index(df)

4.4 噪声数据过滤

噪声数据指数据中随机错误或方差较大的波动,常见于传感器采集、文本OCR识别、网络爬虫等场景。噪声与异常值的区别在于:噪声是随机、无规律的微小扰动,而异常值是显著偏离的极端点。

4.4.1 常见噪声类型与过滤方法

噪声类型 示例 过滤方法
高斯噪声 传感器随机波动 移动平均滤波、高斯滤波
脉冲噪声 单点突变的毛刺 中值滤波、限幅滤波
文本噪声 OCR识别错字、爬虫乱码 正则清洗、拼写校正、停用词过滤
标签噪声 标注错误、类别混淆 交叉验证清洗、置信度过滤

4.4.2 信号滤波代码示例

import numpy as np
from scipy.signal import medfilt

# 模拟含脉冲噪声的信号
signal = np.array([1.0, 1.1, 5.0, 1.0, 1.05, 1.2, 8.0, 1.1])

# 中值滤波(窗口大小=3)
filtered = medfilt(signal, kernel_size=3)
print("原始信号:", signal)
print("滤波后:", filtered)
关键原则:噪声过滤的强度需要权衡。过度滤波会抹除真实信号中的细节,导致信息丢失;滤波不足则噪声残留影响模型稳定性。建议先可视化数据分布,再选择滤波参数。

4.5 数据清洗流程总览

下图展示了从原始数据到干净数据的完整清洗流程,包含本章涉及的四大核心任务及其执行顺序。

数据清洗完整流程 原始数据 步骤1:缺失值处理 删除 / 填充 / 插值 步骤2:异常值检测与处理 Z-Score / IQR / 孤立森林 步骤3:重复数据去重 完全去重 / 部分去重 / 模糊去重 步骤4:噪声数据过滤 中值滤波 / 正则清洗 / 置信度过滤 干净数据集
流程说明:建议按“缺失值 → 异常值 → 重复值 → 噪声”的顺序执行清洗。先处理缺失值可以避免后续异常值检测时因空值导致的误判;最后做噪声过滤可以保证信号质量后再进行特征工程。