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

聚宽因子处理实战:如何对截面因子执行去极值、标准化与行业中性化?

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

问题描述

聚宽因子处理:如何完成去极值、标准化与行业中性化?
如何在聚宽中对 ROE、成长、动量和市值等截面因子执行 Winsorize 去极值、Z-Score 标准化及行业中性化后再进行加权选股?

解决方案

在多因子选股策略中,为了消除量纲影响、极端值干扰以及行业和市值因子的暴露,必须对原始因子进行去极值(Winsorization)、**标准化(Standardization)中性化(Neutralization)**处理。以下是在聚宽(JoinQuant)平台中完成这一标准流程的详细指南及代码实现。

一、 因子预处理三大步骤

  1. 去极值 (Winsorize)

    • 目的:消除市场中极端异常值(如暴涨暴跌或财务数据异常)对整体因子的拉偏影响。
    • 聚宽APIjqfactor.winsorizejqfactor.winsorize_med(中位数去极值)。
  2. 标准化 (Standardize)

    • 目的:将不同量纲的因子(如ROE是百分比,市值是万亿)转换到同一数量级,便于进行加权合成。
    • 聚宽APIjqfactor.standardlize(采用 Z-Score 方法:$(x - \mu) / \sigma$)。
  3. 中性化 (Neutralize)

    • 目的:剔除因子在行业分类和市值大小上的暴露,避免选出来的股票过度集中在某一热门行业或某一市值区间。
    • 聚宽APIjqfactor.neutralize(通过线性回归残差法,对行业哑变量和对数市值进行中性化)。

二、 聚宽代码实战:多因子预处理与加权选股

以下是一个完整的聚宽策略片段,展示了如何获取 roe_ttm(ROE)、growth(成长)、momentum(动量)和 size(市值)因子,并进行预处理后合成综合得分进行选股:

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

def preprocess_factors(context):
    # 1. 定义股票池(以沪深300为例)和目标因子
    stocks = get_index_stocks('000300.XSHG', date=context.previous_date)
    factors = ['roe_ttm', 'growth', 'momentum', 'size']
    
    # 2. 获取因子值(获取前一交易日的数据)
    # get_factor_values 返回 dict, key为因子名,value为DataFrame(index为日期,columns为股票代码)
    factor_data_dict = get_factor_values(
        securities=stocks, 
        factors=factors, 
        start_date=context.previous_date, 
        end_date=context.previous_date
    )
    
    processed_factors = {}
    
    for factor in factors:
        # 提取单日因子数据,转为 Series (index为股票代码)
        raw_series = factor_data_dict[factor].iloc[0]
        
        # 步骤一:Winsorize 去极值 (分位数去极值,保留5%到95%之间)
        clean_series = winsorize(raw_series, qrange=[0.05, 0.95], inclusive=True)
        
        # 步骤二:行业与市值中性化
        # 动量、ROE和成长因子需要剔除行业(jq_l1)和市值(market_cap)的影响
        # 市值因子本身不需要做市值中性化,这里我们对非size因子进行中性化
        if factor != 'size':
            clean_series = neutralize(clean_series, how=['jq_l1', 'market_cap'], date=context.previous_date)
        
        # 步骤三:Z-Score 标准化
        final_series = standardlize(clean_series)
        
        processed_factors[factor] = final_series
        
    # 3. 构建多因子DataFrame
    df = pd.DataFrame(processed_factors)
    
    # 4. 因子合成(等权重加权,注意:size因子通常作为风险控制,若作为Alpha,小市值通常给负权重)
    # 综合得分 = ROE + 成长 + 动量 - 市值(偏好小市值)
    df['score'] = df['roe_ttm'] * 0.3 + df['growth'] * 0.3 + df['momentum'] * 0.3 - df['size'] * 0.1
    
    # 5. 排序并选择前10只股票
    buy_list = df['score'].sort_values(ascending=False).head(10).index.tolist()
    
    return buy_list

三、 核心注意事项

  1. 避免未来函数:在回测或模拟盘中,获取因子值时,start_dateend_date 必须设为 context.previous_date(前一交易日),切勿使用 context.current_dt,因为当前交易日的日频因子在盘中尚未生成。
  2. 中性化依赖数据neutralize 函数依赖当天的行业分类和市值数据。如果传入的 date 对应的数据缺失(例如非交易日),函数将直接返回原始数据而不进行中性化。
  3. 停牌股处理:在实际选股前,建议先过滤掉停牌股(可通过 get_current_data() 获取 paused 属性),避免将资金浪费在无法交易的标的上。