2. 数据准备基础:数据源介绍(行情、财务、另类)、数据清洗与对齐、面板数据结构
因子研究的起点是数据。没有干净、对齐、结构化的数据,任何复杂的模型都会失效。本章将系统梳理量化研究中常用的数据源类型、数据清洗与对齐的核心方法,以及面板数据(Panel Data)的标准结构。
2.1 数据源全景:行情、财务与另类数据
量化因子研究的数据源通常分为三大类:行情数据、财务数据和另类数据。下表对比了这三类数据的关键特征:
| 数据类别 | 典型字段 | 更新频率 | 主要用途 | 常见来源 |
|---|---|---|---|---|
| 行情数据 | 开盘价、收盘价、最高价、最低价、成交量、成交额 | 日频 / 分钟频 / Tick 级 | 价格动量、波动率、流动性因子 | Wind、聚宽、Tushare |
| 财务数据 | 营业收入、净利润、ROE、资产负债率、现金流 | 季频 / 半年频 / 年频 | 价值、质量、成长因子 | Wind、东方财富、CSMAR |
| 另类数据 | 新闻情绪、搜索热度、卫星图像、供应链数据 | 日频 / 实时 / 事件驱动 | 情绪、舆情、供应链风险因子 | 通联数据、第三方数据商 |
实操提示:初学者建议优先使用日频行情数据 + 季频财务数据构建基础因子库。另类数据虽然价值高,但清洗成本大,适合进阶阶段引入。
2.2 数据清洗与对齐:从原始数据到可用面板
原始数据通常存在缺失值、异常值、幸存者偏差、财务数据发布时间滞后等问题。数据清洗与对齐是因子研究中最耗时但最关键的步骤。
2.2.1 核心清洗步骤
- 缺失值处理:行情数据缺失通常直接剔除;财务数据缺失可向前填充(forward fill)或使用行业均值替代。
- 异常值处理:使用 MAD(中位数绝对偏差)或 3-sigma 方法识别并截尾(winsorize)。
- 幸存者偏差消除:必须使用全量历史股票池(包含已退市、ST 股票),否则因子表现会被高估。
- 财务数据时间对齐:财务数据发布存在滞后(通常 T+1~T+4 个月),必须使用 财报发布日期 而非财报截止日期进行对齐。
2.2.2 数据对齐:时间戳与股票代码
多源数据合并时,必须确保时间戳和股票代码严格对齐。常见对齐方式包括:
- 精确对齐:使用
trade_date+stock_code作为联合主键进行左连接。 - 滞后对齐:财务数据使用
announce_date对齐到下一个交易日。 - 重采样对齐:分钟数据对齐到日频时,使用
resample('D').last()或resample('D').ohlc()。
关键原则:因子研究必须使用 前瞻性数据(即因子计算时只能使用当时已知的信息),严禁使用未来数据(look-ahead bias)。财务数据必须滞后对齐,行情数据必须使用复权价格。
2.3 面板数据结构:因子研究的基石
因子研究的标准数据结构是 面板数据(Panel Data),即同时包含截面(股票)和时间(交易日)两个维度的二维表格。每一行代表一个股票在某个时间点的观测值。
2.3.1 面板数据标准格式
| trade_date | stock_code | close_price | volume | factor_momentum | factor_value | forward_return_1d |
|---|---|---|---|---|---|---|
| 2024-01-02 | 000001.SZ | 12.35 | 1.2e7 | 0.85 | 0.32 | 0.015 |
| 2024-01-02 | 600000.SH | 8.92 | 8.5e6 | 0.62 | 0.45 | -0.008 |
| 2024-01-03 | 000001.SZ | 12.54 | 1.5e7 | 0.87 | 0.31 | 0.022 |
上表中:trade_date 和 stock_code 构成联合索引;close_price、volume 为原始行情字段;factor_momentum、factor_value 为计算后的因子值;forward_return_1d 为未来 1 日收益率(用于后续 IC 分析)。
2.3.2 面板数据构建流程
从原始数据到标准面板,通常需要以下步骤:
- 获取全量股票列表(含退市股、ST 股)。
- 获取日频行情数据(复权价格)。
- 获取财务数据并滞后对齐到发布日期。
- 合并行情与财务数据,生成宽表。
- 计算因子值(如动量、价值因子)。
- 计算未来收益率(用于 IC 分析)。
- 清洗缺失值与异常值,生成最终面板。
常见陷阱:很多初学者在合并数据时忘记处理 停牌日 和 非交易日,导致面板中出现大量空行。建议使用交易日历(calendar)进行过滤,只保留实际交易日。
2.4 数据准备流程总览
下图展示了从原始数据到可用面板数据的完整流程:
2.5 代码示例:构建基础面板数据
以下 Python 代码演示了如何使用 pandas 构建标准面板数据:
import pandas as pd
import numpy as np
# 1. 模拟行情数据
dates = pd.date_range('2024-01-01', '2024-01-10', freq='B')
stocks = ['000001.SZ', '600000.SH', '000002.SZ']
data = []
for date in dates:
for stock in stocks:
data.append({
'trade_date': date,
'stock_code': stock,
'close_price': np.random.uniform(8, 15),
'volume': np.random.randint(1e6, 2e7)
})
df_market = pd.DataFrame(data)
# 2. 模拟财务数据(滞后对齐)
finance_data = {
'stock_code': ['000001.SZ', '600000.SH', '000002.SZ'],
'announce_date': pd.to_datetime(['2024-01-05', '2024-01-06', '2024-01-07']),
'roe': [0.12, 0.15, 0.09]
}
df_finance = pd.DataFrame(finance_data)
# 3. 合并行情与财务数据(使用 announce_date 对齐到下一个交易日)
df_market['trade_date'] = pd.to_datetime(df_market['trade_date'])
df_merged = pd.merge_asof(
df_market.sort_values('trade_date'),
df_finance.sort_values('announce_date'),
left_on='trade_date',
right_on='announce_date',
by='stock_code',
direction='forward'
)
# 4. 计算因子值(示例:动量因子 = 过去5日收益率)
df_merged = df_merged.sort_values(['stock_code', 'trade_date'])
df_merged['factor_momentum'] = (
df_merged.groupby('stock_code')['close_price']
.pct_change(5)
)
# 5. 计算未来1日收益率(用于IC分析)
df_merged['forward_return_1d'] = (
df_merged.groupby('stock_code')['close_price']
.pct_change(-1)
)
# 6. 清洗:删除缺失值
df_panel = df_merged.dropna(subset=['factor_momentum', 'forward_return_1d'])
# 7. 最终面板数据
print(df_panel[['trade_date', 'stock_code', 'close_price',
'factor_momentum', 'forward_return_1d']].head())
代码要点:
• 使用
• 因子计算和收益率计算都基于
• 最终面板数据必须包含
• 使用
pd.merge_asof 实现财务数据的滞后对齐,避免未来信息泄露。• 因子计算和收益率计算都基于
groupby 分组操作,确保每个股票独立计算。• 最终面板数据必须包含
trade_date、stock_code、因子值和未来收益率,这是后续 IC 分析的标准输入格式。
2.6 数据质量检查清单
在进入因子分析之前,建议逐项检查以下内容:
- 时间范围完整性:面板数据是否覆盖了完整的回测区间?
- 股票池完整性:是否包含了退市股和 ST 股?
- 缺失值比例:每个因子的缺失值比例是否低于 20%?
- 异常值处理:是否对因子值进行了截尾(winsorize)?
- 未来信息检查:财务数据是否使用了发布日期而非截止日期?
- 复权处理:行情价格是否使用了后复权或前复权?
核心结论:数据准备的质量直接决定因子研究的可信度。一个干净、对齐、无未来信息的面板数据,是后续所有 IC 分析、因子组合构建和回测验证的基石。建议在每次数据更新后,都运行一次上述质量检查清单。