第二章:数据准备与清洗——因子研究的基石

做量化研究这么多年,我越来越觉得一个道理:因子研究,三分靠模型,七分靠数据。你想想看,数据要是脏的,再牛的算法也白搭。这一章,我就把数据准备与清洗的那些坑,一个一个给你讲清楚。

核心观点:数据清洗不是体力活,是决定因子有效性的第一道门槛。跳过这一步,后面全是幻觉。

2.1 数据源选择——选对源头,事半功倍

数据源的选择,说白了就是决定你研究的「原材料」质量。我个人习惯把数据源分成三类:

  • 交易所官方数据:最权威,但获取成本高,更新频率可能不够快。
  • 金融数据服务商:比如Wind、聚宽、Tushare等,覆盖广,但要注意数据清洗程度。
  • 第三方爬虫数据:灵活,但质量参差不齐,需要大量校验。

我在项目中遇到过一个问题:用某家数据商的日频数据做回测,结果发现复权因子算错了,导致回测收益虚高20%。嗯,从那以后,我每次换数据源都会做一次「交叉验证」——拿两个不同来源的数据对比一下,看看关键指标是否一致。

我的建议:至少准备两个独立数据源。一个做主数据,一个做校验。别嫌麻烦,这能救你命。

2.2 缺失值处理——别让「空」骗了你

缺失值,是数据清洗里最常见的坑。很多人上来就删,或者直接填0,这其实很危险。

为什么会这样?因为缺失值背后可能有信息。比如某只股票停牌了,那缺失值代表的是「流动性缺失」,而不是「数据丢了」。

我一般把缺失值分成三类:

类型 含义 处理方法
随机缺失 数据偶然丢失,无规律 插值法(线性/时间序列插值)
结构性缺失 因停牌、退市等原因缺失 保留缺失,或标记为特殊值
完全缺失 该股票从未有数据 直接剔除该股票

举个例子,处理日频收益率数据时,我习惯这样做:

# 伪代码示例:缺失值处理逻辑
if 缺失比例 < 5%:
    使用前向填充 + 线性插值
elif 缺失比例 < 20%:
    使用行业均值填充
else:
    剔除该股票或该时间段

避坑指南:我曾经用「0填充」处理过收益率缺失值,结果回测时发现策略在停牌股上「凭空赚钱」。后来才意识到,停牌期间收益率应该是NaN,而不是0。切记:不要随意填充你不理解的数据。

2.3 异常值识别与处理——别让「极端值」带偏你

异常值,说白了就是那些「离谱」的数据点。比如某只股票一天涨了1000%,这明显是数据错误。

我常用的异常值识别方法有几种:

  • 3σ原则:超过均值±3倍标准差的数据,视为异常。适合正态分布的数据。
  • IQR方法:用四分位距来识别。更稳健,不受极端值影响。
  • MAD方法:中位数绝对偏差。对异常值最不敏感,我比较喜欢用这个。

处理方式上,我一般分两步走:

  1. 先识别:用MAD方法找出异常点。
  2. 再处理:不是直接删除,而是「缩尾处理」(Winsorize)——把异常值拉到边界值。
# 缩尾处理示例(Python风格)
def winsorize(series, limits=[0.01, 0.01]):
    lower = series.quantile(limits[0])
    upper = series.quantile(1 - limits[1])
    return series.clip(lower, upper)

个人经验:我一般缩尾到1%和99%分位数。但如果是高频数据,我会缩得更狠一点,比如0.5%和99.5%。因为高频数据里的异常值往往更「离谱」。

2.4 数据标准化——让因子站在同一起跑线

标准化,说白了就是把不同量纲的因子拉到同一个尺度上。你想想看,市盈率可能是几十,换手率可能是百分之几,不标准化怎么比较?

常用的标准化方法:

方法 公式 适用场景
Z-score (x - μ) / σ 数据近似正态分布
Min-Max (x - min) / (max - min) 数据有明确边界
Rank标准化 排序后映射到[0,1] 数据分布未知,或存在异常值

我个人最常用的是Rank标准化。为什么?因为它对异常值不敏感。你想想看,如果某只股票的市盈率是1000,用Z-score会把它变成一个巨大的异常值,但用Rank标准化,它只是排最后一名而已。

重要提醒:标准化一定要在「截面」上做,也就是每个时间点单独做。千万别把所有时间的数据混在一起标准化,那会引入未来信息,造成「前视偏差」。

嗯,这里要注意一点:标准化之后,因子值就变成了相对值,不再保留原始量纲。所以你在解释因子含义时,要小心别把标准化后的值当成原始值去理解。

本章知识体系

下面这张图,是我梳理的数据准备与清洗的完整流程。你可以把它当成一个检查清单,每次做数据清洗时对照着来。

数据准备与清洗流程 数据源选择 交易所 / 服务商 / 爬虫 缺失值处理 插值 / 填充 / 剔除 异常值识别 3σ / IQR / MAD 异常值处理 缩尾 / 截尾 / 标记 数据标准化 Z-score / Min-Max / Rank 清洗后数据 可用于因子计算 迭代验证:清洗后检查分布 每个步骤都需要「交叉验证」和「业务理解」 不要机械地套用统计方法 记住:数据清洗的目标是「保留真实信号,去除噪声」 而不是「让数据看起来漂亮」

这张图里,我特意画了一个循环箭头。为什么?因为数据清洗不是一次性的工作。你做完标准化之后,最好回头看看原始数据分布有没有变化,异常值处理得是否合理。我经常要迭代两三轮,才能得到一份「干净」的数据。

最后一个小技巧:每次清洗完数据,我都会保存一份「清洗日志」。记录每一步做了什么、删了多少数据、填充了什么值。这样万一回测结果不对,还能回溯排查。别问我怎么知道的——都是血泪教训。

专注资料整理