数据预处理:把脏数据喂给模型之前,先清理干净
说实话,我带过不少团队,大家最喜欢干的事就是拿到数据直接塞进模型。结果呢?跑出来的结果乱七八糟。我几年前接过一个金融反欺诈项目,数据里一堆null值和离群点,模型训练完准确率不到六成,排查了两天才发现是原始数据就没洗干净。
数据预处理,说白了,就是给模型吃的东西先过筛子。你想想看,拿发霉的面粉去做面包,面包能好吃吗?模型也一样。所以这一章,咱们把数据清洗、标准化、缺失值和异常值这四个硬骨头啃下来。
4.1 数据清洗:先把脏东西挑出去
数据清洗,我习惯把它想成「洗菜」。从各个数据源拿到的数据,总会有重复、无效、格式不一致的问题。具体怎么做?我列一下我常用的步骤——
- 重复值处理:用
DataFrame.duplicated()检查,再用.drop_duplicates()删掉。 - 格式统一:比如日期字段有的是“2024-01-15”,有的是“01/15/2024”。全转成标准
datetime。 - 无关特征剔除:像用户ID、时间戳这种,不是特别场景就别留着。
我遇到过最离谱的一个项目,因为用户ID列里混了全角和半角的空格,导致整个关联查询全错。该不会是格式问题吧?嗯,后来排查才发现是清洗阶段漏了这一步。
df.info() 和 df.describe(),先肉眼扫一遍有没有离谱的值。
4.2 标准化:让所有特征站在同一个尺度上
标准化,说白了,就是让不同尺度的特征能在同一个舞台上跳舞。比如一个特征是年龄(0~100),另一个特征是年收入(0~100000),如果不做标准化,模型会自动认为收入这个特征更重要——但实际情况可能完全不是这样。
我常用的两种方法:
| 方法 | 公式 | 适用场景 | 注意事项 |
|---|---|---|---|
| Z-score 标准化 | \( z = \frac{x-\mu}{\sigma} \) | 数据近似正态分布,存在离群点 | 离群点会影响均值和标准差 |
| Min-Max 标准化 | \( x' = \frac{x-min}{max-min} \) | 数据有明确边界,比如像素值0-255 | 对离群点敏感,新数据可能超出[0,1] |
我个人习惯:如果后续要做异常检测,一般先用 Z-score,因为它能保留离群点的相对关系。比如在金融交易数据里,一笔大额交易直接会被 Z-score 打到3σ以外,这对后续检测特别友好。
4.3 缺失值处理:别轻易扔掉那些“空”
缺失值在现实数据里太常见了。有些团队直接一删了事,但我告诉你,这样很可能会出事。为什么?因为缺失本身可能就包含了信息。
我的处理策略通常有三种:
- 直接删除:适用于缺失比例极小(<5%),且随机缺失的情况。用
df.dropna()就行。 - 填充:均值/中位数/众数填充。注意:分类变量用众数,连续变量用中位数(避免受离群点影响)。
- 模型预测:把缺失字段当目标,用其他字段预测它。我记得做用户画像项目时,用随机森林对缺失的年龄做预测,效果比均值填充好了近10个点。
一个简单的代码示例:
# 检查缺失比例
print(df.isnull().mean())
# 中位数填充连续变量
df['income'].fillna(df['income'].median(), inplace=True)
# 众数填充分类变量
df['gender'].fillna(df['gender'].mode()[0], inplace=True)
4.4 异常值初步筛选:先别急着戴帽子
异常值检测是个大学问,这里我们先做初步筛选——说白了,就是把那些明显“离谱”的值先挑出来,别让它们污染后面的标准化和建模。
我常用的快速方法:
- IQR 规则:小于 Q1 - 1.5×IQR 或大于 Q3 + 1.5×IQR 的,标记为可疑点。
- Z-score 规则:Z-score 值大于3的,初步判定异常。
为什么不直接删?因为有些异常值反而是关键信号。比如反欺诈场景,一笔大额交易可能就是诈骗,你删了就等于把目标样本扔了。所以初步筛选只是“标记”,不是“删除”。
import numpy as np
# IQR 方法
Q1 = df['amount'].quantile(0.25)
Q3 = df['amount'].quantile(0.75)
IQR = Q3 - Q1
outliers = df[(df['amount'] < Q1 - 1.5*IQR) | (df['amount'] > Q3 + 1.5*IQR)]
数据预处理整体流程
下面这张图是我个人总结的数据预处理工作流,把这四个环节串起来,你就不会乱了:
这张图的核心逻辑:前四个环节是串行的,缺一不可。异常值筛选放在缺失值处理之后,是因为有些缺失值本身就是异常信号,先填充再筛异常会更合理。箭头最后指向模型构建,但别忘了——预处理只是一个开始。
嗯,上面这些就是数据预处理的核心内容。做异常检测,这部分如果偷懒,后面再怎么调参都没用。下一环节我们来好好聊聊特征工程,那是把原始数据变成模型真正能用的“料”的过程。