4. 切片数据准备:数据清洗与预处理、切片标签生成、时间序列对齐、异常值处理

切片数据的质量直接决定人群复盘结论的可靠性。原始数据通常来自交易系统、估值系统与外部行情源,存在缺失、重复、时间戳不一致、极端值等问题。本章聚焦于将原始数据转化为可用于切片归因的“干净面板数据”,涵盖四个核心步骤:清洗与预处理、标签生成、时间序列对齐、异常值处理。

4.1 数据清洗与预处理

清洗阶段的目标是消除数据中的系统性错误与噪声,确保后续切片操作不会因底层数据缺陷而产生偏差。主要操作包括:

  • 缺失值处理:对于持仓市值、收益率等关键数值字段,若缺失比例低于5%,采用前向填充(ffill)或线性插值;若缺失比例过高,则标记为“无效切片”并剔除。
  • 重复记录去重:按“组合代码+证券代码+交易日”联合主键去重,保留最后更新时间戳的记录。
  • 数据类型统一:将日期字段统一为YYYY-MM-DD格式,收益率字段统一为小数形式(如0.0325),避免因格式混用导致计算错误。
  • 字段标准化:行业分类、风格因子等标签字段需映射至统一编码体系(如申万一级行业、Barra风格因子)。
实践要点:清洗逻辑应封装为可复用的函数,并在每次切片复盘前自动执行。建议保留清洗前后的数据量统计,用于评估数据质量对切片结果的影响。

4.2 切片标签生成

切片标签是人群划分的依据,需根据复盘目标从原始数据中衍生或映射生成。标签分为静态标签与动态标签两类:

标签类型 示例 生成方式 更新频率
静态标签 组合类型、投资经理、托管机构 从组合主数据表直接映射 低频(月度/季度)
动态标签 风格暴露(价值/成长)、行业偏离度、持仓集中度 基于持仓与因子模型计算 高频(日度/周度)
复合标签 高动量+低波动、大盘价值、小盘成长 多标签交叉组合 按复盘周期重算

标签生成需注意以下规则:

  • 可回溯性:标签生成逻辑必须使用切片时点的已知信息,避免未来函数。
  • 分层粒度:标签取值不宜过多(建议单维度不超过10个分类),否则切片后样本量过小,统计意义下降。
  • 缺失标签处理:对于无法生成标签的样本,归入“未分类”切片,并在复盘报告中单独说明。
切片标签生成流程 原始持仓/交易数据 因子暴露计算 标签映射与编码 静态标签映射 动态标签计算 复合标签交叉 切片标签数据集 标签需具备可回溯性 避免未来函数

4.3 时间序列对齐

不同数据源的时间戳粒度可能不一致:交易数据按交易日、估值数据按自然日、因子数据按周度更新。时间序列对齐的目的是将所有切片数据统一到相同的时频上,避免因时间错位导致归因偏差。

对齐策略选择:

  • 降频对齐:将高频数据聚合至低频(如日度→周度),适用于切片周期较长(月度/季度)的复盘。
  • 升频对齐:将低频数据插值至高频(如周度→日度),适用于需要捕捉短期切片切换的场景。
  • 事件对齐:以关键事件(如调仓日、分红日)为锚点,对齐前后窗口的数据。
推荐做法:在切片复盘中优先采用“降频对齐+事件窗口”的组合策略。即:将日度数据聚合为周度,同时保留调仓日前后3个交易日的切片快照,用于分析调仓行为对收益的影响。

4.4 异常值处理

异常值会扭曲切片统计量(如均值、标准差),导致人群对比结论失真。异常值检测需结合业务逻辑与统计方法:

检测方法 适用场景 阈值设定 处理方式
Z-Score法 收益率、波动率等近似正态分布指标 |Z| > 3 截尾处理(Winsorize)
IQR四分位法 持仓市值、换手率等偏态分布指标 Q1 - 1.5×IQR 或 Q3 + 1.5×IQR 替换为边界值
业务规则法 日收益率超过±20%、持仓占比超过100% 根据市场规则设定硬边界 标记为“数据异常”并剔除
注意:异常值处理不应一刀切。对于因市场极端行情(如2020年3月、2024年2月)产生的真实极端收益,应保留并单独标注,而非直接剔除。建议在切片数据集中增加“异常标记”字段,供后续复盘时选择性过滤。
异常值处理决策流程 原始切片数据 是否异常? 业务规则判断 真实极端值 vs 数据错误 保留至切片数据集 无需处理 清洗后切片面板数据

4.5 数据准备清单与代码示例

以下为切片数据准备的完整操作清单,建议在每次复盘前按序执行:

  1. 数据加载:读取组合持仓表、交易流水表、因子暴露表、基准指数表。
  2. 字段校验:检查必填字段(组合代码、证券代码、交易日、市值、收益率)是否完整。
  3. 缺失值处理:对市值缺失的持仓,使用前一日市值填充;对收益率缺失的交易日,标记为NaN并后续剔除。
  4. 标签生成:根据复盘方案生成静态标签与动态标签,写入切片标签字段。
  5. 时间对齐:将所有数据统一至周度频率,保留调仓日前后3日快照。
  6. 异常检测:对收益率、换手率、行业偏离度执行IQR检测,标记异常值。
  7. 数据输出:生成宽表格式的切片面板数据,每行代表一个组合在某个切片标签下的时间序列。
import pandas as pd
import numpy as np

def prepare_slice_data(portfolio_df, factor_df, label_config):
    """
    切片数据准备主函数
    :param portfolio_df: 持仓数据,包含字段 [date, portfolio_id, security_id, market_value, return]
    :param factor_df: 因子数据,包含字段 [date, security_id, factor_name, factor_value]
    :param label_config: 标签配置字典,如 {'style': ['value', 'growth'], 'sector': 'sw_primary'}
    :return: 切片面板数据 DataFrame
    """
    # 1. 去重与缺失值处理
    portfolio_df = portfolio_df.drop_duplicates(subset=['date', 'portfolio_id', 'security_id'])
    portfolio_df['market_value'] = portfolio_df.groupby('portfolio_id')['market_value'].transform(
        lambda x: x.fillna(method='ffill')
    )
    
    # 2. 标签生成(示例:风格标签)
    factor_pivot = factor_df.pivot_table(index=['date', 'security_id'], 
                                         columns='factor_name', values='factor_value').reset_index()
    portfolio_df = portfolio_df.merge(factor_pivot, on=['date', 'security_id'], how='left')
    
    # 3. 时间序列对齐:降频至周度
    portfolio_df['week'] = portfolio_df['date'].dt.isocalendar().week.astype(int)
    weekly_df = portfolio_df.groupby(['portfolio_id', 'week']).agg({
        'market_value': 'sum',
        'return': 'mean',
        'value_factor': 'mean',
        'growth_factor': 'mean'
    }).reset_index()
    
    # 4. 异常值处理(IQR法)
    for col in ['return', 'value_factor']:
        Q1 = weekly_df[col].quantile(0.25)
        Q3 = weekly_df[col].quantile(0.75)
        IQR = Q3 - Q1
        lower = Q1 - 1.5 * IQR
        upper = Q3 + 1.5 * IQR
        weekly_df[col] = weekly_df[col].clip(lower, upper)
    
    return weekly_df
代码说明:上述示例展示了从原始持仓数据到切片面板数据的核心转换逻辑。实际生产环境中,需增加组合维度聚合、多标签交叉、异常标记字段等扩展。建议将清洗、标签、对齐、异常处理拆分为独立模块,便于单元测试与复用。