4、因子构建方法论:标准化与去极值、因子正交化、因子动量与反转处理
各位同学,今天我们来聊聊因子构建中最核心的几个实操环节。说实话,很多人在做多因子模型时,花了大把时间找因子,结果一跑回测,效果惨不忍睹。问题出在哪?往往不是因子本身不行,而是构建流程出了问题。
我个人习惯把因子构建比作「做饭」——原材料再好,清洗、切配、调味这些工序没做好,端上桌照样没人吃。标准化、去极值、正交化,就是这些关键工序。咱们一个一个来拆解。
4.1 标准化与去极值:让因子站在同一起跑线
先问个问题:你手上有两个因子,一个市盈率(PE),数值在5到100之间;另一个是动量因子,数值在-0.3到0.5之间。直接把它们扔进模型会怎样?
结果就是,PE因子会「吃掉」动量因子的影响。因为数值量级差太多,模型会天然偏向数值大的变量。这就是为什么我们需要标准化。
4.1.1 标准化方法
常用的标准化方法有三种,我列个表给你看:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score标准化 | (x - μ) / σ | 数据近似正态分布时 |
| Min-Max标准化 | (x - min) / (max - min) | 数据有明确边界时 |
| Rank标准化 | 排序后映射到[0,1] | 数据分布未知或含异常值 |
我在项目中用得最多的是Rank标准化。为什么?因为金融数据很少是正态分布的,你想想看,收益率分布经常是尖峰厚尾,用Z-score反而容易出问题。
核心要点:标准化不是为了改变数据分布,而是为了消除量纲影响。记住这个目的,你就不会选错方法。
4.1.2 去极值处理
说到去极值,我得讲个真实案例。有一次我在做A股因子测试,发现一个因子在2015年股灾期间表现异常好。仔细一查,原来是某只股票因为停牌后复牌,一天涨了10倍,把整个因子的统计量全带偏了。
这就是极值的危害——一个异常点,就能让你的因子分析结果完全失真。
常用的去极值方法:
- MAD法:中位数 ± 3倍MAD(绝对中位差)。稳健性比标准差法好很多。
- 百分位法:直接截断1%和99%分位数以外的值。
- Winsorize法:把极值替换为分位数边界值,而不是直接删除。
我的建议:先用MAD法做第一轮去极值,再用Winsorize法做第二轮。这样既保留了样本量,又控制了极端值的影响。
4.2 因子正交化:解决「多重共线性」这个老问题
因子多了,难免会互相「串通」。比如估值因子和市值因子,天然就有相关性。如果你不处理,模型就会陷入多重共线性的泥潭——系数估计不稳定,今天跑出来一个结果,明天换段数据又变了。
正交化,说白了就是把这些「串通」的因子拆开,让它们各说各的话,互不干扰。
4.2.1 Gram-Schmidt正交化
这个方法很经典,思路也简单:
- 选一个基准因子,比如市值因子。
- 把其他因子对基准因子做回归,取残差。
- 这个残差就是「剔除基准因子影响后」的新因子。
代码实现也很直接:
import numpy as np
from sklearn.linear_model import LinearRegression
def gram_schmidt_orthogonalize(factors, base_idx=0):
"""
Gram-Schmidt正交化
factors: 因子矩阵,每列一个因子
base_idx: 基准因子的列索引
"""
n_factors = factors.shape[1]
orthogonalized = np.zeros_like(factors)
# 基准因子保持不变
orthogonalized[:, base_idx] = factors[:, base_idx]
for i in range(n_factors):
if i == base_idx:
continue
# 对基准因子做回归
reg = LinearRegression().fit(
factors[:, base_idx].reshape(-1, 1),
factors[:, i]
)
# 取残差作为正交化后的因子
orthogonalized[:, i] = factors[:, i] - reg.predict(
factors[:, base_idx].reshape(-1, 1)
)
return orthogonalized
注意:Gram-Schmidt的缺点是结果依赖于基准因子的选择。你选市值做基准,和选动量做基准,得到的结果完全不同。所以这个方法适合你「明确知道哪个因子更重要」的场景。
4.2.2 PCA正交化
PCA就不一样了。它不偏袒任何一个因子,而是找到数据中「方差最大」的方向。
我个人更喜欢用PCA做正交化,原因有三:
- 不依赖基准选择,结果唯一
- 能自动降维,剔除冗余信息
- 主成分之间天然正交,相关性为零
但PCA也有坑——主成分失去了经济含义。你原来有「估值因子」「动量因子」,PCA之后变成了「主成分1」「主成分2」,解释起来就费劲了。
我的经验:做研究阶段用PCA,追求预测精度;做归因分析时用Gram-Schmidt,保留经济含义。两者不冲突,看场景切换就行。
4.3 因子动量与反转处理:抓住时序上的规律
最后一个话题,也是很多人容易忽略的——因子本身也有「动量」和「反转」效应。
什么意思?你想想看,一个因子今天表现好,明天是不是大概率继续好?不一定。有时候是强者恒强(动量),有时候是盛极而衰(反转)。
4.3.1 因子动量的处理
因子动量,说白了就是「过去表现好的因子,未来一段时间可能继续好」。我在做CTA策略时深有体会——有些因子就像有惯性一样,趋势一旦形成,能持续好几周。
处理方法:
- 滚动窗口平滑:用过去N期的均值代替当期值,过滤噪音
- 指数加权移动平均:给近期数据更高权重,捕捉趋势
- 动量打分:根据因子过去表现给权重,表现越好权重越高
4.3.2 因子反转的处理
反转效应正好相反——涨多了要跌,跌多了要涨。这在A股市场尤其明显,特别是短期反转。
我曾经犯过一个错误:在日频策略中用了动量因子,结果回测漂亮,实盘亏得一塌糊涂。后来才发现,A股市场短期反转效应太强,动量因子在日频上根本跑不通。
处理反转的方法:
- 差分处理:用因子值的变化量代替绝对值
- 均值回复模型:假设因子会回归长期均值
- 周期分解:把因子拆成趋势项和周期项,分别处理
避坑指南:做因子动量/反转处理前,先做一下自相关分析。如果自相关系数为正,用动量处理;为负,用反转处理。别拍脑袋决定。
知识体系总览
说了这么多,我把整个因子构建的流程画了张图,方便你理解各环节的关系:
这张图把整个流程串起来了。你从原始因子出发,先做标准化和去极值,把数据「洗干净」。然后分两条路——要么做正交化消除相关性,要么做动量/反转处理捕捉时序规律。两条路可以都走,最终得到的就是干净、正交、稳定的因子。
嗯,这一章的内容就到这。因子构建是基本功,但基本功往往决定你能走多远。下次你跑因子回测时,记得先问问自己:标准化做了吗?极值去了吗?因子之间正交了吗?时序规律处理了吗?
把这四步走完,你的因子质量至少提升一个档次。