🚀 AI 一键生成 joinquant 策略代码
立即体验
👉 AI 生成代码 👈

量化交易中因子标准化与中性化的先后顺序及原理解析

joinquant | 发布时间: 2026/6/1
以下内容由 EasyQuant 生成。

问题描述

标准化和中性化的顺序

请问在对因子进行行业和市值做中性化的时候

问题1
标准化的操作是在中性化之前做
还是在中性化之后做?

问题2
如果先做标准化,那中性化以后数据的分布岂不是又变成非正态的了吗?

解决方案

这是一个在多因子模型构建中非常经典且重要的问题。在实际的量化投研中,因子的预处理顺序对最终的因子表现有显著影响。以下是对您两个问题的详细解答:

问题1:标准化的操作是在中性化之前做,还是在中性化之后做?

标准答案是:中性化之前和之后都需要做标准化(通常还伴随着去极值)。

业界标准的单因子预处理流水线(Pipeline)通常是这样的:
去极值 (Winsorize) -> 标准化 (Standardize) -> 中性化 (Neutralize) -> 再次标准化 (Standardize)

为什么要在中性化之前做标准化?
中性化的本质是横截面上的多元线性回归(OLS)。我们将原始因子作为因变量 $Y$,将行业哑变量和市值(通常是对数市值)作为自变量 $X$ 进行回归,取其残差 $\epsilon$ 作为中性化后的新因子。
如果在此之前不做去极值和标准化:

  1. 极值影响:线性回归对异常值(Outliers)非常敏感,极值会严重扭曲回归系数,导致算出来的残差失去意义。
  2. 量纲问题:不同因子的量纲差异巨大,标准化可以消除量纲影响,使得回归过程更加稳定。

问题2:如果先做标准化,那中性化以后数据的分布岂不是又变成非正态的了吗?

您的直觉非常敏锐,完全正确!

中性化(回归取残差)之后,虽然残差的均值在理论上会接近于0,但其标准差(方差)通常不再是1。此外,剥离了行业和市值的影响后,数据原本的分布形态确实会发生改变,不再是严格的标准正态分布。

如何解决这个问题?
这就是为什么在标准的数据处理流水线中,在中性化之后,我们通常会再进行一次标准化(甚至再做一次去极值+标准化)

二次标准化的目的在于:

  1. 统一量纲:将中性化后的残差重新缩放到均值为0、标准差为1的尺度上,方便后续将多个因子进行等权或加权合成(如果不做二次标准化,不同因子的方差不同,直接相加会导致方差大的因子占据主导地位)。
  2. 恢复分布:使其在横截面上重新符合标准正态分布的特征,满足后续优化器或打分模型对数据分布的假设。

附:在 JoinQuant (聚宽) 平台上的代码实现

在 JoinQuant 平台上,可以使用 jqfactor 库中提供的内置函数来优雅地完成这一套流水线:

import pandas as pd
import numpy as np
from jqfactor import winsorize, standardlize, neutralize
from jqdata import get_index_stocks

# 假设 data 是一个 DataFrame,index 为因子名称,columns 为股票代码
# 这里以随机生成的数据为例
stocks = get_index_stocks('000300.XSHG', date='2023-01-01')
data = pd.DataFrame(np.random.randn(1, len(stocks)), columns=stocks, index=['my_factor'])

# 1. 去极值 (例如取 5% 和 95% 分位数)
data_win = winsorize(data, qrange=[0.05, 0.95], axis=1)

# 2. 第一次标准化 (Z-score)
data_std1 = standardlize(data_win, axis=1)

# 3. 中性化 (行业 jq_l1 和 市值 market_cap)
# 注意:neutralize 函数内部会自动获取 date 对应的市值和行业数据进行回归
data_neu = neutralize(data_std1, how=['jq_l1', 'market_cap'], date='2023-01-01', axis=1)

# 4. 第二次标准化 (恢复 N(0,1) 分布)
final_factor = standardlize(data_neu, axis=1)

总结:先去极值和标准化是为了保证中性化(回归)的准确性和稳定性;中性化后再次标准化是为了消除回归带来的方差缩放,保证最终因子在横截面上的可比性和可合成性。