问题描述
解决方案
在聚宽(JoinQuant)平台中,对因子数据进行 Z-Score 标准化(即去均值后除以标准差,使数据均值为0,标准差为1),最直接且推荐的方法是使用 jqfactor 库中的 standardlize 函数。
Z-Score 标准化方法
1. 使用 jqfactor.standardlize 函数(推荐)
这是聚宽专门为因子处理提供的函数,能够自动处理 inf(无穷大)值,并支持按行(截面)或按列(时间序列)进行标准化。
函数说明:
standardlize(data, inf2nan=True, axis=1)
- data: 输入的
pd.Series或pd.DataFrame。 - inf2nan: 是否将
inf替换为NaN(默认为True,推荐开启以避免计算错误)。 - axis:
1:对每行做标准化(通常用于截面标准化,即同一时间点下不同股票间的标准化)。0:对每列做标准化(通常用于时间序列标准化,即同一股票在不同时间点间的标准化)。
2. 代码示例
以下代码展示了如何获取沪深300成分股的市值数据,并对其进行 Z-Score 标准化处理。
# -*- coding: utf-8 -*-
from jqdata import *
from jqfactor import standardlize
import pandas as pd
import numpy as np
def initialize(context):
# 设定基准
set_benchmark('000300.XSHG')
# 运行函数
run_daily(factor_process, '09:30')
def factor_process(context):
# 1. 获取数据:以沪深300成分股的“总市值”为例
stocks = get_index_stocks('000300.XSHG')
# 获取市值数据 (market_cap)
q = query(
valuation.code,
valuation.market_cap
).filter(
valuation.code.in_(stocks)
)
df = get_fundamentals(q, date=context.previous_date)
# 将股票代码设为索引,方便处理
if not df.empty:
df.set_index('code', inplace=True)
# 获取因子序列 (Series类型)
raw_factor = df['market_cap']
# 2. 执行 Z-Score 标准化
# 对于 Series,standardlize 会直接计算 (x - mean) / std
std_factor = standardlize(raw_factor, inf2nan=True)
# 打印结果对比
print("--- 原始因子前5行 ---")
print(raw_factor.head())
print("\n--- Z-Score标准化后前5行 ---")
print(std_factor.head())
# 验证标准化结果(均值应接近0,标准差应接近1)
print(f"\n标准化后均值: {std_factor.mean():.4f}")
print(f"标准化后标准差: {std_factor.std():.4f}")
else:
print("未获取到数据")
补充说明:手动实现
如果你不想使用 jqfactor 库,也可以利用 pandas 原生方法实现 Z-Score 标准化,公式为 $z = \frac{x - \mu}{\sigma}$。
# 手动实现 Z-Score (针对 Series)
mean_val = raw_factor.mean()
std_val = raw_factor.std()
z_score_factor = (raw_factor - mean_val) / std_val
但在聚宽环境中,建议优先使用 jqfactor.standardlize,因为它额外处理了边界情况(如无穷大值),在量化回测中更加稳健。
Q&A
Q: 为什么要对因子进行 Z-Score 标准化?
A: 不同因子的量纲(单位)和数量级差异很大(例如股价可能是几十元,而市值可能是几百亿)。标准化可以将不同分布的因子转换为同一尺度(均值为0,标准差为1),从而使它们具有可比性,便于后续进行多因子合成或机器学习模型训练。
Q: standardlize 函数中的 axis=1 和 axis=0 有什么区别?
A: 当输入数据是 DataFrame 时:
axis=1表示截面标准化(Cross-sectional),即在同一时间点上,对所有股票的因子值进行标准化。这是多因子选股中最常用的方式。axis=0表示时间序列标准化(Time-series),即对单只股票在一段时间内的因子值进行标准化。
Q: 标准化之前需要去极值吗?
A: 通常建议先去极值,再标准化。因为 Z-Score 使用均值和标准差,这两个统计量对异常值(Outliers)非常敏感。如果数据中存在极端的异常值,会拉大标准差,导致正常数据的标准化值被压缩在很小的范围内。可以使用 jqfactor.winsorize 先进行去极值处理。