数据清洗与预处理
数据清洗这项工作,说白了就是给原始数据「洗澡」。我见过太多团队,模型怎么调都不收敛,最后发现是特征里藏着各种垃圾。今天咱们就聊聊缺失值、异常值、重复数据这三座大山。
缺失值处理:别让空洞毁了模型
我最开始做特征工程时,以为缺失值就是简单的「扔掉」或者「填个平均值」。直到在一次风控项目中,特征缺失模式直接暴露了数据采集漏洞——嗯,从那以后我再也不随便填数了。
判断缺失类型
- 完全随机缺失 (MCAR):缺失与任何变量无关。可以直接删除或简单填充。
- 随机缺失 (MAR):缺失与其他观测变量有关。需要用模型预测填充。
- 非随机缺失 (MNAR):缺失与缺失值本身有关。最棘手,必须了解业务背景。
我个人习惯先画一张缺失热力图——用 missingno 库几行代码就能看出缺失模式。如果是MCAR且缺失率低于5%,直接删行通常没问题;但超过20%,就要小心了。
常用填充策略
| 方法 | 适用场景 | 注意事项 |
|---|---|---|
| 均值/中位数填充 | 数值型、低缺失率 | 会降低方差,影响模型区分度 |
| 众数填充 | 分类型 | 如果众数占比太高,可能引入偏差 |
| 前向/后向填充 | 时间序列 | 注意时间窗口边界处理 |
| KNN填充 | 中小数据集 | 计算量随样本数平方增长 |
| 模型预测填充 | 缺失与其他特征强相关 | 防止过拟合,需要用交叉验证 |
import pandas as pd
from sklearn.impute import KNNImputer
# 我常用的KNN填充
imputer = KNNImputer(n_neighbors=5, weights='distance')
df_imputed = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)
千万不要在填充前做特征缩放!标准差会被填充值拉偏。我曾经踩过这个坑,导致模型训练时loss死活下不去。
异常值检测与修正:一粒老鼠屎坏一锅粥
异常值不只是「大数」或「小数」,还包括不合逻辑的组合。比如年龄=200,或者性别=3。你想想看,这些数据喂进模型,梯度下降直接迷路。
检测方法对比
| 方法 | 原理 | 最佳使用场景 |
|---|---|---|
| Z-Score | 计算偏离均值的标准差倍数 | 数据近似正态分布 |
| IQR(四分位距) | Q1-1.5*IQR 和 Q3+1.5*IQR 之外 | 偏态分布或含有大量离群点 |
| Isolation Forest | 随机切割,孤立点更容易被切出 | 高维数据,特征数>10 |
| DBSCAN | 密度聚类,低密度点为异常 | 空间数据或地理坐标 |
import numpy as np
from scipy import stats
# Z-Score 检测:以3倍标准差为阈值
z_scores = np.abs(stats.zscore(df['column']))
outliers = np.where(z_scores > 3)
print(f"检测到 {len(outliers[0])} 个异常值")
修正策略
- 截断(Winsorization):将异常值限制在99%分位数以内。我在电商价格特征里经常用。
- 模型预测替换:用正常值训练回归模型,预测异常点应取值。
- 标记为缺失:先标记再走缺失值处理流程。
曾经有个客户数据集里用户年龄列有大量999。用IQR一查,999离中位数远了40个IQR……直接标记为缺失,然后用KNN填充,最终模型AUC提升了3%。
数据去重与一致性检查
重复数据比缺失数据更隐蔽。我见过一个项目,模型性能很好,但上线后发现预测结果毫无价值——原因就是训练集里90%都是重复样本。你想想看,模型学会了「背答案」,哪来的泛化能力?
去重三步走
- 完全去重:所有字段完全一致,直接删除多余行。
- 部分去重:关键字段一致(比如用户ID+时间戳),但其他字段略有差异——需要聚合或保留最新记录。
- 近似去重:使用SimHash、MinHash等算法检测文本相似度,例如评论数据中的刷帖。
# 完全去重
df.drop_duplicates(inplace=True)
# 部分去重:保留每个用户的最新记录
df.sort_values('timestamp').drop_duplicates(subset=['user_id'], keep='last')
一致性检查清单
| 检查项 | 示例 | 处理方法 |
|---|---|---|
| 数据范围 | 性别字段出现'M'、'F'、'男'、'女'、'1' | 统一编码映射 |
| 单位统一 | 部分记录是米,部分是厘米 | 全部转换为同一单位 |
| 时间格式 | 2024-01-01 和 01/01/2024 | 使用pandas.to_datetime统一格式 |
| 逻辑约束 | 订单日期 > 发货日期 | 标记异常或修正 |
| 编码一致性 | 省份名称拼写错误("四川" vs "四州") | 建立标准字典模糊匹配 |
我建议每个数据集开始时都跑一个「数据质量报告」:统计缺失率、唯一值数、最大值最小值、常见脏数据。pandas-profiling(现ydata-profiling)能一键生成,省时省力。
数据清洗没有一招鲜。但你只要把缺失、异常、重复、一致这四个关口把好,后续的特征工程会顺很多。别急,一步一个坑踩过来,模型自然就稳了。