3. IC的数据准备:因子数据清洗、收益率数据对齐、缺失值处理、异常值处理
IC(Information Coefficient,信息系数)分析的质量高度依赖底层数据的洁净度与对齐精度。原始因子数据和收益率数据通常包含大量噪声、缺失和极端值,若不经处理直接计算IC,会导致虚假相关或信号衰减。本节系统梳理IC分析前的数据准备流程,涵盖因子数据清洗、收益率对齐、缺失值处理与异常值处理四个核心环节。
3.1 因子数据清洗
因子数据清洗的目标是消除原始数据中的明显错误、重复记录和格式不一致问题。常见清洗步骤包括:
| 清洗步骤 | 说明 | 典型操作 |
|---|---|---|
| 去重 | 同一股票同一交易日出现多条因子记录 | 按股票代码+交易日期去重,保留最新或均值 |
| 格式统一 | 股票代码、日期格式、数值类型不一致 | 统一为字符串代码、YYYY-MM-DD日期、float64数值 |
| 逻辑校验 | 因子值超出合理范围(如市盈率为负但未标注) | 设定行业或历史合理区间,标记或剔除 |
| 行业/市值标签对齐 | 因子数据与行业分类、市值数据版本不匹配 | 使用统一数据库的行业映射表进行关联 |
实践建议:因子清洗应在原始数据库层面建立自动化校验脚本,每次更新数据后自动执行去重、格式检查和逻辑校验,避免人工重复劳动。
3.2 收益率数据对齐
IC分析通常计算因子值与未来一期(如T+1日、T+5日)收益率之间的截面秩相关。收益率数据必须与因子数据在时间戳和股票维度上精确对齐。
- 时间对齐:因子值通常使用交易日收盘数据,收益率需使用对应股票在因子值日期之后的下一个交易日的收益率(或持有期收益率)。
- 股票对齐:仅保留因子数据和收益率数据中都存在的股票,剔除停牌、退市或数据缺失的股票。
- 复权处理:收益率应使用后复权价格计算,以准确反映真实投资回报,避免分红、送股导致的收益率失真。
对齐示例:若因子数据日期为2024-01-05(周五),则T+1收益率应为2024-01-08(下周一)的收益率;若计算T+5收益率,则持有期覆盖2024-01-08至2024-01-12共5个交易日。
3.3 缺失值处理
因子数据中缺失值普遍存在,处理方式直接影响IC计算的样本量和稳定性。常见缺失值处理方法包括:
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 直接删除 | 缺失比例低(<5%) | 简单、无偏差引入 | 损失样本量 |
| 截面均值/中位数填充 | 因子分布相对稳定 | 保留样本量 | 可能压缩因子方差 |
| 行业均值填充 | 因子存在行业差异 | 保留行业特征 | 需行业标签完整 |
| 前向填充(ffill) | 时间序列因子 | 利用历史信息 | 不适用于突变因子 |
| 模型预测填充 | 缺失比例较高 | 精度较高 | 计算复杂、有过度拟合风险 |
注意:缺失值处理应在因子标准化之前进行。若先标准化再填充,会扭曲因子分布特征,导致IC计算偏差。建议按“清洗 → 缺失填充 → 异常值处理 → 标准化”的顺序执行。
3.4 异常值处理
因子数据中的极端值会主导IC计算结果,使秩相关系数失真。异常值处理的核心目标是降低极端值的影响,同时保留有效信号。
- MAD(中位数绝对偏差)法:以中位数为中心,剔除超过中位数±N倍MAD的样本。N通常取3~5,对厚尾分布更稳健。
- 百分位截断法:将因子值上下各1%或0.5%的极端值截断为边界值,保留样本量但压缩极端值。
- 分位数缩尾法(Winsorize):将超出指定百分位(如1%~99%)的因子值替换为该百分位的边界值,而非直接删除。
- 行业分组处理:在行业内分别进行异常值处理,避免行业间因子分布差异导致的误判。
3.5 数据准备完整流程代码示例
以下Python代码展示了因子数据清洗、收益率对齐、缺失值填充和异常值处理的典型实现:
import pandas as pd
import numpy as np
# 1. 因子数据清洗
def clean_factor_data(df):
# 去重:按股票代码+交易日期保留最后一条
df = df.drop_duplicates(subset=['stock_code', 'trade_date'], keep='last')
# 格式统一:日期转为datetime
df['trade_date'] = pd.to_datetime(df['trade_date'])
# 逻辑校验:剔除因子值为负但未标注的异常记录
df = df[(df['factor_value'] >= 0) | (df['factor_value'].isna())]
return df
# 2. 收益率对齐(T+1)
def align_returns(factor_df, return_df):
# 将收益率数据向前移动一天,实现T+1对齐
return_df['next_date'] = return_df.groupby('stock_code')['trade_date'].shift(-1)
merged = pd.merge(factor_df, return_df, left_on=['stock_code', 'trade_date'],
right_on=['stock_code', 'next_date'], how='inner')
return merged
# 3. 缺失值处理(行业均值填充)
def fill_missing_by_sector(df, factor_col, sector_col):
sector_mean = df.groupby(sector_col)[factor_col].transform('mean')
df[factor_col] = df[factor_col].fillna(sector_mean)
return df
# 4. 异常值处理(MAD法)
def mad_outlier_removal(df, factor_col, n=3):
median = df[factor_col].median()
mad = np.median(np.abs(df[factor_col] - median))
lower = median - n * mad
upper = median + n * mad
df = df[(df[factor_col] >= lower) & (df[factor_col] <= upper)]
return df
# 执行完整流程
factor_data = pd.read_csv('factor_data.csv')
return_data = pd.read_csv('return_data.csv')
factor_data = clean_factor_data(factor_data)
merged_data = align_returns(factor_data, return_data)
merged_data = fill_missing_by_sector(merged_data, 'factor_value', 'sector')
merged_data = mad_outlier_removal(merged_data, 'factor_value', n=4)
关键参数说明:MAD法中的n值选择需结合因子分布特征。对于正态分布因子,n=3可剔除约0.3%的极端值;对于厚尾分布因子,建议n=4~5以避免过度剔除有效信号。建议在正式分析前对n值进行敏感性测试。
3.6 数据准备质量检查清单
完成数据准备后,建议逐项检查以下指标,确保数据质量满足IC分析要求:
| 检查项 | 合格标准 | 检查方法 |
|---|---|---|
| 缺失率 | 整体缺失率 < 10%,单截面缺失率 < 20% | 按交易日统计缺失比例 |
| 异常值比例 | 处理后异常值比例 < 1% | 统计超出MAD边界或百分位边界的样本数 |
| 时间对齐精度 | 因子日期与收益率日期严格相差1个交易日 | 检查日期差值的唯一性 |
| 股票覆盖稳定性 | 每期股票数量波动 < 10% | 按交易日统计股票数量并计算变异系数 |
| 因子分布形态 | 处理后因子偏度 < 2,峰度 < 10 | 计算偏度和峰度统计量 |
数据准备是IC分析中最耗时但最关键的环节。经过系统清洗、对齐、缺失填充和异常值处理后的因子数据,能够显著提升IC计算的稳定性和可解释性,为后续分层测试和因子筛选奠定可靠基础。