3. 数据预处理:数据清洗、缺失值处理、标准化
数据拿到手,第一件事不是急着建模。我见过太多人把脏数据直接喂进模型,结果跑出来一堆异常值,还跑来问我「为什么模型不准」。说白了,数据预处理就像做菜前的洗菜切菜——菜不干净,厨艺再好也白搭。
这一章,我们重点解决三个问题:数据清洗、缺失值处理、标准化。这三个步骤,我在实际项目中踩过的坑不少,咱们一个一个说。
3.1 数据清洗:把脏数据筛出来
数据清洗,说白了就是去掉那些明显有问题的数据。比如重复行、无关特征、格式错误等等。
我个人习惯先做这几步:
- 检查重复行:重复数据会拉偏统计分布,影响异常值检测的准确性。
- 检查无关特征:比如ID列、时间戳(如果不做时序分析),这些特征对异常值检测没帮助,直接去掉。
- 检查格式一致性:比如日期格式不统一、数值列混入字符串,这些要提前修复。
我在项目中遇到过最坑的一次:某张表里的“年龄”列,居然混了十几个“未知”字符串。如果不做清洗,这一步直接让整个异常值检测模型崩掉。
小技巧:清洗前,先用 df.info() 快速扫一眼各列的数据类型和非空计数,一眼就能看出格式问题。
3.2 缺失值处理:别着急删
嗯,这里要注意。缺失值是异常值分析里的「灰色地带」。它可能意味着数据采集失败,也可能是真实的业务缺失。
我的处理原则是三步:
- 先排查缺失模式:是全随机缺失?还是跟某些特征有关?
- 再决定策略:删除、填充,还是单独标记?
- 最后验证影响:处理后看看数据分布是否发生偏移。
具体策略我常用这几种:
| 策略 | 适用场景 | 注意事项 |
|---|---|---|
| 直接删除 | 缺失比很低(<5%),且随机分布 | 避免连续删除过多行,打乱样本结构 |
| 均值/中位数填充 | 数值型特征,缺失比适中 | 会拉低方差,适合模型对分布不敏感的场景 |
| KNN回归填充 | 特征间存在相关性 | 计算量大,适合小数据集 |
| 标记为特殊值 | 缺失本身有意义(如用户未填写) | 常用 -999 或 NaN 类别 |
举个例子,你想想看,金融风控场景里,用户没填收入可能意味着收入极低或极高,这种缺失就不能随便填充。我曾经在信贷评分项目里,用特殊值标记法处理收入缺失,反而提升了模型的区分度。
避坑指南:千万不要在缺失值处理前做标准化。因为填充后的数据矩阵行数和特征数变了,标准化时会把缺失值当成真实值处理,结果全错。我曾经因为这个顺序问题,浪费了整整一个下午。
3.3 标准化:让特征站在同一起跑线
为什么标准化很重要?因为异常值检测算法通常基于距离(如欧氏距离、马氏距离)。如果某个特征的数值范围特别大(比如“收入”从几千到几百万),它就会主导距离计算,其他特征(如“年龄”20-60)直接被忽略。
常用的标准化方法,我整理成表格方便对比:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score 标准化 | (x - μ) / σ | 数据近似正态分布,且存在明显离群点 |
| Min-Max 归一化 | (x - min) / (max - min) | 数据有上下界,且无极端离群点 |
| RobustScaler | (x - median) / IQR | 数据存在大量离群点,不适合Z-score |
我个人偏好 Z-score,因为它保留了离群点相对位置的信息。标准化后的数据,均值约0,标准差约1。但注意,如果数据本身非常稀疏(比如大部分是0),RobustScaler 会更稳健。
代码示例:
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
# 假设 df 已清洗,缺失值已处理
features = ['feature_a', 'feature_b', 'feature_c']
# Z-score 标准化
scaler_z = StandardScaler()
df[features] = scaler_z.fit_transform(df[features])
# RobustScaler(抗离群点)
scaler_r = RobustScaler()
df[features] = scaler_r.fit_transform(df[features])
核心要点:标准化必须在训练集上 fit,然后用同样的 scaler transform 测试集。我见过有人对测试集重新 fit,结果训练集和测试集的分布不一致,模型直接废了。
3.4 数据预处理的整体流程
这张图我特意画出来,帮你把整个流程串起来。你可以看成一张“脱水版”的路线图:
为什么这么排?你看看:清洗去掉脏数据,缺失值处理补上漏洞,最后标准化让所有特征尺度统一。顺序不能乱。我见过有团队先标准化再清洗,结果标准化把缺失值当成0,清洗时又删掉行,最后数据乱成一锅粥。
一句话总结:清洗去脏,填充补缺,标准化对齐——三步走完,数据才能真正交给异常值检测模型。
3.5 实战中要注意的细节
说几个我实际踩过的坑,你写代码时可以提前避开:
- 别在原始数据上直接修改:先做一份副本。我习惯用
df_clean = df.copy(),万一改坏了还能回溯。 - 标准化前记得处理缺失值:否则 scaler 会报错,或者把缺失值当数值处理。我当初在 KPI 异常检测项目里就犯了这个错误,标准化后缺失值变成了一个奇怪的数值,导致后续模型识别出大量假异常。
- 记录你的预处理步骤:我习惯写一个简单的 Pipeline 配置文件,把清洗规则、填充策略、标准化参数都记下来。这在模型上线时尤其重要——测试数据必须走跟训练数据一模一样的预处理流程。
实战贴士:学会用 sklearn.pipeline.Pipeline 把清洗、填充、标准化串成一个对象。你只需要定义一次 Pipeline,后续用 pipeline.fit() 和 pipeline.transform() 就行,能很大程度避免预处理步骤遗漏。
好了,数据预处理这部分就讲到这里。记住一个原则:对数据多一份耐心,模型就少一次崩溃。项目里我因为预处理不够细,导致交付延期的情况,到现在都记得清清楚楚。希望你这一步走稳了,后续的路会顺很多。