数据预处理与对齐:不同频率数据的清洗、重采样、时间戳对齐与缺失值处理
做量化研究的朋友都知道,高频数据和低频数据就像两个不同节奏的舞者。一个每秒跳好几步,一个每天才动一下。想让它们配合好,预处理这关必须过。我个人习惯把这一步叫做「数据对齐的炼狱」,因为踩过的坑实在太多了。
核心痛点:高频数据(如 tick 级、分钟级)与低频数据(如日频、周频)天然存在采样频率不一致、时间戳格式不同、缺失值模式迥异等问题。不处理好这些,后续的因子融合就是空中楼阁。
一、数据清洗:先别急着对齐,把脏数据筛掉
我刚开始做高频因子那会儿,拿到数据就直接重采样,结果发现收益率曲线像心电图一样乱跳。后来才明白,清洗是第一步,也是最容易被忽视的一步。
1.1 高频数据常见脏数据
- 零值或负值的成交量/成交额:交易所数据偶尔会出这种幺蛾子。我建议直接剔除,或者用前向填充。
- 价格异常跳变:比如某只股票突然从10元跳到100元又跳回来。这通常是数据录入错误。我曾经用3倍标准差法过滤,效果还行。
- 非交易时段数据:集合竞价、午休时间的数据要不要保留?我个人习惯是只保留连续竞价时段(9:30-11:30, 13:00-15:00)。
1.2 低频数据常见脏数据
- 停牌日数据:停牌期间的价格是无效的。我一般用前复权价格,或者直接标记为NaN。
- 财报数据中的异常值:比如营收突然暴增100倍,大概率是并购或数据错误。需要结合公告判断。
我的小技巧:清洗时先做「肉眼检查」。随机抽几只股票,把原始数据画出来看看。很多异常是肉眼可见的,比任何算法都靠谱。
二、重采样:把不同频率的数据拉到同一个节奏上
重采样说白了就是「降频」或「升频」。高频转低频容易,低频转高频就有点技术活了。
2.1 高频转低频(降采样)
这是最常见的操作。比如把分钟级数据转成日频。关键是要选对聚合函数:
import pandas as pd
# 假设 df 是分钟级数据,index 是时间戳
# 转成日频:价格用最后一条,成交量用总和
daily_df = df.resample('D').agg({
'close': 'last',
'volume': 'sum',
'open': 'first',
'high': 'max',
'low': 'min'
})
嗯,这里要注意:不要所有字段都用同一个聚合函数。我见过有人把成交量也取平均值,那结果就完全失真了。
2.2 低频转高频(升采样)
低频数据(比如日频因子)要跟高频数据对齐,就得升采样。常用的方法:
- 前向填充(ffill):用上一个有效值填充。适合基本面因子,比如市值、市盈率。
- 线性插值:适合连续变化的指标,比如指数点位。
- 填充0或NaN:适合事件型因子,比如分红公告日。
避坑指南:我曾经在升采样时用了「后向填充」,结果把未来的数据泄露到了过去。回测收益高得离谱,实盘直接打脸。记住:永远不要用未来信息填充过去。
三、时间戳对齐:让高频和低频数据在同一个时间点上握手
时间戳对齐是数据预处理中最头疼的部分。为什么?因为不同数据源的时间戳格式五花八门。
3.1 统一时间戳格式
我建议把所有时间戳统一成 UTC 时间,或者至少统一成交易所本地时间(比如中国就用北京时间)。
# 统一转为 datetime 类型,并设置时区
df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True)
df['timestamp'] = df['timestamp'].dt.tz_convert('Asia/Shanghai')
3.2 对齐到标准时间网格
高频数据通常是不规则采样的(比如每笔成交时间不同)。我们需要把它对齐到固定的时间网格上。
| 原始时间戳 | 对齐到分钟网格 | 对齐到5分钟网格 |
|---|---|---|
| 09:30:15 | 09:30:00 | 09:30:00 |
| 09:30:47 | 09:30:00 | 09:30:00 |
| 09:31:02 | 09:31:00 | 09:35:00 |
你想想看,如果不对齐,两个数据集的索引根本对不上,后续的合并操作就会出大问题。
四、缺失值处理:别让NaN毁了你的因子
缺失值处理是门艺术。处理得太粗暴,会引入偏差;处理得太精细,又可能过拟合。
4.1 高频数据的缺失值
高频数据缺失通常有两种情况:
- 短暂缺失(几秒到几分钟):可能是网络延迟或数据推送问题。我一般用前向填充,最多填充5分钟。
- 长时间缺失(超过30分钟):可能是停牌或数据源故障。这时候我会标记为NaN,后续模型自己处理。
4.2 低频数据的缺失值
低频数据缺失更常见,比如:
- 财务数据:季报发布有滞后,最新数据可能缺失。我习惯用「最近一期有效值」填充。
- 因子值:某些因子在某些股票上算不出来(比如流动性因子对停牌股)。这时候我会用行业均值填充。
我的经验:不要一股脑全填充。先看看缺失比例。如果某只股票缺失超过30%,我建议直接剔除这只股票。硬填进去只会污染模型。
五、整体流程框架
说了这么多,我画个图帮你理清思路。这是我自己做数据预处理的标准流程:
六、实战中的几个坑
最后分享几个我踩过的坑,希望能帮你省点时间:
- 不要忽略节假日:不同市场的节假日不同。A股春节休市,美股可没有。对齐时要用交易日历,别用自然日。
- 小心复权数据:前复权和后复权对高频数据影响很大。我建议用后复权做计算,最后再转回前复权展示。
- 内存管理:高频数据量很大,分钟级数据一年就有几十万行。我习惯用 parquet 格式存储,比 CSV 快10倍。
- 验证对齐结果:对齐后一定要做交叉验证。比如检查高频数据的日收盘价是否跟低频日数据一致。不一致就是对齐出了问题。
总结一句话:数据预处理花的时间,往往比建模还多。但这一步做扎实了,后面的工作会顺畅很多。别嫌麻烦,这是量化研究的必修课。