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 数据清洗流程总览
下图展示了从原始数据到干净数据的完整清洗流程,包含本章涉及的四大核心任务及其执行顺序。
流程说明:建议按“缺失值 → 异常值 → 重复值 → 噪声”的顺序执行清洗。先处理缺失值可以避免后续异常值检测时因空值导致的误判;最后做噪声过滤可以保证信号质量后再进行特征工程。