4. 数据清洗与预处理:缺失值处理、异常值检测、数据对齐、时间序列重采样

绩效归因分析的可靠性高度依赖输入数据的质量。原始金融时间序列通常包含缺失观测、极端报价、不同频率的数据源以及非对齐的时间戳。本章将系统讲解数据清洗与预处理的四个核心环节,确保后续模型训练建立在干净、连续、对齐的数据基础之上。

核心原则: 在金融量化领域,数据预处理不是一次性任务,而是与特征工程、模型迭代并行的持续过程。每次数据切分前都应重新执行清洗流程,避免数据泄露。

4.1 缺失值处理

金融数据缺失的常见原因包括:非交易日、停牌、数据源中断、合并调整延迟等。处理策略需根据缺失模式(随机缺失、完全随机缺失、非随机缺失)和业务场景选择。

处理方法 适用场景 优点 缺点
前向填充(ffill) 价格、收益率序列 保持时间连续性,符合市场逻辑 可能掩盖真实波动
后向填充(bfill) 数据起始段缺失 简单快速 引入未来信息风险
线性插值 短期缺失(1-3个时间步) 平滑过渡,保留趋势 不适用于跳跃性数据
模型预测填充 长期缺失或关键因子 精度较高 计算成本高,需独立验证
删除缺失行 缺失比例极低(<1%) 无偏差引入 损失样本量
import pandas as pd
import numpy as np

# 示例:日频收益率缺失值处理
price_df = pd.read_csv('daily_prices.csv', index_col=0, parse_dates=True)
returns = price_df.pct_change().dropna(how='all')

# 策略1:前向填充(适用于价格)
price_ffill = price_df.fillna(method='ffill')

# 策略2:线性插值(适用于短期缺失)
returns_interp = returns.interpolate(method='linear', limit=3)

# 策略3:按资产分组填充(多标的场景)
returns_grouped = returns.groupby('asset_id').apply(
    lambda x: x.fillna(method='ffill').fillna(method='bfill')
)
避坑提示: 使用 fillna(method='ffill') 时,务必先按资产或因子分组,避免跨标的错误填充。对于停牌数据,建议保留缺失标记而非直接填充,以便后续归因时识别。

4.2 异常值检测

异常值可能源于数据录入错误、市场极端事件或模型假设失效。在绩效归因中,异常值会扭曲因子暴露和收益分解结果。常用检测方法包括统计阈值法和机器学习法。

  • Z-Score 方法: 假设数据服从正态分布,将 |Z| > 3 的观测标记为异常。适用于收益率、波动率等近似对称分布。
  • IQR 方法: 基于四分位距,将低于 Q1-1.5×IQR 或高于 Q3+1.5×IQR 的值视为异常。对偏态分布更稳健。
  • 滚动窗口法: 在时间序列上使用滚动均值和标准差,检测局部异常。适合捕捉结构性突变。
  • 孤立森林: 无监督集成方法,适合高维因子数据的异常检测。
# IQR 异常值检测示例
def detect_outliers_iqr(series, factor=1.5):
    Q1 = series.quantile(0.25)
    Q3 = series.quantile(0.75)
    IQR = Q3 - Q1
    lower_bound = Q1 - factor * IQR
    upper_bound = Q3 + factor * IQR
    return (series < lower_bound) | (series > upper_bound)

# 滚动窗口异常检测(窗口20天)
rolling_mean = returns.rolling(20).mean()
rolling_std = returns.rolling(20).std()
z_scores = (returns - rolling_mean) / rolling_std
outliers = z_scores.abs() > 3

# 处理策略:截断(Winsorize)而非直接删除
returns_clipped = returns.clip(
    lower=returns.quantile(0.01),
    upper=returns.quantile(0.99),
    axis=1
)
异常值检测流程与处理策略 原始时间序列 Z-Score 方法 IQR 方法 滚动窗口法 孤立森林 异常值标记 截断(Winsorize) 替换为NaN后插值 删除(谨慎使用)

4.3 数据对齐

绩效归因通常需要合并多个数据源:日频收益率、月频因子暴露、季频财务报表、周频行业分类。不同频率的数据必须对齐到统一的时间戳网格上,否则归因计算会产生偏差。

对齐策略:
  • 左连接(Left Join): 以收益率时间序列为主表,其他数据向左对齐。这是最常用的策略,确保归因窗口完整。
  • 前向填充对齐: 低频数据(如因子暴露)在合并时使用前向填充,直到下一个有效观测。
  • 重采样对齐: 将不同频率数据统一重采样到目标频率(如将日频转为周频)。
# 多源数据对齐示例
returns_daily = pd.read_csv('returns_daily.csv', index_col=0, parse_dates=True)
factor_exposure_monthly = pd.read_csv('factor_exposure_monthly.csv', index_col=0, parse_dates=True)

# 策略1:左连接 + 前向填充
aligned = returns_daily.join(factor_exposure_monthly, how='left')
aligned = aligned.fillna(method='ffill')

# 策略2:重采样到统一频率(日频转周频)
returns_weekly = returns_daily.resample('W-FRI').apply(
    lambda x: (1 + x).prod() - 1
)

# 策略3:使用 reindex 对齐到指定日历
trading_calendar = pd.date_range('2023-01-01', '2023-12-31', freq='B')
aligned_calendar = factor_exposure_monthly.reindex(trading_calendar, method='ffill')

4.4 时间序列重采样

重采样是将时间序列从一种频率转换为另一种频率的过程。在绩效归因中,重采样用于统一归因周期(如将日频归因汇总为月频报告)、降噪以及匹配不同数据源的频率。

重采样类型 方法 金融应用场景
降采样(高频→低频) 聚合函数(sum, mean, prod) 日收益率→月收益率;分钟波动率→日波动率
升采样(低频→高频) 插值或填充 月因子暴露→日因子暴露(需谨慎)
对齐到特定日历 reindex + 填充 将非交易日数据对齐到交易日历
# 重采样操作示例
import pandas as pd

# 日频收益率数据
dates = pd.date_range('2023-01-01', '2023-12-31', freq='B')
returns = pd.Series(np.random.randn(len(dates)) * 0.02, index=dates)

# 降采样:日频→月频(复合收益率)
monthly_returns = returns.resample('M').apply(
    lambda x: (1 + x).prod() - 1
)

# 降采样:日频→周频(最后一个交易日)
weekly_last = returns.resample('W-FRI').last()

# 升采样:月频→日频(前向填充)
monthly_index = pd.date_range('2023-01-31', '2023-12-31', freq='M')
monthly_data = pd.Series([0.01, 0.02, -0.005, 0.015], index=monthly_index[:4])
daily_index = pd.date_range('2023-01-31', '2023-04-30', freq='B')
daily_data = monthly_data.reindex(daily_index, method='ffill')
时间序列重采样流程 原始高频数据(日频) 重采样决策 降采样 日频→周频/月频 升采样 月频→日频 日历对齐 非交易日→交易日 统一频率的对齐数据
最佳实践:
  1. 始终保留原始数据副本,清洗流程可重复执行。
  2. 对缺失值和异常值的处理记录日志,便于审计和回溯。
  3. 数据对齐后,检查对齐后的时间戳数量是否与预期一致。
  4. 重采样时注意金融日历的特殊性(如非交易日、月末效应)。
常见陷阱:
  • 升采样时使用线性插值可能引入未来信息,应优先使用前向填充。
  • 异常值检测的阈值(如 Z-Score 的 3 倍标准差)应根据资产类别调整,固定收益与权益的波动特征不同。
  • 多标的对齐时,注意不同标的的交易日历可能不同(如 A 股与港股)。