3、数据预处理实战:缺失值处理、异常值检测、时间戳对齐与重采样

数据预处理这件事,我做了快十年了。说实话,很多刚入行的朋友总觉得建模才是核心,预处理不过是「洗菜」的杂活。但我在项目中吃过太多亏了——有一次辛辛苦苦调了三天的模型,结果上线后预测值全飘了,最后发现是训练数据里有一列时间戳没对齐。嗯,从那以后,我再也不敢小看预处理这一步。

今天这一章,咱们就聊聊滚动预测场景下,数据预处理必须搞定的四个硬骨头:缺失值、异常值、时间戳对齐、重采样。你想想看,如果数据本身就有问题,再牛的模型也是白搭。

3.1 缺失值处理:别让「空」毁了你的时序

时序数据里的缺失值,跟普通表格数据不一样。普通数据缺失了,你可以直接删掉一行。但时序数据不行——你删掉一个时间点,整个时间序列就断了。我个人习惯的做法是:先搞清楚缺失的原因,再决定怎么补。

核心原则: 时序缺失值处理,优先考虑时间相关性,而不是统计相关性。

3.1.1 常见缺失模式

  • 随机缺失: 传感器偶尔没采到,占比小,影响不大
  • 连续缺失: 设备宕机、网络中断,可能缺失一大段
  • 周期性缺失: 比如每天凌晨系统维护,数据固定缺失

我在项目中遇到过一种情况:某个传感器每到整点就会丢数据,一开始以为是随机缺失,后来发现是采集程序的定时器有bug。这种周期性缺失,你要是用均值填充,那预测结果肯定跑偏。

3.1.2 填充方法选择

缺失类型 推荐方法 适用场景
少量随机缺失(<5%) 前向填充(ffill) 变化缓慢的指标,如温度、湿度
中等缺失(5%-20%) 线性插值 趋势明显的序列,如销量、流量
大量缺失(>20%) 时间序列分解+预测填充 有周期性规律的数据
连续缺失块 分段处理,避免跨段填充 设备宕机导致的数据断层
# 我个人最常用的填充方式
import pandas as pd
import numpy as np

# 前向填充:适合变化缓慢的指标
df['value'].fillna(method='ffill', inplace=True)

# 线性插值:适合有趋势的数据
df['value'].interpolate(method='linear', inplace=True)

# 时间加权插值:考虑时间间隔不均匀的情况
df['value'].interpolate(method='time', inplace=True)
小技巧: 填充前先看一眼缺失的分布。如果缺失集中在某个时间段,建议单独处理,不要全局统一填充。

3.2 异常值检测:揪出那些「捣乱」的数据点

异常值在滚动预测里特别要命。为什么?因为滚动预测依赖历史数据来预测未来,一个异常值会污染后续所有预测窗口。我曾经接手过一个项目,模型预测的准确率一直上不去,查了三天才发现是训练数据里混了几个传感器故障产生的「毛刺」。

3.2.1 时序异常检测三板斧

  1. 统计方法: Z-score、IQR(四分位距法)——简单粗暴,适合快速筛查
  2. 移动窗口法: 滚动均值±3倍滚动标准差——适合局部异常检测
  3. 季节性分解法: STL分解后检测残差中的异常——适合有周期性的数据
# 移动窗口异常检测——我项目里最常用的方法
def detect_anomalies(series, window=24, threshold=3):
    rolling_mean = series.rolling(window=window).mean()
    rolling_std = series.rolling(window=window).std()
    
    # 计算上下界
    upper_bound = rolling_mean + threshold * rolling_std
    lower_bound = rolling_mean - threshold * rolling_std
    
    # 标记异常
    anomalies = (series > upper_bound) | (series < lower_bound)
    return anomalies

# 使用示例
anomaly_mask = detect_anomalies(df['value'], window=12, threshold=3)
df['is_anomaly'] = anomaly_mask
注意: 窗口大小很关键。窗口太小,会把正常波动误判为异常;窗口太大,又可能漏掉真正的异常。我一般先试24小时窗口,再根据业务场景调整。

3.2.2 异常值处理策略

检测到异常后,怎么处理?我的经验是:不要直接删除。时序数据里,删除一个点会影响时间对齐。我建议的做法是:

  • 业务确认: 如果是传感器故障,标记后填充;如果是真实事件(比如促销导致的销量暴增),保留并单独建模
  • 替换为边界值: 用上下界替换异常值,而不是直接删除
  • 分段处理: 如果异常值集中在某个时间段,考虑把这段数据单独拿出来分析

3.3 时间戳对齐:把「乱糟糟」的时间线捋直

时间戳对齐,说白了就是让所有数据在同一个时间刻度上「对齐」。我在做多传感器融合项目时,遇到过最头疼的问题就是:A传感器每5秒采一次,B传感器每10秒采一次,C传感器还不定时上报。你想想看,这种数据直接丢进模型,模型根本学不到东西。

3.3.1 对齐的两种思路

对齐方式 做法 适用场景
左对齐 以最早的时间戳为基准,向后填充 实时预测场景,需要尽快拿到结果
右对齐 以最晚的时间戳为基准,向前填充 离线分析场景,追求数据完整性
最近邻对齐 找到时间上最接近的点进行匹配 采样频率差异较大的情况
# 时间戳对齐实战
# 假设有两个时间序列,频率不同
ts1 = pd.Series([1, 2, 3], index=pd.to_datetime(['2024-01-01 00:00:00', 
                                                   '2024-01-01 00:05:00',
                                                   '2024-01-01 00:10:00']))
ts2 = pd.Series([10, 20, 30], index=pd.to_datetime(['2024-01-01 00:02:00',
                                                     '2024-01-01 00:07:00',
                                                     '2024-01-01 00:12:00']))

# 统一重采样到5分钟频率,然后合并
ts1_resampled = ts1.resample('5T').ffill()
ts2_resampled = ts2.resample('5T').ffill()

# 合并对齐后的数据
aligned_df = pd.concat([ts1_resampled, ts2_resampled], axis=1)
aligned_df.columns = ['sensor_a', 'sensor_b']
避坑指南: 我曾经犯过一个错误——直接用merge函数按时间戳精确匹配,结果因为两个传感器的时间戳差了0.1秒,导致大量数据没匹配上。后来改用resample统一频率,问题就解决了。

3.4 重采样:把「不规则」变成「规则」

重采样,就是把原始数据从一种时间频率转换到另一种。在滚动预测里,这一步几乎是必须的。因为大多数预测模型都要求输入数据是等间隔的。

3.4.1 降采样 vs 升采样

  • 降采样(高频→低频): 比如从1分钟频率降到1小时频率。聚合方式有均值、求和、最大值等
  • 升采样(低频→高频): 比如从1小时频率升到15分钟频率。需要填充或插值
# 重采样实战
# 降采样:从分钟级到小时级,用均值聚合
hourly_data = df.resample('1H').mean()

# 升采样:从小时级到15分钟级,用线性插值
fifteen_min_data = hourly_data.resample('15T').interpolate(method='linear')

# 自定义聚合:比如取每个小时的最大值
hourly_max = df.resample('1H').agg({'value': 'max', 'sensor_id': 'first'})

3.4.2 重采样频率选择

频率怎么选?我的经验是:

  • 看预测步长: 如果你要预测未来24小时,那重采样到小时级就够了,没必要用分钟级
  • 看数据量: 频率太高,数据量太大,训练慢;频率太低,信息损失多
  • 看业务需求: 有些场景需要秒级响应,那就得保留高频数据
重要提醒: 重采样时一定要注意时间边界。比如从分钟级重采样到小时级,默认是按整点对齐的。如果你的数据是从10:30开始的,那第一个小时窗口可能只有30分钟的数据,均值会偏小。

3.5 本章知识体系总览

下面这张图,是我自己梳理的数据预处理流程。每次做项目前,我都会对照着走一遍,确保没有遗漏。

滚动预测数据预处理流程 原始时序数据 步骤1:缺失值处理 步骤2:异常值检测 步骤3:时间戳对齐 步骤4:重采样(统一频率) 关键要点 • 先看缺失模式 • 异常值不要直接删 • 对齐用resample • 频率匹配预测步长 • 注意时间边界 • 分段处理连续缺失 • 保留业务上下文 • 验证对齐结果 • 记录预处理日志

嗯,以上就是数据预处理的四个核心步骤。每一步看起来都不难,但真正做起来,坑还是挺多的。我个人建议,每次做完预处理后,都花10分钟检查一下结果——画个图看看时间序列是否连续,统计一下缺失值比例,确认一下时间戳是否对齐。这些检查花不了多少时间,但能帮你省下后面调模型的好几天时间。

一句话总结: 数据预处理不是「洗菜」,而是「地基」。地基没打好,楼盖得再高也得塌。

公众号:蓝海资料掘金营,微信deep3321