3、因子数据获取:使用Python获取因子数据、数据清洗与预处理、因子标准化处理

好,咱们进入第三章。说实话,因子数据获取这块,是很多量化新手最容易翻车的地方。我见过太多人策略逻辑写得漂亮,结果数据源一塌糊涂,回测曲线看着完美,实盘一跑就崩。为什么?数据质量不行。

今天我就把我在实战中踩过的坑、总结的经验,一次性给你讲透。咱们从数据获取开始,一步步走到标准化处理。

3.1 数据获取:别让脏数据毁了你的策略

我个人习惯,数据获取分两步走:先确定数据源,再写获取逻辑。

常见的数据源有哪些?

  • 免费公开数据:比如Tushare、AKShare、Yahoo Finance。适合个人研究、小规模回测。
  • 商业数据库:Wind、Bloomberg、Quandl。机构用得最多,数据质量高,但贵。
  • 自建数据库:用InfluxDB或MongoDB存自己清洗过的数据。我团队就是这么干的。
我的建议:刚开始做研究,用AKShare就够了。它覆盖A股、期货、基金,接口统一,文档也全。我早期很多因子回测都是用它的数据跑的。

下面是一个用Python获取股票日行情的例子:

import akshare as ak
import pandas as pd

# 获取沪深300成分股日行情
stock_zh_a_hist_df = ak.stock_zh_a_hist(
    symbol="000300",
    period="daily",
    start_date="20200101",
    end_date="20231231",
    adjust="qfq"  # 前复权
)

print(stock_zh_a_hist_df.head())

嗯,这里要注意。很多新手直接拿原始数据就跑因子计算,结果发现收益率算出来是负的。为什么?因为没做复权处理。股票分红、送股都会影响价格连续性。我建议你始终用前复权数据,这样历史收益率才真实。

3.2 数据清洗与预处理:80%的时间花在这里

说实话,因子研究里最耗时的不是建模,而是数据清洗。我在项目中遇到过,一个看起来完美的动量因子,跑出来IC值全是负的。查了两天,发现是某只股票在2015年股灾期间有连续跌停,数据里出现了-20%的日收益率,把整个因子都带偏了。

清洗流程我一般这么走:

  1. 缺失值处理:先看缺失比例。低于5%的,直接删除或填充。高于30%的,这个因子基本废了。
  2. 异常值检测:用3σ原则或IQR方法。金融数据里,极端值往往是数据错误,不是真实信号。
  3. 行业与市值中性化:这个后面会细讲,但清洗阶段就要把行业分类和市值数据准备好。
  4. 时间对齐:不同频率的数据(日频、月频)要统一时间戳。我习惯用交易日历对齐。
我曾经踩过的坑:有一次用某免费数据源,发现某只股票在停牌期间居然有交易数据。后来查出来是数据源把停牌当成了0成交量处理,但价格没变。这种数据如果不处理,你的流动性因子会完全失真。

代码示例——缺失值处理:

# 假设df是因子数据,index是日期,columns是股票代码
# 检查缺失比例
missing_ratio = df.isnull().mean()

# 删除缺失超过30%的股票
df = df.loc[:, missing_ratio < 0.3]

# 对剩余缺失值,用行业均值填充
# 假设industry是每只股票的行业标签
for industry in industry.unique():
    mask = industry == industry
    df.loc[:, mask] = df.loc[:, mask].fillna(
        df.loc[:, mask].mean()
    )

3.3 因子标准化处理:让不同因子站在同一起跑线

你想想看,市盈率因子取值范围可能是5到100,而换手率因子可能是0.1%到10%。如果不做标准化,你合成多因子时,市盈率会完全主导结果。这显然不合理。

常用的标准化方法有三种:

方法 公式 适用场景
Z-score (x - μ) / σ 因子近似正态分布时
Min-Max (x - min) / (max - min) 因子有明确上下界时
Rank标准化 排序后映射到[0,1] 因子有极端值时,最稳健

我个人最常用的是Rank标准化。为什么?金融数据里极端值太多了。Z-score对异常值敏感,一个极端值就能把整个分布拉偏。而Rank标准化只看相对排序,稳健得多。

核心逻辑:因子标准化不是为了改变因子本身的信息,而是为了消除量纲影响。你合成多因子时,每个因子的贡献应该是平等的。

代码示例——Rank标准化:

import numpy as np
from scipy.stats import rankdata

def rank_standardize(series):
    """
    对因子序列进行Rank标准化
    输出范围:[0, 1]
    """
    # 计算排名
    ranks = rankdata(series)
    # 映射到[0, 1]
    normalized = (ranks - 1) / (len(series) - 1)
    return normalized

# 应用
df_standardized = df.apply(rank_standardize, axis=1)

嗯,这里有个细节。你注意看,我是按axis=1做的,也就是每个时间截面上对所有股票做标准化。为什么不是按股票做时间序列标准化?因为因子投资的核心是横截面比较——同一时刻,哪些股票因子值高,哪些低。时间序列标准化会破坏这种横截面信息。

3.4 本章知识体系总览

下面这张图,是我自己画的数据处理流程。你跟着这个流程走,基本不会出大问题。

因子数据获取与处理流程 数据获取 AKShare / Wind / 自建 数据清洗 缺失值 / 异常值 行业市值中性化 因子标准化 Z-score / Min-Max Rank标准化 因子库 每个步骤的常见问题 数据获取常见问题 • 未做复权处理 • 停牌数据未过滤 • 不同数据源时间不一致 数据清洗常见问题 • 缺失比例判断失误 • 异常值未做截尾处理 • 行业分类标准不统一 标准化常见问题 • 横截面vs时间序列混淆 • 极端值影响Z-score • 未考虑行业差异

3.5 实战中的几个小技巧

最后,分享几个我这些年总结出来的经验:

  • 数据备份:原始数据永远不要直接修改。我习惯把原始数据存一份Parquet格式,清洗后的存另一份。万一洗错了,还能回滚。
  • 因子监控:标准化之后,我会定期检查因子的分布。如果某个因子突然变成双峰分布,大概率是数据出了问题。
  • 不要过度清洗:有些异常值其实是真实的市场信号。比如2015年股灾时的极端波动,你把它洗掉了,那你的风控因子就失效了。清洗前先问问自己:这个异常值,是数据错误还是市场行为?
一个小工具推荐:我写了个简单的函数,每次清洗完数据后自动生成一份质量报告——缺失率、异常值数量、分布偏度等。这样一眼就能看出数据有没有问题。你也可以试试,花不了多少时间,但能省很多排查的功夫。

好了,数据获取、清洗、标准化这三步走完,你的因子数据基本就准备好了。下一步就是因子测试和组合构建了。记住,数据质量决定了策略的天花板。你花在数据上的每一分钟,都会在回测结果里体现出来。


专注资料整理