3. 因子计算与预处理:因子值计算、去极值、标准化、中性化处理
原始因子数据通常包含噪声、极端值和多重共线性,直接用于选股或回测会导致虚假信号。本章系统讲解因子值计算后的三大预处理步骤:去极值、标准化与中性化,确保因子信号稳定、可比且逻辑纯净。
3.1 因子值计算基础
因子值计算是将原始行情、财务或另类数据转化为数值信号的过程。常见因子类型及计算方式如下:
| 因子类型 | 典型因子 | 计算公式(简写) | 数据来源 |
|---|---|---|---|
| 估值因子 | 市盈率(PE) | 收盘价 / 每股收益(TTM) | 日行情 + 财报 |
| 动量因子 | 过去N日收益率 | (Pt - Pt-N) / Pt-N | 日收盘价 |
| 波动率因子 | 历史波动率 | std(ln(Pt/Pt-1), N) | 日收益率序列 |
| 质量因子 | ROE | 净利润 / 股东权益 | 季度/年度财报 |
| 成长因子 | 营收增长率 | (营收t - 营收t-4) / 营收t-4 | 同比财报数据 |
实战提示:因子计算需对齐截面时间戳。例如每月末计算因子时,应使用当月最后一个交易日的数据,并确保所有股票使用同一截止日期,避免未来信息泄漏。
3.2 去极值(Winsorization / MAD)
极端值会严重扭曲因子排序和回归结果。去极值的核心目标是将极端值压缩到合理边界内,而非直接删除。
3.2.1 常用方法对比
| 方法 | 原理 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| MAD(中位数绝对偏差) | 以中位数为中心,MAD = median(|xi - median(x)|),将超出 median ± n·MAD 的值截断 | 因子分布偏态严重时 | 稳健,不受极端值影响 | 计算稍复杂 |
| 百分位截断(Winsorization) | 将低于 p% 分位数的值设为 p% 分位数,高于 (1-p)% 的值设为 (1-p)% 分位数 | 正态性较好的因子 | 简单直观,易于实现 | 对尾部信息丢失较多 |
| 标准差截断(Z-score) | 将超出 mean ± k·std 的值截断 | 近似正态分布 | 计算最快 | 对极端值敏感,均值易被拉偏 |
3.2.2 MAD 去极值代码示例
import numpy as np
def mad_winsorize(factor_series, n=5):
"""
使用MAD方法去极值
factor_series: pandas Series, 截面因子值
n: 倍数,通常取3~5
"""
median = factor_series.median()
mad = np.median(np.abs(factor_series - median))
upper = median + n * mad
lower = median - n * mad
return factor_series.clip(lower, upper)
避坑提醒:去极值必须在每个截面(如每月末)独立进行,不能跨截面使用全局统计量。不同截面的因子分布可能差异很大,统一阈值会导致信号失真。
3.3 标准化(Standardization / Normalization)
标准化使不同量纲的因子具有可比性,避免量级大的因子在组合权重或回归中主导结果。
3.3.1 两种主流标准化方法
| 方法 | 公式 | 输出范围 | 适用场景 |
|---|---|---|---|
| Z-score 标准化 | z = (x - μ) / σ | 均值0,标准差1 | 因子后续用于回归或机器学习模型 |
| Min-Max 归一化 | z = (x - min) / (max - min) | [0, 1] | 因子用于排序打分或需要固定边界 |
3.3.2 Z-score 标准化代码示例
def zscore_standardize(factor_series):
"""
截面Z-score标准化
"""
mean = factor_series.mean()
std = factor_series.std()
return (factor_series - mean) / std
实战提示:标准化同样按截面独立进行。若因子值在截面内存在大量缺失值,应先填充或剔除缺失样本,再计算均值和标准差,避免统计量被缺失值扭曲。
3.4 中性化(Neutralization)
中性化的目的是剔除因子中与已知风险因子(如市值、行业、波动率)相关的部分,使因子暴露纯粹反映选股能力,而非隐含的风格或行业赌注。
3.4.1 中性化流程
- 确定中性化变量:通常包括行业虚拟变量(申万一级/二级行业)、市值对数、BP等。
- 建立回归模型:以因子值为因变量,中性化变量为自变量,进行截面回归。
- 提取残差:回归残差即为中性化后的纯净因子。
3.4.2 行业与市值中性化代码示例
import statsmodels.api as sm
def neutralize_factor(factor_series, industry_dummies, log_market_cap):
"""
对因子进行行业+市值中性化
factor_series: 待中性化因子值
industry_dummies: DataFrame, 行业虚拟变量(已one-hot)
log_market_cap: Series, 对数市值
"""
X = pd.concat([industry_dummies, log_market_cap], axis=1)
X = sm.add_constant(X) # 添加截距项
model = sm.OLS(factor_series, X, missing='drop').fit()
residual = factor_series - model.predict(X)
return residual
避坑提醒:中性化回归时务必检查多重共线性。行业虚拟变量若包含所有行业(如申万一级31个行业),必须删除一个行业作为基准类别,否则回归矩阵不满秩,导致系数无法估计。
3.5 预处理全流程架构
下图展示了因子计算完成后,从原始因子到纯净因子的完整预处理流水线:
3.6 预处理顺序与注意事项
三个步骤的执行顺序不可随意调换:
- 先去极值,再标准化:极端值会拉偏均值和标准差,导致标准化后的因子仍包含异常信号。
- 先标准化,再中性化:标准化使因子量纲统一,中性化回归时系数更稳定;若先中性化再标准化,会破坏中性化后的残差结构。
- 缺失值处理前置:在去极值之前,应至少剔除或填充缺失比例过高的样本(如缺失率 > 30% 的股票直接剔除该截面)。
最佳实践总结:一个稳健的因子预处理流水线为:
原始因子 → 缺失值处理 → MAD去极值(n=5) → Z-score标准化 → 行业+市值中性化 → 纯净因子。
该流程适用于绝大多数截面选股因子,能有效提升因子IC的稳定性和选股区分度。
原始因子 → 缺失值处理 → MAD去极值(n=5) → Z-score标准化 → 行业+市值中性化 → 纯净因子。
该流程适用于绝大多数截面选股因子,能有效提升因子IC的稳定性和选股区分度。