3. 数据预处理:数据清洗、缺失值处理、标准化

数据拿到手,第一件事不是急着建模。我见过太多人把脏数据直接喂进模型,结果跑出来一堆异常值,还跑来问我「为什么模型不准」。说白了,数据预处理就像做菜前的洗菜切菜——菜不干净,厨艺再好也白搭。

这一章,我们重点解决三个问题:数据清洗、缺失值处理、标准化。这三个步骤,我在实际项目中踩过的坑不少,咱们一个一个说。

3.1 数据清洗:把脏数据筛出来

数据清洗,说白了就是去掉那些明显有问题的数据。比如重复行、无关特征、格式错误等等。

我个人习惯先做这几步:

  • 检查重复行:重复数据会拉偏统计分布,影响异常值检测的准确性。
  • 检查无关特征:比如ID列、时间戳(如果不做时序分析),这些特征对异常值检测没帮助,直接去掉。
  • 检查格式一致性:比如日期格式不统一、数值列混入字符串,这些要提前修复。

我在项目中遇到过最坑的一次:某张表里的“年龄”列,居然混了十几个“未知”字符串。如果不做清洗,这一步直接让整个异常值检测模型崩掉。

小技巧:清洗前,先用 df.info() 快速扫一眼各列的数据类型和非空计数,一眼就能看出格式问题。

3.2 缺失值处理:别着急删

嗯,这里要注意。缺失值是异常值分析里的「灰色地带」。它可能意味着数据采集失败,也可能是真实的业务缺失。

我的处理原则是三步:

  1. 先排查缺失模式:是全随机缺失?还是跟某些特征有关?
  2. 再决定策略:删除、填充,还是单独标记?
  3. 最后验证影响:处理后看看数据分布是否发生偏移。

具体策略我常用这几种:

策略 适用场景 注意事项
直接删除 缺失比很低(<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 数据预处理的整体流程

这张图我特意画出来,帮你把整个流程串起来。你可以看成一张“脱水版”的路线图:

数据预处理流程总览 原始数据 1. 数据清洗 2. 缺失值处理 3. 标准化/归一化 干净数据集 注意:清洗和缺失值处理可以并行或串行,但标准化必须在两者之后做

为什么这么排?你看看:清洗去掉脏数据,缺失值处理补上漏洞,最后标准化让所有特征尺度统一。顺序不能乱。我见过有团队先标准化再清洗,结果标准化把缺失值当成0,清洗时又删掉行,最后数据乱成一锅粥。

一句话总结:清洗去脏,填充补缺,标准化对齐——三步走完,数据才能真正交给异常值检测模型。

3.5 实战中要注意的细节

说几个我实际踩过的坑,你写代码时可以提前避开:

  • 别在原始数据上直接修改:先做一份副本。我习惯用 df_clean = df.copy(),万一改坏了还能回溯。
  • 标准化前记得处理缺失值:否则 scaler 会报错,或者把缺失值当数值处理。我当初在 KPI 异常检测项目里就犯了这个错误,标准化后缺失值变成了一个奇怪的数值,导致后续模型识别出大量假异常。
  • 记录你的预处理步骤:我习惯写一个简单的 Pipeline 配置文件,把清洗规则、填充策略、标准化参数都记下来。这在模型上线时尤其重要——测试数据必须走跟训练数据一模一样的预处理流程。

实战贴士:学会用 sklearn.pipeline.Pipeline 把清洗、填充、标准化串成一个对象。你只需要定义一次 Pipeline,后续用 pipeline.fit() 和 pipeline.transform() 就行,能很大程度避免预处理步骤遗漏。

好了,数据预处理这部分就讲到这里。记住一个原则:对数据多一份耐心,模型就少一次崩溃。项目里我因为预处理不够细,导致交付延期的情况,到现在都记得清清楚楚。希望你这一步走稳了,后续的路会顺很多。