4. 因子标准化
任务目标
对单期截面因子数据完成三条预处理链路:去极值(MAD法)、标准化(z-score)与缺失值填充(截面中位数),并验证处理后因子分布的稳定性。本案例使用随机生成的模拟截面数据,聚焦于处理逻辑本身,不涉及具体选股策略。
实现代码
import numpy as np
import pandas as pd
def mad_winsorize(series: pd.Series, n: float = 3.0) -> pd.Series:
"""MAD去极值:将超出中位数±n*1.4826*MAD的值截断至边界"""
median = series.median()
mad = (series - median).abs().median()
if mad == 0:
return series.copy()
upper = median + n * 1.4826 * mad
lower = median - n * 1.4826 * mad
return series.clip(lower, upper)
def zscore_standardize(series: pd.Series) -> pd.Series:
"""z-score标准化:去均值后除以标准差"""
return (series - series.mean()) / series.std()
def process_cross_section(df: pd.DataFrame, factor_col: str) -> pd.DataFrame:
"""
对单期截面因子执行完整预处理
流程:去极值 → 缺失值填充(中位数) → 标准化
返回含原始列与处理列的新DataFrame
"""
result = df.copy()
raw = result[factor_col]
# 1. 去极值(基于原始非缺失值计算边界)
winsorized = mad_winsorize(raw.dropna())
# 2. 缺失值填充:用去极值后的中位数填充
fill_value = winsorized.median()
filled = raw.fillna(fill_value)
# 3. 标准化(对填充后的完整序列)
standardized = zscore_standardize(filled)
result[f'{factor_col}_winsorized'] = winsorized.reindex(result.index)
result[f'{factor_col}_processed'] = standardized
return result
# ========== 最小可复现示例 ==========
if __name__ == '__main__':
# 构造含缺失值与极端值的模拟截面数据(50只股票)
np.random.seed(42)
n = 50
raw_factor = np.random.normal(0, 1, n)
raw_factor[5] = 15.0 # 人为极端值
raw_factor[10] = -12.0 # 人为极端值
raw_factor[[15, 20, 35]] = np.nan # 人为缺失值
df = pd.DataFrame({'stock_id': range(n), 'factor': raw_factor})
# 执行预处理
out = process_cross_section(df, 'factor')
# 验证输出
processed = out['factor_processed']
print(f"处理前缺失数: {df['factor'].isna().sum()}")
print(f"处理后缺失数: {processed.isna().sum()}")
print(f"处理后均值: {processed.mean():.4f}")
print(f"处理后标准差: {processed.std():.4f}")
print(f"处理后最小值: {processed.min():.4f}")
print(f"处理后最大值: {processed.max():.4f}")
print("\n前5行结果:")
print(out.head())
运行与验证
运行方式:直接执行脚本(需安装 numpy 与 pandas):
python factor_preprocess.py
通过条件:输出应满足以下全部判定:
- 处理后缺失数为 0(缺失值已被中位数填充);
- 处理后均值接近 0(|mean| < 0.05),标准差接近 1(0.9 ~ 1.1);
- 处理后最大/最小值落在约 [-3, 3] 区间内(极端值已被截断至MAD边界);
- 原始极端值(索引5、10)与缺失值(索引15、20、35)所在行均存在有效的
factor_processed值。
关键说明
- MAD系数1.4826:使MAD与正态分布下的标准差一致,保证去极值边界具有统计可比性。
- 填充顺序:先基于非缺失值计算去极值边界,再用去极值后的中位数填充缺失,避免极端值污染填充值。
- 标准化时机:必须在填充完成后进行,否则缺失值会导致均值和标准差计算偏差。
- 多期截面扩展:本案例处理单期截面;若需处理多期,应按日期分组后逐期调用
process_cross_section,避免未来数据泄漏。