数据预处理:异常值检测与处理方法归纳总结
好,到了第三章。前面我们聊了缺失值和数据类型,这一章我们专门对付那些「不合群」的数值——异常值。
异常值是什么?说白了就是那些明显偏离正常分布的样本。比如客户年龄填了200岁,或者月收入写了个-5000。这些数据如果不管,后面建模会出大问题。我早年做评分卡的时候,就因为漏掉了一批异常的收入数据,模型AUC直接掉了0.15。嗯,教训很深。
第一步:先搞清楚异常值从哪来
我习惯把异常值分成三类,这样后续处理才有针对性。
| 类型 | 来源 | 例子 |
|---|---|---|
| 人为录入错误 | 手误、输入格式错位 | 年龄写成了“230” |
| 设备/系统异常 | 传感器故障、网络传输丢包 | 交易金额突然多两个零 |
| 真实但极端的业务现象 | 大额存款、黑天鹅事件 | 客户月收入100万(确实真实) |
第二步:异常值检测的常用方法
方法很多,我这里只讲信用评分场景下最实用的几种。你不需要全用,选一个适合数据分布的就行。
1. Z-score(三西格玛法)
适用于近似正态分布的数据。计算每个样本与均值的距离,除以标准差。一般绝对值超过3就算异常。我在客户“负债率”变量上用过,效果不错。
import numpy as np
from scipy import stats
def detect_outliers_zscore(data, threshold=3):
z = np.abs(stats.zscore(data))
return np.where(z > threshold)[0]
2. IQR(四分位距法)
不依赖正态分布,用中位数和四分位数。定义下界 Q1 - 1.5*IQR,上界 Q3 + 1.5*IQR。超过边界就算异常。这是最通用的方法,我在几乎所有信用数据集上都会先用它扫一遍。
3. DBSCAN(基于密度的聚类)
把样本稠密区域归为簇,孤立的点标记为异常。适合分布不规则的数据,比如“客户消费金额”这种长尾分布。不过参数调起来比较麻烦,我建议先试试前两种。
4. 孤立森林(Isolation Forest)
随机切割特征空间,异常点更容易被孤立。速度快,适合高维数据。在“多头借贷”这种多变量场景下,我常用它做第一轮筛选。
第三步:异常值处理方法归纳
检测出来以后,怎么处理?下面这张表基本覆盖了所有常用策略。
| 方法 | 适用场景 | 注意 |
|---|---|---|
| 直接删除 | 数据量大、异常比例低(低于5%) | 删除后要检查样本分布是否偏移 |
| 截尾(Winsorize) | 数值型特征、异常为极端值 | 用边界值替换,保留样本数量 |
| 用中位数/均值填充 | 异常值可视为缺失 | 均值受异常影响大,优先用中位数 |
| 分箱(Binning) | 连续变量异常边界模糊 | 将异常归入“最高档”或“最低档” |
| 模型预测修正 | 有足够正常样本做回归 | 用正常值训练模型,预测替换异常 |
我个人最常用的组合是:先用IQR检测,然后对小比例异常直接删除,对大比例异常做截尾处理。比如征信查询次数这个变量,异常值往往集中在顶部,我给它设个99%分位值截断,既保留了样本量,又消除了极端影响。
一张图看懂异常值检测与处理全流程
下面这张流程图是我在项目中整理的架构,涵盖了从原始数据到清洗后数据的完整链。你可以直接复制到自己的代码笔记里。
第四步:动手前的检查清单
在实际代码跑起来之前,我建议你按下面这个顺序走一遍:
- 逐个特征看分布——箱线图、直方图,别只看统计量。
- 判断异常值是否为业务合理值——比如年收入500万在信用评分里可能不是异常,是优质客户。
- 选择检测方法——正态分布用Z-score,其他用IQR,多变量用孤立森林。
- 确定处理策略——先试删除,如果样本减少太多再换截尾。
- 回验效果——处理前后特征分布是否变好?目标变量关系是否保持?
好了,异常值这部分我们就聊到这。别看方法多,实际项目中你反复用的就那么两三个。关键是要理解数据背后的业务意义——别让算法帮你做完决定。下一环节我们会聊特征变换与标准化,把数值拉到同一个量级上。嗯,继续加油。