4、数据准备与清洗:数据源选择、缺失值处理、异常值识别、复权处理
多因子选股模型的稳健性,本质上取决于输入数据的质量。业界常说“Garbage in, Garbage out”,在量化研究场景中,数据源不一致、缺失值未处理、异常值未识别、复权方式错误,都会直接导致因子失效、回测失真甚至实盘亏损。本章围绕数据准备与清洗的四个核心环节展开:数据源选择、缺失值处理、异常值识别、复权处理,帮助学员建立一套可落地、可复核的数据工程标准流程。
4.1 数据源选择:多源交叉验证与主数据源确定
数据源选择是数据工程的第一步,也是决定后续清洗工作量的关键。不同数据源在字段定义、更新频率、历史深度、复权算法上存在显著差异。例如,Wind 的财务数据字段最全,但价格数据的前复权因子在除权除息日可能产生微小偏差;聚宽和米筐的数据更偏向于量化研究场景,接口友好但历史深度可能受限;Tushare 免费版适合教学和原型验证,但稳定性和字段完整性需要额外校验。
核心原则是:确定一个主数据源,至少一个辅助数据源用于交叉验证。主数据源负责日常因子计算和回测,辅助数据源用于关键字段(如收盘价、总股本、净利润)的抽样比对。对于财务数据,建议以定期报告披露的原始值为主,避免使用数据商已经做过的“调整后”字段,因为不同数据商的调整逻辑可能不同。
| 数据源 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| Wind | 字段最全、机构认可度高 | 费用高、接口较重 | 机构实盘、正式研究 |
| 聚宽 / 米筐 | 量化友好、因子库丰富 | 历史深度有限 | 策略研发、回测 |
| Tushare | 免费、社区活跃 | 限流、字段不稳定 | 教学、原型验证 |
| 自建数据库 | 完全可控、可定制 | 维护成本高 | 长期生产环境 |
4.2 缺失值处理:分层策略与行业中性化填充
缺失值是面板数据中最常见的问题,来源包括停牌、新股上市初期、财务数据未及时披露、数据商采集遗漏等。处理缺失值不能一刀切,需要根据缺失比例和缺失原因分层处理。
第一层:删除策略。对于缺失比例超过 30% 的字段(如某些冷门财务指标),直接删除该字段,避免后续因子计算引入大量噪声。对于单只股票在某个时间窗口内缺失超过 20 个交易日的,考虑剔除该股票在该窗口的数据。
第二层:填充策略。对于时间序列型数据(如日收益率、成交量),优先使用前向填充(Forward Fill)或线性插值。对于截面型数据(如市盈率、市净率),使用行业均值或行业中位数填充。这里的关键是行业中性化填充——用同行业、同市值区间的股票均值填充,避免填充值本身带有行业偏差。
第三层:标记策略。对于无法准确填充的缺失值,建议在因子计算时增加一个“缺失标记”虚拟变量,让模型自行学习缺失模式是否具有预测信息。例如,某股票连续停牌后复牌,其缺失期间的数据不应简单填充,而应标记为“停牌状态”。
# 缺失值处理伪代码示例
def handle_missing(df, industry_col='industry', value_col='pe_ttm'):
# 按行业分组填充中位数
df[value_col] = df.groupby(industry_col)[value_col].transform(
lambda x: x.fillna(x.median())
)
# 剩余缺失值用全局中位数填充
df[value_col] = df[value_col].fillna(df[value_col].median())
# 增加缺失标记
df[value_col + '_missing'] = df[value_col].isnull().astype(int)
return df
4.3 异常值识别:MAD 法与分位数截尾
异常值(Outlier)对因子值的影响远大于缺失值。一个极端值可能让因子排序完全失真,导致回测结果被少数股票主导。常用的异常值识别方法有三种:Z-score 法、MAD 法、分位数截尾法。
Z-score 法假设数据服从正态分布,将超过均值 3 个标准差的值视为异常。但金融数据普遍具有厚尾特征,Z-score 法容易将正常的高收益误判为异常。
MAD 法(Median Absolute Deviation)基于中位数和偏差,对厚尾分布更稳健。计算方式为:MAD = median(|x_i - median(x)|),将偏离中位数超过 3 倍 MAD 的值视为异常。MAD 法不需要数据服从正态分布,更适合处理市盈率、市净率等具有明显偏态的财务比率。
分位数截尾法直接将因子值上下 1% 或 2.5% 的极值替换为边界值(Winsorize)。这种方法简单直观,但会损失尾部信息。在实际操作中,建议先使用 MAD 法识别异常值,再对识别出的异常值进行 Winsorize 处理,而不是直接删除。
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Z-score | 近似正态分布的数据 | 计算简单 | 厚尾数据误判率高 |
| MAD | 厚尾分布、财务比率 | 稳健、抗极端值 | 计算稍复杂 |
| 分位数截尾 | 因子排序前处理 | 直观、易解释 | 损失尾部信息 |
4.4 复权处理:前复权、后复权与涨跌幅还原
复权处理是数据清洗中最容易出错、但影响最大的环节。股票在除权除息日(如送股、配股、分红)会出现价格跳空,如果不做复权处理,收益率计算会失真。复权分为前复权、后复权和涨跌幅还原三种方式。
前复权以当前价格为基准,调整历史价格。优点是当前价格与市场一致,适合技术分析和因子计算;缺点是每次新除权事件发生,历史价格都会变化,导致历史数据不可回溯。
后复权以上市首日价格为基准,调整后续价格。优点是历史价格固定,适合长期回测;缺点是当前价格与市场不一致,不便于直观理解。
涨跌幅还原是更精细的处理方式:不直接调整价格,而是计算每日涨跌幅时,将除权除息日的涨跌幅用“除权除息参考价”还原。这种方式最准确,但需要数据商提供完整的除权除息因子。
在多因子模型中,建议使用后复权价格计算收益率,因为因子计算需要历史价格的一致性。但在展示净值曲线时,可以转换为前复权价格,便于投资者理解。
4.5 实战场景:从原始数据到可用因子面板
下面通过一个完整案例,串联本章所有知识点。假设我们需要构建一个包含“市盈率倒数(EP)”、“市净率倒数(BP)”、“过去 20 日收益率(MOM20)”三个因子的模型,数据源为聚宽,时间范围为 2018 年 1 月至 2023 年 12 月。
第一步:数据源体检。从聚宽下载全部 A 股日线数据,与 Wind 数据对比 10 只样本股票的收盘价,发现 2019 年 7 月某只股票在聚宽的收盘价与 Wind 差异 0.3%,排查后确认是聚宽在该日未处理停牌状态,导致价格未更新。解决方案:在数据下载时增加“停牌标记”字段,后续计算收益率时跳过停牌日。
第二步:缺失值处理。财务数据(PE、PB)存在约 5% 的缺失,主要集中在次新股和 ST 股。采用行业中性化填充:按申万一级行业分组,用行业中位数填充。对于 ST 股,单独标记,不参与填充,因为 ST 股的财务数据本身具有特殊性。
第三步:异常值识别。对 EP 和 BP 因子分别计算 MAD,发现 EP 因子有 2.3% 的异常值,BP 因子有 1.8% 的异常值。对这些异常值进行 1% 分位数 Winsorize 处理。MOM20 因子没有发现异常值,因为收益率本身已经经过标准化。
第四步:复权处理。使用聚宽提供的后复权价格计算 MOM20 因子。在除权除息日,聚宽的后复权价格已经自动调整,无需额外处理。但需要验证:随机抽取 10 只股票,手动计算除权日的涨跌幅,与聚宽数据对比,确认误差在 0.01% 以内。
第五步:质量校验。生成最终面板数据后,检查以下指标:时间戳是否连续、股票代码是否唯一、因子值分布是否合理(EP 因子应在 -0.1 到 0.1 之间,BP 因子应在 0 到 1 之间)、是否存在极端值(超过 5 倍 MAD)。
4.6 总结复盘:数据清洗的五个核心原则
数据准备与清洗是量化研究中最“枯燥”但最“值钱”的环节。总结五个核心原则:
- 可追溯性:每一步清洗操作都要有日志记录,确保任何因子值都可以回溯到原始数据。
- 行业中性化:填充和异常值处理都要考虑行业差异,避免引入行业偏差。
- 稳健优先:优先使用 MAD 等稳健统计量,而不是依赖正态分布假设。
- 复权一致性:整个研究流程中,收益率计算必须统一使用同一种复权方式,不能混用。
- 自动化与监控:将清洗流程封装为自动化脚本,每次数据更新后自动运行,并输出质量报告(缺失率、异常率、复权因子变化等)。
数据清洗的质量直接决定了因子有效性的上限。一个优秀的量化研究员,首先是一个优秀的数据工程师。掌握本章内容,你就为后续的因子计算、组合优化和回测验证打下了坚实的地基。