数据清洗与预处理:缺失值处理、异常值检测、数据标准化、时间戳对齐
大家好,我是你们这趟数据回放之旅的向导。今天咱们聊一个绕不开的话题——数据清洗与预处理。
说实话,我见过太多项目,算法模型调得再漂亮,最后死在了数据质量上。数据回放更是如此,你回放的是历史数据,如果数据本身就有问题,那回放出来的结果就是垃圾。嗯,这话可能有点糙,但理不糙。
这一章,我会把数据清洗和预处理的四个核心环节拆开揉碎了讲。包括:缺失值怎么处理、异常值怎么揪出来、数据怎么标准化、时间戳怎么对齐。每个点我都会结合我踩过的坑来说。
核心观点:数据清洗不是一次性工作,而是贯穿整个数据回放流程的迭代过程。你永远不可能拿到“完美”的数据,但你可以通过系统化的方法,让数据“足够好”。
一、缺失值处理:别让“空”坑了你
先说说缺失值。我在项目中遇到过最离谱的一次,是某传感器在凌晨3点到5点之间,数据全部丢失。原因是那台设备所在的机房断电了。你想想看,如果我不处理这些缺失值,直接拿去回放,那这两个小时的回放结果就是一片空白,完全没法用。
缺失值处理,说白了就三种思路:
- 删除法:直接扔掉有缺失的行或列。简单粗暴,但会损失数据量。
- 填充法:用某种策略把空值补上。比如用均值、中位数、众数,或者用前后值填充。
- 插值法:更高级一点,用线性插值、多项式插值,甚至用机器学习模型去预测缺失值。
我个人习惯,先看缺失比例。如果某个字段缺失超过70%,我一般直接删掉这列。如果缺失不多,比如5%以内,我会用均值或中位数填充。但要注意,时间序列数据里,用前后值填充往往更合理。
小技巧:对于时间序列数据,我推荐用 pandas 的 ffill() 或 bfill() 方法。前者用上一个有效值填充,后者用下一个有效值填充。简单高效。
import pandas as pd
# 读取数据
df = pd.read_csv('sensor_data.csv')
# 查看缺失情况
print(df.isnull().sum())
# 用前向填充处理时间序列缺失
df['temperature'].fillna(method='ffill', inplace=True)
# 如果开头也有缺失,用后向填充
df['temperature'].fillna(method='bfill', inplace=True)
二、异常值检测:揪出那些“不听话”的数据点
异常值,说白了就是那些明显偏离正常范围的数据点。比如温度传感器突然跳到了1000度,这明显是设备故障或者通信错误。
我曾经在一个风电项目里,发现某台风机的转速数据里,每隔几秒就出现一个负值。你想想看,转速怎么可能为负?后来排查发现是传感器接线松了。如果不处理这些异常值,回放出来的功率曲线会完全失真。
常用的异常值检测方法有:
- 3σ原则:假设数据服从正态分布,超出均值±3倍标准差的数据视为异常。
- 箱线图法:用四分位数(Q1和Q3)和IQR(四分位距)来界定异常值。超出Q1-1.5*IQR或Q3+1.5*IQR的视为异常。
- 领域知识法:根据业务逻辑设定合理范围。比如电压正常范围是380V±10%,超出这个范围的直接标红。
注意:不要盲目删除异常值。有些异常值其实是真实事件,比如设备故障前的异常波动。我建议先标记,再人工确认。
import numpy as np
# 用3σ原则检测异常值
def detect_outliers_zscore(data, threshold=3):
z_scores = np.abs((data - data.mean()) / data.std())
return z_scores > threshold
# 标记异常值
df['is_outlier'] = detect_outliers_zscore(df['temperature'])
# 查看异常值
print(df[df['is_outlier'] == True])
三、数据标准化:让不同量纲的数据“平起平坐”
数据标准化,这个我得多说两句。很多初学者容易忽略这一步。你想想看,如果温度是0-100度,压力是0-1000帕,这两个量纲完全不同的数据放在一起做分析,压力会主导结果,温度几乎没影响。这不合理。
标准化的目的,就是把不同量纲的数据映射到同一个尺度上。常用的方法有两种:
- Min-Max标准化:把数据缩放到[0,1]区间。公式是 (x - min) / (max - min)。适合数据分布比较均匀的情况。
- Z-score标准化:把数据转换成均值为0、标准差为1的分布。公式是 (x - mean) / std。适合数据存在异常值的情况。
我个人习惯,如果后续要用机器学习模型,优先用Z-score。如果只是做可视化或者简单对比,Min-Max更方便。
from sklearn.preprocessing import MinMaxScaler, StandardScaler
# Min-Max标准化
scaler_minmax = MinMaxScaler()
df['temp_scaled'] = scaler_minmax.fit_transform(df[['temperature']])
# Z-score标准化
scaler_zscore = StandardScaler()
df['pressure_scaled'] = scaler_zscore.fit_transform(df[['pressure']])
四、时间戳对齐:让所有数据“步调一致”
时间戳对齐,这是数据回放里最容易被忽视、但也是最容易出问题的一环。为什么?因为不同数据源的时间戳精度、采样频率、时区可能都不一样。
我记得有一次做多传感器融合回放,一个传感器每100毫秒采一次样,另一个每200毫秒采一次样。如果不做时间戳对齐,回放出来的轨迹就是错位的,位置和速度对不上。
时间戳对齐的核心思路:
- 统一时间基准:把所有时间戳转换成同一个时区,推荐用UTC。
- 重采样:把不同频率的数据重采样到同一个时间轴上。比如把100ms和200ms的数据都重采样到100ms。
- 插值对齐:对于非对齐的时间点,用插值法估算出该时刻的值。
避坑指南:我曾经因为时区问题,导致回放结果差了8个小时。后来我强制要求所有数据源在入库前先转成UTC时间戳,再也不用本地时间。
import pandas as pd
# 假设有两个数据源
df_sensor1 = pd.read_csv('sensor1.csv', parse_dates=['timestamp'])
df_sensor2 = pd.read_csv('sensor2.csv', parse_dates=['timestamp'])
# 设置时间戳为索引
df_sensor1.set_index('timestamp', inplace=True)
df_sensor2.set_index('timestamp', inplace=True)
# 重采样到100ms间隔
df_sensor1_resampled = df_sensor1.resample('100ms').interpolate()
df_sensor2_resampled = df_sensor2.resample('100ms').interpolate()
# 合并对齐后的数据
df_aligned = pd.concat([df_sensor1_resampled, df_sensor2_resampled], axis=1)
知识体系总览
下面这张图,是我自己梳理的数据清洗与预处理知识体系。你可以把它当作一个检查清单,每次做数据回放前,对照着过一遍。
好了,这一章的内容就到这里。数据清洗和预处理,说白了就是给数据“洗澡”。洗得干净,后面的回放才能顺畅。洗不干净,后面全是坑。
记住我一句话:数据清洗花的时间,永远值得。
本章小结:
- 缺失值处理:先看缺失比例,再选删除、填充或插值
- 异常值检测:3σ、箱线图、领域知识,三种方法结合用
- 数据标准化:Min-Max或Z-score,根据场景选
- 时间戳对齐:统一时区、重采样、插值,三步走
可可精品资料库