4. 数据预处理实战
在金融时序预测项目中,原始数据往往来自多个渠道:行情接口、交易所文件、第三方数据库、宏观指标发布页。它们的时间戳格式、交易时段、频率和缺失模式各不相同。如果直接把原始数据喂给模型,模型学到的可能不是市场规律,而是数据采集过程中的噪声。数据预处理不是“清洗一下”这么简单,它决定了后续特征工程和模型训练的上限。本节围绕缺失值处理、异常值检测、时间对齐、重采样与频率转换五个核心环节,给出可落地的工程方法。
一、核心原理:金融时序的四种“脏数据”
金融时序的脏数据通常表现为四类。第一类是缺失值,包括非交易时段缺失、停牌缺失、接口丢包和字段未披露。第二类是异常值,如价格瞬时跳变、成交量错误放大、涨跌幅超出制度限制。第三类是时间不对齐,例如日频因子在周末有值而行情没有,或不同市场因时区差异导致同一“日期”实际错位。第四类是频率不一致,分钟线、日线、周线和月度宏观数据混用。
处理这四类问题的基本原则是:先理解业务时间语义,再做数学变换。金融时间不是均匀的连续轴,而是由交易日历、交易时段和结算规则共同定义的离散事件序列。忽略这一点,任何插值和对齐都可能引入前视偏差。
二、方法流程:从原始表到建模宽表
一个稳健的预处理流水线通常按以下顺序执行:
- 统一时间索引:将所有数据的时间戳转换为带时区的标准时间,并映射到统一的交易日历。
- 缺失值诊断:统计缺失率、连续缺失长度和缺失发生的时间分布。
- 异常值检测:结合业务规则与统计方法标记可疑点。
- 对齐:以目标频率的时间轴为基准,将多源数据对齐到同一索引。
- 重采样与频率转换:按目标频率聚合或升采样,并明确每个字段的聚合函数。
- 输出建模宽表:保留原始值、处理后值和缺失/异常标记列。
下面是一个使用 pandas 的典型预处理骨架:
import pandas as pd
import numpy as np
# 1. 统一时间索引
df["timestamp"] = pd.to_datetime(df["timestamp"], utc=True)
df = df.set_index("timestamp").sort_index()
# 2. 缺失值诊断
missing_rate = df.isna().mean()
continuous_gap = df["close"].isna().astype(int).groupby(
(df["close"].notna()).cumsum()
).sum()
# 3. 异常值检测:基于滚动中位数绝对偏差
window = 20
median = df["close"].rolling(window).median()
mad = (df["close"] - median).abs().rolling(window).median()
df["is_outlier"] = (df["close"] - median).abs() > 5 * mad
# 4. 对齐到交易日历
trading_days = pd.date_range("2020-01-01", "2024-12-31", freq="B")
df = df.reindex(trading_days)
# 5. 重采样:分钟线转日线
daily = df.resample("1D").agg({
"open": "first",
"high": "max",
"low": "min",
"close": "last",
"volume": "sum"
})
三、案例场景:多源数据对齐与频率转换
假设我们要构建一个日频预测模型,输入包括:A股某股票的日行情、分钟级资金流、以及月度发布的宏观经济指标。三者的时间语义完全不同。日行情只在交易日有值;分钟资金流需要先聚合到日频;宏观指标通常在月初发布,但实际可用时间可能滞后一周。
正确的做法是:以交易日历为主轴,将分钟资金流按交易日聚合为日频;对宏观指标,使用发布日而非统计月份进行对齐,避免未来信息泄露。对于停牌日,行情字段保留缺失,但可以增加“是否停牌”的标记列,让模型自行学习。
| 数据类型 | 原始频率 | 目标频率 | 聚合/转换方式 | 注意事项 |
|---|---|---|---|---|
| 股票行情 | 分钟 | 日 | OHLC:first/max/min/last,成交量求和 | 停牌日不填补价格 |
| 资金流 | 分钟 | 日 | 净流入求和,大单占比取均值 | 注意交易时段过滤 |
| 宏观指标 | 月度 | 日 | 按发布日前向填充 | 禁止使用统计月份直接对齐 |
| 财务数据 | 季度 | 日 | 按公告日前向填充 | 区分报告期与公告期 |
mean() 对价格和成交量都不合适。价格用 OHLC 逻辑,成交量用求和,比率类字段用加权平均或最后值。
四、误区与复盘:预处理中最容易犯的错
误区一:用未来数据填补过去。例如用全样本均值填补缺失值,或用后向填充处理宏观数据。这会造成严重的前视偏差,模型在回测中表现优异,实盘却失效。
误区二:把停牌日当作缺失值填补。停牌期间没有交易,价格不应被插值。正确做法是保留缺失并增加停牌标记,或直接从训练样本中排除。
误区三:异常值一律删除。金融市场的极端行情往往包含重要信息。更稳妥的做法是:先标记,再在特征工程中增加“是否异常”的哑变量,或使用稳健缩放(如 RobustScaler)降低影响。
误区四:忽略时区与夏令时。跨市场数据对齐时,纽约、伦敦、东京的交易日和交易时段不同。必须统一到 UTC 或交易所本地时间,并处理夏令时切换。
数据预处理的质量直接决定了模型能否学到真实的市场结构。把缺失、异常、对齐和频率转换当作一个整体流水线来设计,而不是零散地调用几个函数,才能在后续的特征工程和模型训练中少走弯路。建议在每次预处理后保留完整的处理日志和标记列,这样当模型表现异常时,可以快速回溯到数据层面的原因。