3、时序数据预处理:缺失值处理、异常值检测、重采样、平滑、差分、归一化与标准化,以及训练/验证/测试集划分的时序特殊性
时序数据预处理是时间序列建模与MLOps落地的第一道质量闸门。与静态表格数据不同,时序数据具有时间顺序依赖、自相关性、趋势与季节性成分,以及非平稳性等特征。若预处理不当,后续的特征工程、模型训练与在线推理都会受到系统性污染。本章围绕七个核心环节展开:缺失值处理、异常值检测、重采样、平滑、差分、归一化与标准化,以及训练/验证/测试集划分的时序特殊性。每个环节都需结合业务语义与时间结构进行判断,而非机械套用通用数据清洗方法。
3.1 缺失值处理:时间上下文优先于统计填充
核心原理:时序数据的缺失值并非随机出现,往往由传感器断连、网络丢包、业务系统故障或人工录入遗漏造成。缺失模式可分为完全随机缺失(MCAR)、随机缺失(MAR)和非随机缺失(MNAR)。在时序场景中,MNAR尤其需要警惕——例如温度传感器在高温时段更容易失效,若直接删除或简单填充,会引入系统性偏差。处理缺失值的核心原则是:优先利用时间邻域信息,其次利用全局统计信息,最后才考虑删除。
判断方法与操作流程:首先统计缺失比例与连续缺失长度。若缺失比例低于5%且为孤立点,可采用前向填充(ffill)或后向填充(bfill);若存在连续缺失,线性插值或时间加权插值更合适;对于周期性强的序列(如电力负荷、交通流量),可结合同一周期(如昨日同时刻、上周同一天)的数据进行填充。具体流程如下:
- 绘制缺失值时间分布图,识别缺失聚集区间;
- 计算缺失比例与最大连续缺失长度;
- 根据业务语义选择填充策略:短缺失用插值,长缺失用周期匹配或模型预测;
- 填充后对比填充前后序列的均值、方差与自相关函数(ACF),确认未引入畸变。
| 缺失模式 | 推荐方法 | 适用场景 | 风险提示 |
|---|---|---|---|
| 孤立缺失(1-2个点) | 前向/后向填充、线性插值 | 传感器瞬时断连 | 若序列波动剧烈,填充值可能偏离真实值 |
| 连续缺失(3-10个点) | 样条插值、时间加权插值 | 网络丢包、短暂停机 | 样条插值可能过冲,需检查边界 |
| 长区间缺失(>10个点) | 周期匹配、回归预测、多重插补 | 设备长时间离线 | 模型预测需基于完整特征,避免引入偏差 |
| 非随机缺失 | 单独标记缺失指示变量 | 故障与缺失相关 | 直接填充会掩盖故障信号 |
3.2 异常值检测:区分噪声、离群点与事件信号
核心原理:时序异常值可分为三类:加性异常(单点突变,如传感器毛刺)、水平偏移(均值突变,如设备校准)、季节性异常(在特定周期内偏离正常模式,如节假日效应)。检测方法需与异常类型匹配。静态阈值(如3σ)在趋势和季节性存在时容易误判——例如用电量在夏季自然升高,会被误判为异常。因此,时序异常检测应基于残差分析:先分解出趋势和季节性成分,再对残差进行统计检验。
判断方法与操作流程:推荐采用“先分解、后检测”的流程:
- 使用STL(Seasonal-Trend decomposition using Loess)或移动平均分解序列,得到趋势、季节和残差分量;
- 对残差计算滑动窗口内的均值和标准差,设置动态阈值(如±3倍滑动标准差);
- 标记超过阈值的点为候选异常;
- 结合业务规则复核:例如交易量突增可能是营销活动而非异常,需人工确认。
对于高维或复杂模式,可使用隔离森林(Isolation Forest)或DBSCAN,但需注意这些方法不直接利用时间顺序,建议将滞后特征(lag features)作为输入。
某工厂对旋转机械安装振动传感器,采样频率1Hz,连续采集30天数据。初始现象:第15天出现连续2小时的振动幅值升高,但未超过设备报警阈值。若仅用全局3σ检测,该段数据不会被标记,因为整体方差较大。
分析过程:使用STL分解后,发现该时段残差超过滑动窗口(窗口=1小时)的5倍标准差。进一步检查日志,发现该时段冷却泵切换导致共振。操作步骤:① 将残差检测阈值设为动态(滑动窗口均值±4倍滑动标准差);② 对异常段前后各30分钟数据做对比,确认无传感器故障;③ 将异常段标记为“事件信号”而非“噪声”,保留在训练集中但增加事件标签。
结果对比:动态阈值方法识别出12个异常段,其中10个对应真实设备事件,2个为误报。若使用全局阈值,仅识别出3个极端峰值。复盘经验:异常检测必须结合业务上下文,区分“需要剔除的噪声”和“需要保留的事件信号”。
3.3 重采样:统一时间粒度与对齐业务周期
核心原理:多源时序数据往往具有不同采样频率——例如传感器每100ms采集一次,业务数据库每5分钟记录一次,外部天气数据每小时更新一次。建模前必须统一时间粒度。重采样分为降采样(高频转低频,如秒级转分钟级)和升采样(低频转高频,如日级转小时级)。降采样通常使用聚合函数(均值、求和、最大值、最小值),升采样则使用插值或填充。选择聚合函数需考虑业务语义:流量用求和,温度用均值,峰值用最大值。
操作流程与注意事项:
- 确定目标频率:根据模型预测周期和业务决策频率确定,例如预测未来1小时流量,则目标频率为5分钟或15分钟;
- 处理时间戳对齐:使用pandas的
resample()时,需明确标签规则(左闭右闭或左开右闭); - 降采样时注意聚合窗口的边界效应——例如将日数据聚合成周数据时,周一至周日应作为一个完整窗口;
- 升采样时避免引入未来信息:只能使用当前及之前的数据进行插值,不能使用未来值。
# 降采样示例:将秒级数据聚合成分钟级均值
df_min = df_sec.resample('1min', label='right', closed='right').mean()
# 升采样示例:将小时级数据插值为15分钟级(仅使用历史值)
df_15min = df_hour.resample('15min').ffill() # 前向填充,不引入未来信息
3.4 平滑:去除高频噪声但保留转折点
核心原理:平滑的目的是降低随机噪声对模型训练的干扰,但过度平滑会抹掉重要的转折点和突变信号。常用的平滑方法包括:简单移动平均(SMA)、指数加权移动平均(EWMA)和Savitzky-Golay滤波。SMA对窗口内所有点等权,滞后明显;EWMA对近期点赋予更高权重,滞后较小;Savitzky-Golay通过局部多项式拟合,在去噪的同时较好地保留峰值形状。
参数选择与验证:窗口大小或衰减因子是关键参数。窗口过小,去噪效果差;窗口过大,会延迟信号变化。建议通过交叉验证选择参数:在训练集上尝试不同窗口,比较平滑后序列的预测误差。对于趋势明显的序列,可先差分再平滑,避免平滑引入趋势滞后。
3.5 差分:实现平稳化与去除趋势/季节性
核心原理:许多时序模型(如ARIMA、VAR)要求序列平稳——即均值和方差不随时间变化。差分通过计算相邻时间点的差值来去除趋势和季节性。一阶差分去除线性趋势,二阶差分去除二次趋势;季节性差分(如对月度数据做12阶差分)去除周期性。判断平稳性的常用工具是ADF检验(Augmented Dickey-Fuller test)和KPSS检验。ADF的原假设是序列非平稳,若p值小于0.05则拒绝原假设,认为序列平稳。
操作流程:
- 绘制原始序列图,观察趋势和季节性;
- 进行ADF检验,若p值>0.05,则进行一阶差分;
- 再次检验,若仍不平稳,则进行季节性差分或二阶差分;
- 差分后检查ACF/PACF图,确认自相关结构是否简化。
需要注意的是,差分会丢失信息,且预测时需要将差分结果还原(累积求和)。在MLOps中,差分操作应封装为可逆的转换函数,并保存差分阶数参数。
3.6 归一化与标准化:防止未来信息泄漏
核心原理:归一化(Min-Max Scaling)将数据缩放到[0,1]区间,适用于有界数据或神经网络输入;标准化(Z-Score Normalization)将数据转换为均值为0、标准差为1的分布,适用于存在离群值或需要保留分布形状的场景。对于时序数据,关键问题是缩放参数的拟合时机。若在完整数据集上计算均值和标准差,再划分训练/测试集,则测试集的信息已泄漏到训练过程中。
正确做法:
- 仅在训练集上计算均值和标准差(或最小值和最大值);
- 将训练集的缩放参数保存为工件(artifact),用于验证集、测试集和在线推理;
- 对于滚动预测场景,应使用扩展窗口或滑动窗口重新计算缩放参数,但需确保每次只使用当前时间点之前的数据。
# 正确做法:仅用训练集拟合scaler
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
train_scaled = scaler.fit_transform(train.reshape(-1, 1))
test_scaled = scaler.transform(test.reshape(-1, 1)) # 使用训练集的参数
3.7 训练/验证/测试集划分:时间顺序不可打乱
核心原理:时序数据的划分必须严格遵循时间顺序,不能使用随机打乱(K-Fold随机划分会破坏时间依赖,导致未来信息泄漏)。常用的划分方式有三种:简单时间切分(前70%训练,后30%测试)、滚动预测评估(Walk-Forward Validation)和时间序列交叉验证(如TimeSeriesSplit)。对于超参数调优,验证集应位于训练集之后、测试集之前,且验证集的时间范围不应与测试集重叠。
操作流程与案例:
| 划分方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 简单时间切分 | 数据量充足,分布稳定 | 简单直观 | 若分布漂移,测试误差可能偏大 |
| Walk-Forward | 在线预测、滚动更新 | 模拟真实推理环境 | 计算开销大 |
| TimeSeriesSplit | 小样本、需要多次评估 | 充分利用数据 | 训练集大小递增,早期训练不充分 |
某电商平台需预测未来7天每日销量,历史数据为2年日粒度数据。初始方案:随机划分70%训练、30%测试,模型在测试集上RMSE为1200。但上线后实际RMSE达到2800。
分析:随机划分导致训练集中包含测试集时间段的节假日信息,模型“记住”了特定日期的销量模式。修正方案:按时间顺序划分——前18个月训练,接下来3个月验证,最后3个月测试。同时,在验证集上调整模型超参数(如LSTM的lookback窗口),确保验证集时间在训练集之后。
结果:修正后测试RMSE为1900,虽高于随机划分的1200,但更接近真实上线表现。复盘经验:时序划分必须模拟真实预测场景——训练数据只能是预测时刻之前的数据。此外,对于季节性明显的业务,训练集应至少包含一个完整年度周期。
总结复盘:时序数据预处理不是一次性操作,而是贯穿模型开发与部署全生命周期的持续工程。缺失值处理需考虑缺失机制与时间邻域;异常值检测需区分噪声与事件信号;重采样需统一粒度并避免未来信息;平滑需平衡去噪与信号保真;差分需验证平稳性并保证可逆;归一化需防止缩放参数泄漏;数据划分必须严格遵循时间顺序。在MLOps实践中,建议将上述所有预处理步骤封装为独立的、可版本化的转换组件,并在训练与推理流水线中保持一致,确保数据分布的一致性。