4、回放数据预处理:数据清洗、缺失值处理、异常值检测、数据标准化
数据回放,说白了就是把录下来的操作重新跑一遍。但现实中的数据,从来都不是干干净净的。我做了这么多年数据工程,见过太多「录进去是垃圾,回放出来还是垃圾」的案例。所以,预处理这一步,我建议你把它当成整个回放流程的基石。
嗯,咱们直接进入正题。这一章,我会带你过一遍数据预处理的四个核心环节:清洗、缺失值、异常值、标准化。每个环节我都会结合我踩过的坑来讲。
4.1 数据清洗:把脏东西筛出去
数据清洗,说白了就是「去杂质」。我遇到过最离谱的一次,回放数据里居然混入了测试环境的日志,时间戳全是乱的。你想想看,这种数据回放出来,结果能对吗?
常见的脏数据有这几类:
- 重复数据:同一个操作被录了两次,回放时就会多执行一次。
- 格式不一致:比如时间戳有的是"2024-01-01",有的是"01/01/2024"。
- 无效字符:比如字段里混入了换行符、特殊符号。
- 超出范围的值:比如年龄字段出现了 -1 或者 200。
我个人习惯,清洗的第一步永远是做一次「全字段扫描」。写个脚本,把每个字段的类型、范围、唯一值数量都打印出来。这样一眼就能看出问题。
核心原则:清洗不是删数据,而是让数据变得「可用」。能修复的尽量修复,实在修复不了的才考虑删除。
4.2 缺失值处理:别让空值毁了回放
缺失值,是回放数据里最常见的问题。我记得有一次做金融交易的回放,某个关键字段「订单金额」有 5% 的缺失。如果直接跳过这些记录,回放结果就会失真。
处理缺失值,我一般按这个优先级来:
- 直接删除:如果缺失比例很小(比如 < 1%),且不影响整体分布,直接删掉最省事。
- 填充默认值:比如数值型字段填 0,字符串型字段填 "unknown"。
- 均值/中位数填充:适合数值型字段,且数据分布比较集中。
- 前向/后向填充:适合时间序列数据,比如回放日志里某个字段突然空了,用前一条记录的值补上。
- 模型预测填充:如果缺失值很重要,且数据量够大,可以用机器学习模型来预测缺失值。
我的经验:对于回放数据,我强烈推荐「前向填充」。因为回放数据本质上是时间序列,前一条记录的值往往和后一条高度相关。我曾经用这个方法修复过一批传感器回放数据,效果出奇的好。
4.3 异常值检测:揪出那些「不听话」的数据
异常值,就是那些明显偏离正常范围的数据点。比如用户点击速度突然从每秒 5 次飙升到每秒 1000 次——这明显是机器在刷数据,不是真人操作。
我常用的异常值检测方法有这三种:
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 3σ 原则 | 数据服从正态分布 | 简单快速 | 对非正态分布效果差 |
| 箱线图法 (IQR) | 任意分布 | 不受极端值影响 | 需要手动调整阈值 |
| 孤立森林 | 高维数据 | 适合大规模数据 | 解释性较差 |
为什么会这样?因为不同的数据分布,适合不同的检测方法。我个人习惯先用箱线图法快速扫一遍,如果发现异常值比例很高,再换孤立森林做精细检测。
避坑指南:我曾经在某个项目中,直接用 3σ 原则去检测非正态分布的数据,结果把大量正常值误判为异常值。后来改用 IQR 方法,才得到合理的结果。所以,选方法之前,一定要先看看数据的分布形态。
4.4 数据标准化:让不同量纲的数据「对齐」
标准化,就是把不同量纲的数据映射到同一个尺度上。比如回放数据里,既有「点击次数」(0-100),又有「页面加载时间」(0-5000 毫秒)。如果不做标准化,模型就会天然偏向数值大的特征。
常用的标准化方法:
- Z-score 标准化:将数据转换为均值为 0、标准差为 1 的分布。适合数据近似正态分布的情况。
- Min-Max 标准化:将数据缩放到 [0, 1] 区间。适合数据有明确边界的情况。
- Robust 标准化:使用中位数和四分位距,对异常值不敏感。适合数据包含较多异常值的情况。
嗯,这里要注意:标准化不是万能的。如果数据本身就有问题(比如大量缺失或异常),标准化只会放大这些问题。所以,一定要先做完清洗、缺失值处理和异常值检测,最后再做标准化。
我的建议:对于回放数据,我一般优先用 Z-score 标准化。因为回放数据往往涉及多个维度,Z-score 能保留数据的相对关系,不会像 Min-Max 那样被极端值拉偏。
4.5 本章知识体系
下面这张图,是我自己总结的数据预处理流程。你可以把它当成一个检查清单,每次做回放数据预处理时,按这个顺序过一遍。
4.6 实战代码示例
最后,给你一个我常用的预处理脚本框架。你可以根据自己的数据格式,直接修改字段名和参数。
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
# 1. 加载数据
df = pd.read_csv('replay_data.csv')
# 2. 数据清洗:删除重复行
df = df.drop_duplicates()
# 3. 缺失值处理:前向填充
df = df.fillna(method='ffill')
# 4. 异常值检测:使用 IQR 方法
Q1 = df['value'].quantile(0.25)
Q3 = df['value'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
df = df[(df['value'] >= lower_bound) & (df['value'] <= upper_bound)]
# 5. 数据标准化:Z-score
scaler = StandardScaler()
df['value_scaled'] = scaler.fit_transform(df[['value']])
print('预处理完成,剩余记录数:', len(df))
嗯,这个脚本虽然简单,但我在多个项目中都用过,效果很稳定。你只需要根据实际情况调整阈值和填充策略就行。
最后提醒一句:预处理没有「万能公式」。每个数据集都有自己的脾气,多试几种方法,找到最适合你数据的那一套流程。