清洗与异常值
异常值的两种身份
Section titled “异常值的两种身份”异常值可能是错误(价格多一个零、小数点错位),也可能是真实的极端事件(熔断日、闪崩、退市清算)。把前者修掉是清洗,把后者修掉是删数据——而极端事件恰恰是风险度量最需要的数据。分层的处理策略由此而来。
第一层:按规则识别录入错误
Section titled “第一层:按规则识别录入错误”确定性错误有明确特征,用规则识别:
- 价格 、成交量 ;
- 当日价格变动超过涨跌停/熔断机制允许的范围(如 A 股单日 ±10% 之外,见A 股:T+1、涨跌停与融券);
- 最高价 < 最低价、开盘价偏离上一收盘超过机制允许的范围;
- 与相邻交易日的价格水平跳变超过若干倍日波动率。
识别出错误后用前值或邻日收盘替换,并记录替换日志。
第二层:真实极端值,用稳健统计
Section titled “第二层:真实极端值,用稳健统计”无法归为错误的极端值,保留数据、限制其影响:
- 缩尾(winsorize):把超过分位点的值截到分位点值,通常取 1%/99% 或 3 倍 MAD——保留观测但压低杠杆;
- MAD 标准化:中位数绝对偏差对极端值稳健,,稳健 z 分数 ;
- 截面标准化前先缩尾:z 分数对极端值极敏感,一个错位价格能污染整个截面的标准化结果。
import numpy as npimport pandas as pd
def winsorize_zscore(x: pd.Series, n_mad: float = 3.0) -> pd.Series: """稳健缩尾 + 标准化:先按 MAD 截尾,再标准化""" med = x.median() mad = (x - med).abs().median() * 1.4826 upper, lower = med + n_mad * mad, med - n_mad * mad clipped = x.clip(lower, upper) return (clipped - clipped.mean()) / clipped.std()永远保留原始数据
Section titled “永远保留原始数据”清洗结果的纪律:
- 原始列只读,清洗结果写到新列或新表;
- 每一步清洗(替换、缩尾、剔除)都记录日志与参数,保证可复现,见复现性:版本、种子与环境;
- 回测报告能追溯到"这一天的价格被替换过"。
量化中的用法
Section titled “量化中的用法”- 错误识别用规则(阈值、机制边界),极端值处理用稳健统计;
- 缩尾参数(分位点、MAD 倍数)写入配置并固定,不逐次调;
- 横截面因子计算前,先缩尾再标准化。
- 缩尾(winsorize)比截尾(trim)更常用,通常取 1%/99% 或 3 倍 MAD
- 横截面标准化前先缩尾
- 永远保留原始列,清洗结果写到新列