3. 金融数据与特征工程

在金融模型验证与Optuna调优的完整链路中,特征工程决定了模型性能的上限,而数据清洗决定了这个上限是否可信。金融数据与通用机器学习数据集有本质差异:它同时具有时序依赖性、截面相关性、低信噪比、非平稳性四大特征。本节围绕数据清洗、缺失值处理、异常值检测、时序特征、截面特征与金融因子构建六个环节,建立一套可复现、可验证的特征工程流程。

一、核心原理:金融数据的四类"污染源"

金融原始数据在进入模型前,通常携带四类污染:缺失(停牌、未上市、数据源断档)、异常(涨跌停、乌龙指、复权错误)、不一致(不同数据源口径差异)、前视偏差(使用了未来信息)。其中前视偏差最隐蔽也最致命——例如用当日收盘价计算的特征去预测当日收益,回测曲线会异常漂亮,实盘却完全失效。

关键原则:任何特征在时刻 t 的取值,只能依赖 t 及之前可获得的信息。财务数据还需考虑公告滞后(如年报通常在次年4月底前披露),必须按"公告日"而非"报告期"对齐。

二、方法流程:六步特征工程流水线

下图展示了从原始行情到因子矩阵的完整数据流,注意清洗与特征构建是交替迭代的,而非一次性线性过程。

金融特征工程数据流 原始行情/财务 OHLCV·财报·公告 清洗与对齐 复权·去重·时区 缺失/异常处理 前向填充·MAD 特征构建 时序·截面·因子 前视偏差检查点 公告日对齐 · 滚动窗口只用历史 · 标签错位验证 标准化因子矩阵 截面去极值 → 标准化 → 中性化 → 缺失填充

三、关键环节与代码实践

1. 缺失值处理

金融时序缺失不能简单用均值填充。停牌导致的缺失应前向填充(保留最后有效价格),而财务指标缺失需区分"未披露"与"不适用"。推荐策略:

  • 价格类:前向填充 + 标记停牌标志位
  • 财务类:按公告日前向填充,缺失超过两期则剔除
  • 截面因子:行业中位数填充,避免均值被极端值拉偏

2. 异常值检测

金融数据中异常值可能是噪声,也可能是真实信号(如涨停)。推荐使用MAD(中位数绝对偏差)而非3σ,因为收益率分布厚尾,σ本身就被异常值污染。

import numpy as np
import pandas as pd

def mad_winsorize(s, n=5):
    """按MAD对截面因子做缩尾处理"""
    med = s.median()
    mad = (s - med).abs().median()
    if mad == 0:
        return s
    upper = med + n * 1.4826 * mad
    lower = med - n * 1.4826 * mad
    return s.clip(lower, upper)

# 对每个交易日的截面因子分组处理
factor_df = factor_df.groupby('date')['value'].transform(mad_winsorize)

3. 时序特征与截面特征

时序特征刻画单只标的的历史演化,如动量、波动率、换手率变化;截面特征刻画同一时刻不同标的的相对位置,如排名、分位数、行业中性化后的暴露。二者结合才能构建稳健因子。

特征类型典型构造窗口/维度常见陷阱
时序动量过去20日收益率时间窗口未复权导致跳空
时序波动收益率滚动标准差20/60日未年化、未对齐
截面排名因子值在当日全市场分位截面未剔除ST/新股
行业中性因子减去行业均值行业×日期行业分类变更未处理
财务因子ROE、营收增速季度公告日对齐错误

4. 金融因子构建

因子构建的核心是经济逻辑 + 统计验证。以动量因子为例,需先做截面标准化与中性化,再检验IC、IR与换手率。Optuna调优时,因子的窗口参数(如动量回看期)本身就是重要超参数。

# 因子标准化与中性化流程
def build_factor(df):
    df['rank'] = df.groupby('date')['raw'].rank(pct=True)
    df['zscore'] = df.groupby('date')['rank'].transform(
        lambda x: (x - x.mean()) / x.std())
    # 行业中性化:减去行业均值
    df['neutral'] = df['zscore'] - df.groupby(
        ['date', 'industry'])['zscore'].transform('mean')
    return df
验证提示:因子构建完成后,务必用样本外数据检验IC衰减。若IC在样本外骤降,通常是过拟合或前视偏差所致,而非因子本身无效。

四、误区与复盘

高频误区一:用未来数据填充缺失。例如用后向填充(bfill)处理财务数据,等于把未来公告信息泄露到当前。正确做法是仅用前向填充,并记录缺失标志。
高频误区二:全样本标准化。对因子做全局z-score会引入未来信息。必须按交易日截面分别标准化,或使用扩展窗口(expanding)标准化。

复盘一个真实场景:某策略在回测中夏普比率高达3.2,实盘却亏损。排查发现,因子构建时使用了df.fillna(method='bfill'),导致停牌期间的价格被未来复牌价填充,回测中"提前"获得了复牌信息。修正为前向填充后,夏普降至1.1,与实盘一致。这说明数据清洗的每一个选择都必须通过前视偏差检查。

另一个常见问题是异常值处理过度。将涨停板全部缩尾会抹掉真实的动量信号。建议对价格类异常保留但标记,对财务类异常做缩尾,并在Optuna调优中将缩尾阈值作为可搜索参数。

本节小结:金融特征工程的本质是在"保留信号"与"去除噪声"之间寻找平衡。清洗、缺失、异常、时序、截面、因子六个环节环环相扣,任何一步引入前视偏差都会让后续的模型验证与Optuna调优失去意义。建议将上述流程封装为可配置的Pipeline,并把关键参数(窗口长度、缩尾倍数、填充策略)纳入Optuna搜索空间,实现特征工程与超参数调优的联合优化。