数据准备与清洗:数据源选择、对齐与预处理

做多因子模型,有个铁律:数据质量决定模型上限。我见过太多人花几个月调参数,结果数据源里藏着几个异常值,模型直接崩了。今天咱们就聊聊数据准备这关怎么过。

核心观点:数据清洗占整个因子研究工作量的60%以上。别嫌麻烦,这一步偷懒,后面全是坑。

2.1 数据源选择:Wind、Tushare、聚宽怎么选?

我个人习惯把数据源分成三类:

  • Wind(万得):机构标配,数据全、质量高,但贵。一年几万块,个人用户基本劝退。
  • Tushare:开源免费,社区活跃。适合个人研究和回测。但要注意,免费版有调用频率限制。
  • 聚宽(JoinQuant):自带回测平台,数据直接可用。适合快速验证想法,但导出数据不太灵活。

我在项目中遇到过一个问题:用Tushare拉历史数据,某天突然发现某只股票的复权因子对不上。后来查了半天,原来是接口版本更新了。所以我的建议是——生产环境用Wind,研究阶段用Tushare或聚宽。如果条件允许,最好两个源交叉验证。

小技巧:用Tushare时,记得设置缓存。不然每次跑回测都重新拉数据,API额度很快就用完了。

2.2 数据对齐:不同频率的数据怎么合并?

多因子模型里,因子数据、收益率数据、市值数据往往来自不同频率。日频因子、月频调仓、季频财报……怎么对齐?

说白了,就是以调仓日为基准,向前取最近的有效值。举个例子:每月第一个交易日调仓,那因子值就用上一个交易日的收盘数据。

import pandas as pd

# 假设因子数据是日频,调仓日是每月第一个交易日
factor_data = pd.read_csv('factor_daily.csv', index_col=0, parse_dates=True)
rebalance_dates = pd.date_range('2020-01-01', '2023-12-31', freq='BMS')  # 每月第一个交易日

# 对齐:取调仓日前一天的因子值
aligned = factor_data.reindex(rebalance_dates, method='ffill')

嗯,这里要注意:ffill是向前填充,但如果你用bfill,那就用到未来数据了——这是回测中常见的“未来函数”陷阱。我曾经因为这个原因,回测曲线漂亮得不像话,实盘直接打脸。

2.3 缺失值处理:删还是补?

数据缺失是常态。比如某只股票停牌,或者财报数据延迟披露。处理方式就三种:

  1. 直接删除:简单粗暴,但会损失样本量。如果缺失比例超过5%,慎用。
  2. 填充均值/中位数:适合因子值分布稳定的情况。但要注意,填充后可能会引入偏差。
  3. 用行业均值填充:我个人最推荐。比如某银行股缺失了市盈率,就用同行业其他银行股的均值来补。

避坑指南:千万不要用未来数据填充!比如用下个月的因子值来补这个月的缺失——这在回测中属于严重的数据泄露。

我曾经在做一个A股多因子模型时,发现某只股票连续停牌30天,因子值全是NaN。当时我直接删掉了这只股票,结果模型在银行板块的预测能力明显下降。后来改用行业均值填充,效果好了很多。

2.4 异常值处理:别让一个极端值毁了整个模型

因子数据里经常出现极端值。比如某只小盘股突然暴涨,市盈率飙到1000倍。这种值如果不处理,模型会把它当成重要信号,结果就是过拟合。

常用的方法:

  • MAD法(中位数绝对偏差):比标准差更稳健。我一般用3倍MAD作为阈值。
  • 分位数截断:比如把上下1%的极端值替换成1%和99%分位数。
  • 缩尾处理(Winsorize):把极端值拉到阈值,而不是直接删除。
from scipy.stats import mstats

# 缩尾处理:上下1%的极端值拉到边界
factor_clean = mstats.winsorize(factor_data, limits=[0.01, 0.01])

你想想看,如果直接用原始数据,一个异常值可能让相关系数从0.1变成0.5——这完全是虚假信号。所以,异常值处理不是可选项,是必选项

2.5 复权处理:后复权还是前复权?

这个问题我每次讲课都会被问到。简单说:

  • 前复权:保持当前价格不变,调整历史价格。适合回测,因为能看到真实的收益率。
  • 后复权:保持上市首日价格不变,调整后续价格。适合看长期走势,但回测时容易失真。

我个人习惯用前复权做因子计算。为什么呢?因为因子模型需要的是收益率序列,前复权能保证收益率计算准确。后复权虽然能反映真实分红,但会导致价格跳跃,影响因子值的稳定性。

注意:如果用前复权,记得把分红、送股都考虑进去。有些数据源只做了价格复权,没做股本复权——这会导致市值计算错误。

我记得有一次,我用聚宽的数据做回测,发现某只股票的因子值突然跳变。查了半天,原来是那天除权除息,但数据源只做了价格复权,没调整股本。从那以后,我每次都会检查复权后的股本数据是否连续。

知识体系总览

下面这张图概括了数据准备与清洗的核心流程。你可以把它当成一个检查清单:

数据准备与清洗流程 数据源选择 Wind / Tushare / 聚宽 数据对齐 不同频率 → 向前填充 缺失值处理 删除 / 填充 / 行业均值 异常值处理 MAD法 / 分位数截断 / 缩尾 复权处理 前复权(推荐) / 后复权 质量控制要点 • 避免未来函数 • 交叉验证数据源 • 检查股本复权 • 记录清洗日志 每个步骤都需要记录处理参数,方便后续复现和审计

数据准备这一步,说白了就是给模型打好地基。地基不稳,楼盖得再高也是危房。我个人建议,每次做数据清洗时都写个日志,记录每一步的参数和结果。这样出了问题也好回溯。

最后说一句:数据清洗没有银弹。不同市场、不同因子、不同频率,处理方法都不一样。关键是要理解每一步背后的逻辑,而不是机械地套模板。

蓝海数据掘金营,专注资料整理