3. 因子计算与标准化

因子计算与标准化是量化因子研究流程中的核心环节。原始因子数据通常包含极端值、量纲差异和行业/市值干扰,必须经过系统化处理才能用于后续的因子有效性检验和组合构建。本章将详细讲解因子计算公式、去极值、标准化和中性化处理的标准流程。

3.1 因子计算公式

因子计算是将原始市场数据(价格、成交量、财务指标等)转化为具有预测能力的数值信号的过程。常见的因子计算公式可分为以下几类:

因子类别 典型公式 参数说明
动量因子 Momentum = (Pt / Pt-n) - 1 Pt为当日收盘价,n为回溯期(如20日)
反转因子 Reversal = (Pt-1 / Pt-21) - 1 使用过去1日与21日均价之比
波动率因子 Volatility = std(returnt-20:t-1) 过去20日收益率的标准差
价值因子 BP = BookValue / MarketCap 账面市值比,需使用最新财报数据
质量因子 ROE = NetIncome / Equity 净资产收益率,反映盈利能力
实战要点:因子计算时需注意数据对齐——财务数据应使用最新披露的季报/年报,价格数据需考虑复权处理(前复权或后复权),避免因分红送股导致的价格跳跃影响因子值。

3.2 去极值处理

原始因子数据中常包含极端异常值,这些值可能由数据错误、特殊事件或市场极端波动引起。若不处理,会严重扭曲后续标准化和回归分析的结果。常用的去极值方法有两种:

3.2.1 MAD(中位数绝对偏差)法

MAD法基于中位数和绝对偏差,对异常值具有较好的鲁棒性。处理步骤如下:

  1. 计算因子序列的中位数 median
  2. 计算每个因子值与中位数的绝对偏差 |xi - median|
  3. 计算绝对偏差的中位数 MAD = median(|xi - median|)
  4. 设定阈值 n(通常取3~5),将超出 median ± n × MAD 的值替换为边界值
import numpy as np

def mad_winsorize(factor, n=5):
    median = np.median(factor)
    mad = np.median(np.abs(factor - median))
    upper = median + n * mad
    lower = median - n * mad
    return np.clip(factor, lower, upper)

3.2.2 百分位法

百分位法直接根据数据分布的分位数设定上下限,操作简单直观:

def percentile_winsorize(factor, lower_pct=0.01, upper_pct=0.99):
    lower = np.percentile(factor, lower_pct * 100)
    upper = np.percentile(factor, upper_pct * 100)
    return np.clip(factor, lower, upper)
方法 优点 缺点 适用场景
MAD法 对极端值不敏感,鲁棒性强 计算稍复杂,需选择n值 因子分布偏态严重时
百分位法 简单直观,易于解释 可能剔除过多正常值 因子分布较对称时
常见误区:去极值不等于删除数据。正确的做法是使用“截尾(Winsorize)”将极端值替换为边界值,而非直接删除样本点,否则会破坏截面数据的完整性,导致后续分析产生偏差。

3.3 标准化处理

标准化旨在消除不同因子之间的量纲差异,使因子值具有可比性。常用的标准化方法包括Z-score和Rank标准化。

3.3.1 Z-score标准化

Z-score将因子转换为均值为0、标准差为1的标准正态分布:

def zscore_normalize(factor):
    mean = np.mean(factor)
    std = np.std(factor)
    return (factor - mean) / std

Z-score的优点是保留了因子值的相对距离信息,但要求因子分布接近正态分布,且对异常值敏感。因此,Z-score标准化前必须先进行去极值处理。

3.3.2 Rank标准化

Rank标准化将因子值转换为排序后的百分位数,最终映射到[0,1]或[-1,1]区间:

def rank_normalize(factor):
    rank = factor.rank()
    return (rank - 1) / (len(rank) - 1)  # 映射到[0,1]

Rank标准化的优势在于:

  • 对异常值不敏感,无需预先去极值
  • 适用于任何分布形态的数据
  • 保留了因子间的排序关系
方法对比:Z-score适合因子值本身具有实际意义、分布较对称的场景(如估值类因子);Rank标准化更适合因子值仅需排序信息、分布不确定的场景(如情绪类因子)。在实际多因子模型中,Rank标准化更为常用。

3.4 中性化处理

中性化处理旨在剔除因子中与行业、市值等系统性变量相关的部分,提取因子特有的选股能力。最常用的方法是回归残差法:

  1. 以因子值为因变量,行业虚拟变量和市值(或市值对数)为自变量,建立线性回归模型
  2. 提取回归残差作为中性化后的因子值
import statsmodels.api as sm

def neutralize_factor(factor, industry_dummies, market_cap):
    # 构建自变量矩阵:行业哑变量 + 市值对数
    X = pd.concat([industry_dummies, np.log(market_cap)], axis=1)
    X = sm.add_constant(X)
    # 回归并提取残差
    model = sm.OLS(factor, X).fit()
    return model.resid
中性化要点:
  • 行业中性化:使用申万一级或二级行业分类,每个股票属于且仅属于一个行业
  • 市值中性化:通常使用市值对数而非原始市值,以降低市值分布的偏态影响
  • 中性化应在截面(横截面)上进行,即每个时间点独立处理

3.5 完整处理流程

下图展示了因子计算与标准化的完整处理流程:

因子计算与标准化完整流程 原始市场数据 因子公式计算 去极值处理 MAD法 百分位法 标准化处理 Z-score Rank 中性化处理 行业中性化 市值中性化 标准化因子值

3.6 处理顺序与注意事项

因子处理的顺序至关重要,错误的顺序会导致结果失真。推荐的处理顺序为:

步骤 操作 说明
1 因子计算 根据公式计算原始因子值
2 去极值 使用MAD或百分位法处理极端值
3 标准化 Z-score或Rank标准化,消除量纲
4 中性化 回归残差法剔除行业/市值影响
顺序陷阱:若先中性化再去极值,极端值会通过回归模型影响中性化系数,导致中性化效果变差。若先标准化再去极值,标准化后的均值和标准差会被极端值扭曲。因此,去极值 → 标准化 → 中性化是标准且不可颠倒的顺序。

完成上述全部处理后,得到的因子值即为可用于后续有效性检验和组合构建的标准化因子。该因子值在不同股票之间具有可比性,且剔除了行业和市值的系统性影响,能够更纯粹地反映因子本身的选股能力。