3. 数据获取与预处理:宏观经济数据源与清洗对齐

做宏观因子归因,说白了就是跟数据打交道。我入行那会儿,最头疼的不是模型怎么搭,而是数据从哪来、怎么洗干净。你想想看,模型再漂亮,数据是脏的,结果就是一堆垃圾。

这一章,咱们就聊聊宏观经济数据的获取和预处理。我会把常用的数据源、清洗技巧、频率转换这些硬骨头,一个一个啃下来。

3.1 宏观经济数据源:Wind、CEIC、FRED

宏观数据源,我主要用三个:Wind、CEIC、FRED。各有各的脾气,也各有各的拿手好戏。

3.1.1 Wind(万得)

Wind 是国内做量化绕不开的坎。我个人习惯用它来拉A股相关的宏观数据,比如CPI、PPI、工业增加值、社融数据。它的API接口挺全的,Python 和 R 都能直接调。

举个例子,用 Python 从 Wind 拉数据:

from WindPy import w
w.start()

# 拉取CPI月度数据
cpi_data = w.edb("M0001396", "2010-01-01", "2024-12-31", "Fill=Previous")
print(cpi_data.Data)

这里有个坑:Wind 的代码体系比较乱,同一个指标可能有多个代码。我建议你建一个自己的代码映射表,省得每次都要查。

3.1.2 CEIC

CEIC 的优势在于全球宏观数据覆盖广。我做跨境策略时,经常用它拉新兴市场的GDP、汇率、利率数据。它的数据质量很高,但价格也不便宜。

CEIC 的数据通常以 Excel 或 CSV 格式导出。我一般会写个脚本批量导入,避免手动操作出错。

3.1.3 FRED(Federal Reserve Economic Data)

FRED 是美联储的免费数据源,做海外宏观必备。它的API是开放的,用起来很方便。

import pandas as pd
import pandas_datareader.data as web
from datetime import datetime

# 拉取美国GDP数据
gdp = web.DataReader('GDP', 'fred', start='2010-01-01', end='2024-12-31')
print(gdp.head())

FRED 的数据频率很杂,有日度的、周度的、月度的、季度的。嗯,这里要注意,不同频率的数据对齐是个大问题,后面我会细说。

我的经验: 别只依赖一个数据源。我曾在Wind上拉到的工业增加值,跟CEIC上的对不上,后来发现是口径不同。建议交叉验证,至少用两个源核对关键指标。

3.2 数据清洗与对齐

数据拿到手,第一件事不是建模,而是清洗。我见过太多人跳过这步,结果模型跑出来全是噪音。

3.2.1 常见数据问题

  • 缺失值: 宏观数据常有缺失,比如节假日、统计口径调整。
  • 异常值: 比如某个月CPI突然跳升,可能是数据录入错误。
  • 单位不一致: 有的数据是百分比,有的是绝对值,得统一。
  • 时间戳错位: 比如数据发布时间和实际时间对不上。

3.2.2 清洗实战

我一般用 pandas 做清洗,流程如下:

import pandas as pd
import numpy as np

# 假设df是原始数据
df = pd.read_csv('macro_data.csv', index_col='date', parse_dates=True)

# 1. 处理缺失值:前向填充
df.fillna(method='ffill', inplace=True)

# 2. 检测异常值:用3倍标准差法
for col in df.columns:
    mean = df[col].mean()
    std = df[col].std()
    df[col] = np.where(np.abs(df[col] - mean) > 3*std, np.nan, df[col])

# 3. 再次填充异常值
df.fillna(method='ffill', inplace=True)

# 4. 统一单位:假设所有数据转为百分比
df = df / 100
注意: 前向填充不是万能的。我曾经在GDP数据上用了前向填充,结果把季度数据填成了月度数据,导致模型完全跑偏。一定要搞清楚数据的真实频率。

3.2.3 数据对齐

不同数据源的时间戳可能不一样。比如Wind的数据是月末,FRED的数据是月初。对齐的方法很简单:统一到一个时间基准。

我常用的对齐策略:

  1. 确定基准频率(比如月度)。
  2. 将所有数据重采样到该频率。
  3. 用最接近的时间点填充。
# 对齐到月末
df_aligned = df.resample('M').last()

3.3 频率转换:日/周/月/季

频率转换是宏观因子归因里最绕的一环。你想想看,GDP是季度数据,CPI是月度数据,利率可能是日度数据。怎么把它们放到一个模型里?

3.3.1 降频(高频转低频)

降频相对简单。日度转月度,可以用月末值、平均值或中位数。我个人习惯用月末值,因为宏观数据通常反映的是时点状态。

# 日度转月度:取月末值
monthly = daily.resample('M').last()

# 日度转季度:取季末值
quarterly = daily.resample('Q').last()

3.3.2 升频(低频转高频)

升频就麻烦多了。季度数据转月度,不能简单填充,否则会引入伪模式。

我常用的方法:

  • 线性插值: 假设数据在季度内线性变化。
  • 样条插值: 更平滑,适合趋势明显的指标。
  • 前向填充: 简单粗暴,但会丢失信息。
# 季度转月度:线性插值
monthly = quarterly.resample('M').interpolate(method='linear')

# 季度转月度:样条插值
monthly_spline = quarterly.resample('M').interpolate(method='spline', order=2)
小技巧: 升频时,我建议先用可视化检查插值结果。如果插值后的曲线出现奇怪的抖动,说明方法选错了。我曾经用样条插值处理GDP数据,结果插出了负值,闹了个笑话。

3.3.3 频率转换的避坑指南

我曾经在做一个多因子模型时,把季度GDP数据直接填充到月度,然后用月度数据跑回归。结果R²高得离谱,但回测一塌糊涂。后来发现,填充后的数据引入了严重的自相关,模型过拟合了。

所以,频率转换时记住三点:

  1. 不要过度填充: 低频数据转高频,信息量不会增加。
  2. 保留原始频率: 建模时尽量用原始频率,避免人为制造数据。
  3. 使用混合频率模型: 如果必须用不同频率,考虑MIDAS(混合数据抽样)模型。

3.4 本章知识体系

下面这张图,是我自己梳理的数据获取与预处理流程。你看一眼,心里就有谱了。

宏观因子归因:数据获取与预处理流程 数据源 Wind(国内宏观) CEIC(全球宏观) FRED(海外宏观) 其他(Bloomberg等) 数据清洗 缺失值处理 异常值检测 单位统一 时间戳对齐 频率转换 降频(高→低) 升频(低→高) 插值方法选择 混合频率处理 输出:干净、对齐、统一频率的数据集 用于宏观因子归因建模

这张图把整个流程串起来了。从数据源到清洗,再到频率转换,最后输出干净的数据集。每一步都不能省,省了就是给自己挖坑。


好了,数据获取和预处理就聊到这儿。下一章咱们会深入因子构建,到时候这些数据就能派上用场了。

专注资料整理