4. 数据准备与清洗:风险数据源梳理、数据质量检查、缺失值与异常值处理、数据标准化

数据准备与清洗是组合风险归因分析中最耗时、最关键的环节。原始风险数据通常来自多个异构系统,包含大量噪声、缺失值和格式不一致问题。本节将系统梳理风险数据源、建立数据质量检查框架,并给出缺失值、异常值处理及标准化的实战方法。

4.1 风险数据源梳理

组合风险归因所需的数据源通常涵盖以下四类:

数据类别 典型数据源 关键字段示例 更新频率
持仓数据 交易系统、托管行、组合管理系统 证券代码、持仓数量、市值、成本价 日频 / 实时
行情数据 Wind、Bloomberg、交易所行情 收盘价、涨跌幅、成交量、波动率 日频 / 分钟频
因子数据 Barra、Axioma、自建因子库 因子暴露、因子收益率、因子协方差 月频 / 日频
基准与分类数据 指数公司、行业分类标准 基准权重、行业代码、风格标签 季度 / 年度
实战建议:建议建立数据源清单(Data Source Inventory),记录每个数据源的接入方式、字段映射关系、历史数据起止日期和已知问题,作为后续数据质量检查的基线文档。

4.2 数据质量检查框架

数据质量检查应覆盖完整性、准确性、一致性和时效性四个维度。以下为推荐的质量检查清单:

  • 完整性检查:检查关键字段是否存在空值,时间序列是否存在断点,证券代码是否在参考表中存在。
  • 准确性检查:验证数值字段是否在合理范围内(如持仓数量 > 0,价格 > 0),计算逻辑是否与源系统一致(如市值 = 持仓数量 × 收盘价)。
  • 一致性检查:跨系统比对同一字段(如交易系统与托管行的持仓市值差异 < 0.1%),检查行业分类代码是否与标准分类一致。
  • 时效性检查:确认数据日期是否为最新交易日,延迟数据是否已标记,历史数据回溯是否完整。
质量检查输出:每次数据更新后应生成数据质量报告(Data Quality Report),包含各维度检查通过率、异常记录明细和处理建议。建议将检查规则固化到自动化脚本中,实现每日自动巡检。
数据质量检查流程 原始风险数据 完整性检查 准确性检查 一致性检查 时效性检查 数据质量报告 通过? 进入清洗流程 人工核查修正

4.3 缺失值与异常值处理

4.3.1 缺失值处理策略

风险数据中的缺失值通常出现在行情数据(停牌、节假日)、因子暴露(新上市证券)或持仓数据(数据延迟)中。根据缺失机制和业务场景,推荐以下处理策略:

缺失类型 典型场景 推荐处理方法 注意事项
完全随机缺失 单日行情数据丢失 前向填充(Forward Fill) 连续缺失不超过3个交易日
随机缺失 部分证券因子暴露缺失 行业均值填充 / 回归插补 需验证填充值对风险贡献的影响
非随机缺失 停牌证券的行情缺失 标记为“停牌”并沿用停牌前价格 复牌后需重新评估价格有效性
结构性缺失 新上市证券无历史因子数据 使用同类证券均值或模型估计 在归因报告中标注为“估计值”
避坑提示:切勿对缺失比例超过30%的字段进行简单填充。此时应优先排查数据源问题,或考虑在分析中剔除该字段。填充后的数据应进行敏感性测试,评估不同填充方法对风险归因结果的影响。

4.3.2 异常值检测与处理

异常值在风险数据中常见于价格错误、因子暴露极端值或持仓数据录入错误。推荐使用以下方法进行检测:

  • Z-Score 方法:计算每个字段的 Z-Score,绝对值大于 3 的标记为异常值。适用于近似正态分布的数据。
  • IQR 方法:计算四分位距(IQR),超出 Q1 - 1.5×IQR 或 Q3 + 1.5×IQR 的标记为异常值。适用于偏态分布。
  • 业务规则法:根据业务常识设定硬阈值,如股票价格不能为负、持仓数量不能超过总股本等。
  • 时间序列方法:对日频数据使用滚动窗口的均值和标准差,检测突变点。

异常值处理策略:

  • 修正:如果能确认正确值(如人工核查),直接替换。
  • 截尾:将异常值替换为阈值上限或下限(Winsorization)。
  • 剔除:在分析中排除该记录,但需记录剔除原因和数量。

4.4 数据标准化

数据标准化是确保不同量纲、不同分布的数据能够进行统一分析的关键步骤。在组合风险归因中,主要涉及以下标准化操作:

标准化类型 公式 适用场景 对风险归因的影响
Z-Score 标准化 z = (x - μ) / σ 因子暴露、收益率序列 保留分布形状,便于跨因子比较
Min-Max 标准化 x' = (x - min) / (max - min) 风险指标、权重数据 将数据映射到 [0,1],便于可视化
排名标准化 rank(x) / N 非正态分布、存在极端值 消除极端值影响,但丢失幅度信息
行业中性化 x - mean(xindustry) 行业因子暴露 消除行业系统性偏差
标准化顺序:建议先处理缺失值和异常值,再进行标准化。标准化参数(均值、标准差、最小值、最大值)应基于训练期数据计算,并应用于全样本,避免未来信息泄露。
数据标准化流程与对比 原始风险数据 缺失/异常值处理 选择标准化方法 Z-Score 标准化 z = (x - μ) / σ Min-Max 标准化 x' = (x - min) / (max - min) 排名标准化 rank(x) / N 标准化后的风险数据 用于风险归因计算与人群切片

4.5 数据清洗实战代码示例

以下 Python 代码展示了数据清洗的核心流程,包括缺失值处理、异常值检测和标准化:

import pandas as pd
import numpy as np
from scipy import stats

# 加载原始风险数据
df = pd.read_csv('risk_data_raw.csv', parse_dates=['date'])

# ========== 1. 缺失值处理 ==========
# 前向填充行情数据(最多连续填充3天)
df['close_price'] = df.groupby('security_id')['close_price'] \
    .transform(lambda x: x.fillna(method='ffill', limit=3))

# 行业均值填充因子暴露
df['factor_exposure'] = df.groupby('industry')['factor_exposure'] \
    .transform(lambda x: x.fillna(x.mean()))

# 标记仍为缺失的记录
df['is_imputed'] = df['factor_exposure'].isna().astype(int)

# ========== 2. 异常值检测 ==========
# Z-Score 方法检测价格异常
z_scores = np.abs(stats.zscore(df['close_price'].dropna()))
df.loc[df['close_price'].notna(), 'price_outlier'] = (z_scores > 3).astype(int)

# IQR 方法检测持仓异常
Q1 = df['holding_value'].quantile(0.25)
Q3 = df['holding_value'].quantile(0.75)
IQR = Q3 - Q1
df['holding_outlier'] = ((df['holding_value'] < Q1 - 1.5*IQR) | 
                         (df['holding_value'] > Q3 + 1.5*IQR)).astype(int)

# 截尾处理异常持仓
upper_limit = Q3 + 1.5*IQR
lower_limit = Q1 - 1.5*IQR
df['holding_value_winsorized'] = df['holding_value'].clip(lower_limit, upper_limit)

# ========== 3. 数据标准化 ==========
# Z-Score 标准化因子暴露
df['factor_exposure_z'] = (df['factor_exposure'] - df['factor_exposure'].mean()) / \
                           df['factor_exposure'].std()

# Min-Max 标准化风险贡献
df['risk_contribution_norm'] = (df['risk_contribution'] - df['risk_contribution'].min()) / \
                                (df['risk_contribution'].max() - df['risk_contribution'].min())

# 输出清洗后的数据质量报告
quality_report = {
    'total_records': len(df),
    'missing_after_fill': df['factor_exposure'].isna().sum(),
    'price_outliers': df['price_outlier'].sum(),
    'holding_outliers': df['holding_outlier'].sum(),
    'standardized_fields': ['factor_exposure_z', 'risk_contribution_norm']
}
print("数据质量报告:", quality_report)
工程化建议:将上述清洗逻辑封装为可复用的数据管道(Data Pipeline),支持增量更新和回溯重算。每次清洗后保存清洗日志(包括处理记录数、方法、参数),便于审计和复现。