4. 数据频率对齐:日频、周频、月频、季频数据的对齐与重采样技术

做宏观择时模型,最头疼的事情是什么?

我个人觉得,不是策略逻辑设计,也不是参数调优。而是——数据频率对不齐。

你想想看,GDP数据一个季度才出一回,CPI每个月公布一次,而股市行情是每天在跳。把这些数据揉到一起,就像把大象、马、兔子关进同一个笼子,你得先让它们步调一致。

我在搭建第一个宏观择时模型时,就栽过这个跟头。当时直接把日频的股指数据和季频的GDP数据丢进回归模型,结果跑出来一堆伪回归。嗯,后来才明白,频率不对齐,模型就是空中楼阁。

4.1 为什么必须做频率对齐?

说白了,不同频率的数据,背后是不同节奏的经济活动。

  • 日频数据:市场情绪、资金流动、短期波动。噪音多,信号弱。
  • 周频数据:开工率、库存变化、短期信贷。比日频稳定一些。
  • 月频数据:CPI、PMI、社融、工业增加值。宏观择时的核心信号源。
  • 季频数据:GDP、上市公司财报、资本形成总额。最慢,但最扎实。

如果你不做对齐,模型会「看到」日频数据每天更新,而季频数据三个月才动一次。结果就是,模型过度拟合了日频的噪音,忽略了季频的趋势。

核心原则:低频数据决定方向,高频数据决定节奏。对齐的目的是让低频数据「指导」高频数据,而不是让高频数据「淹没」低频数据。

4.2 对齐策略:降频 vs 升频

对齐有两种思路。我习惯先问自己一个问题:我的模型最终要预测什么?

如果预测的是季度GDP增速,那就把所有数据都降频到季频。如果预测的是明天股市涨跌,那就得把低频数据升频到日频。

4.2.1 降频(Downsampling)

把高频数据聚合到低频。常用的聚合方式:

原始频率 目标频率 常用聚合方法 适用场景
日频 月频 月末取值、月均值、月累计值 股指、利率、汇率
日频 季频 季末取值、季度均值 市场波动率、信用利差
月频 季频 季末取值、季度均值 CPI、PMI、社融

我的经验:对于宏观择时,我更喜欢用「月末取值」或「季末取值」。因为宏观数据发布有滞后性,用月末值更贴近实际可用的信息集。用均值会引入未来信息,造成前视偏差。

4.2.2 升频(Upsampling)

把低频数据填充到高频。常用的方法:

  • 向前填充(ffill):用上一个已知值填充缺失值。最常用,也最安全。
  • 向后填充(bfill):用下一个已知值填充。容易引入未来信息,慎用。
  • 线性插值:假设数据在两点之间线性变化。适合趋势明显的序列。
  • 样条插值:更平滑,但容易过拟合。我一般不用。

我曾经踩过的坑:用线性插值把季度GDP升频到日频。结果模型在季度中间「看到」了GDP在平滑增长,但实际上GDP数据只在季度末才公布。模型提前知道了「未来」的信息,回测表现好得离谱,实盘一塌糊涂。

记住:升频时只能用过去已知的信息。向前填充是最保守、最诚实的方法。

4.3 重采样技术实战

下面是我在项目中常用的重采样代码框架。以Python的pandas为例。

import pandas as pd
import numpy as np

# 假设我们有三个数据源
# 1. 日频的沪深300指数
# 2. 月频的CPI数据
# 3. 季频的GDP数据

# 读取数据(假设已加载)
# hs300_daily: 日期索引, 收盘价
# cpi_monthly: 日期索引, CPI同比
# gdp_quarterly: 日期索引, GDP同比

# 第一步:统一索引为日期格式
hs300_daily.index = pd.to_datetime(hs300_daily.index)
cpi_monthly.index = pd.to_datetime(cpi_monthly.index)
gdp_quarterly.index = pd.to_datetime(gdp_quarterly.index)

# 第二步:降频——把日频指数转为月频
# 方法:月末最后一个交易日收盘价
hs300_monthly = hs300_daily.resample('M').last()

# 方法:月内平均收盘价(更平滑,但会引入未来信息)
hs300_monthly_avg = hs300_daily.resample('M').mean()

# 第三步:升频——把季频GDP填充到月频
# 方法:向前填充
gdp_monthly = gdp_quarterly.resample('M').ffill()

# 第四步:对齐所有数据到同一个频率(月频)
aligned_data = pd.DataFrame({
    'hs300': hs300_monthly['close'],
    'cpi': cpi_monthly['cpi_yoy'],
    'gdp': gdp_monthly['gdp_yoy']
})

# 删除缺失值
aligned_data = aligned_data.dropna()

print(aligned_data.head())

关键点:对齐后的数据,每一行代表同一个时间点的信息。这个时间点,应该是所有数据都「已知」的时间点。比如GDP在季度末之后一个月才公布,那你的对齐时间点应该再往后推一个月。

4.4 频率对齐的避坑指南

我总结了几个实战中容易出问题的地方:

  1. 发布时滞:宏观数据不是实时公布的。GDP滞后1-2个月,CPI滞后1个月。对齐时,数据的时间戳应该是「可获取时间」,而不是「数据所属时间」。
  2. 交易日历:A股有交易日,宏观数据按自然月。对齐时要注意跳过非交易日。用pandas的resample配合bfillffill可以处理。
  3. 数据修订:宏观数据经常修订。比如GDP初值、修正值、终值。对齐时要用「当时可获取的版本」,而不是修订后的版本。否则又是前视偏差。
  4. 频率不一致的统计量:日频的波动率和月频的波动率不是一个量级。对齐后,要检查统计特征是否合理。

一个小技巧:我习惯在数据对齐后,画一张时间序列图。把不同频率的数据叠在一起看。如果某个数据在图中出现「阶梯状」跳跃,说明升频方式可能有问题。如果某个数据出现「锯齿状」波动,说明降频时可能混入了噪音。

4.5 知识体系总览

下面这张图,是我自己整理的数据频率对齐核心逻辑。你可以把它当作一个检查清单。

数据频率对齐核心逻辑 日频数据 股指、利率、汇率 月频数据 CPI、PMI、社融 季频数据 GDP、财报 对齐策略选择 降频:高频→低频(聚合) 升频:低频→高频(填充) 降频方法 • 月末/季末取值 • 月内/季内均值 • 累计值(如社融) • 波动率聚合 升频方法 • 向前填充(ffill) • 向后填充(bfill)⚠️ • 线性插值 ⚠️ • 样条插值 ❌ 对齐后的统一频率数据集

这张图把整个流程串起来了。从左到右,先识别数据频率,再选择对齐策略,最后输出统一频率的数据集。每次做数据对齐前,我都会过一遍这个流程,确保没有遗漏。

最后说一句:数据频率对齐看起来是个技术活,其实是个「认知活」。你选择什么样的对齐方式,本质上是在表达你对经济数据发布机制的理解。对齐做得越细致,模型就越贴近真实世界的决策环境。

专注资料整理