4. 异常值检测与修正:基于统计、距离与模型的综合策略

在金融压力测试中,异常值会严重扭曲风险因子分布、破坏协方差结构,导致压力情景下的损失估计偏差。本章系统讲解三类异常检测方法及其修正技术,确保特征工程输出的数据质量满足压力测试的稳健性要求。

4.1 异常值检测方法体系

根据数据分布假设与计算复杂度,异常检测方法可分为统计、距离与模型三大类。下表对比了核心方法的适用场景与优缺点:

方法类别代表算法分布假设适用场景主要局限
统计Z-score、IQR正态或对称分布单变量、快速筛查对多变量交互异常不敏感
距离LOF (Local Outlier Factor)局部密度可比局部密度变化、簇状数据计算复杂度 O(n²)
模型Isolation Forest无显式分布高维、非线性、大规模对弱异常可能漏检

4.2 基于统计的异常检测

4.2.1 Z-score 方法

Z-score 衡量数据点与均值的偏离程度,适用于近似正态分布的数据。金融压力测试中常用于检测利率、汇率等单变量极端波动。

import numpy as np
from scipy import stats

def zscore_outliers(data, threshold=3):
    z = np.abs(stats.zscore(data))
    return np.where(z > threshold)[0]

# 示例:检测日收益率序列中的极端值
returns = np.random.randn(1000) * 0.02 + 0.001
outlier_idx = zscore_outliers(returns, threshold=3.5)
print(f"检测到 {len(outlier_idx)} 个异常点")

4.2.2 IQR 方法

IQR(四分位距)不依赖正态假设,通过箱线图规则识别异常。在信用评分、违约率等偏态分布特征中表现稳健。

def iqr_outliers(data, multiplier=1.5):
    Q1, Q3 = np.percentile(data, [25, 75])
    IQR = Q3 - Q1
    lower = Q1 - multiplier * IQR
    upper = Q3 + multiplier * IQR
    return np.where((data < lower) | (data > upper))[0]

# 金融压力测试中常用 multiplier=3 作为极端值截断
extreme_idx = iqr_outliers(loan_default_rates, multiplier=3)
实践建议:在压力测试中,建议同时使用 Z-score 和 IQR 进行交叉验证。若两种方法均标记为异常,则该点应优先处理;若仅一种方法标记,需结合业务逻辑判断。

4.3 基于距离的异常检测:LOF

LOF(局部异常因子)通过比较数据点与其邻域的局部密度来识别异常。在金融特征中,能有效发现“孤立但密度高”的异常簇,如特定市场环境下的共变异常。

from sklearn.neighbors import LocalOutlierFactor

def lof_detection(X, contamination=0.05, n_neighbors=20):
    lof = LocalOutlierFactor(
        n_neighbors=n_neighbors,
        contamination=contamination,
        novelty=False
    )
    y_pred = lof.fit_predict(X)
    # -1 表示异常,1 表示正常
    outlier_indices = np.where(y_pred == -1)[0]
    return outlier_indices, lof.negative_outlier_factor_

# 多变量特征矩阵:波动率、相关性、流动性
features = np.column_stack([volatility, correlation, liquidity])
outliers, lof_scores = lof_detection(features, contamination=0.03)
注意:LOF 对 n_neighbors 参数敏感。在金融时间序列中,建议使用 10~30 的邻域范围,过小会导致误报,过大会平滑掉局部异常。

4.4 基于模型的异常检测:Isolation Forest

Isolation Forest 通过随机切割特征空间来隔离异常点。异常点因路径更短而被快速隔离,适合高维金融特征(如多资产收益率、风险因子载荷)。

from sklearn.ensemble import IsolationForest

def isolation_forest_detection(X, contamination=0.05, random_state=42):
    iso_forest = IsolationForest(
        contamination=contamination,
        random_state=random_state,
        n_estimators=100,
        max_samples='auto'
    )
    y_pred = iso_forest.fit_predict(X)
    outlier_indices = np.where(y_pred == -1)[0]
    anomaly_scores = iso_forest.decision_function(X)
    return outlier_indices, anomaly_scores

# 压力测试情景:同时检测 50 个风险因子的异常
risk_factors = np.random.randn(5000, 50) * 0.1
anomaly_idx, scores = isolation_forest_detection(risk_factors, contamination=0.02)
异常检测方法对比与选择流程 金融特征数据 统计:Z-score / IQR 距离:LOF 模型:Isolation Forest 单变量、正态/对称 快速筛查、低维 局部密度变化 簇状数据、中等维度 高维、非线性 大规模、无分布假设 异常标记 + 异常分数

4.5 极端值截尾与 Winsorize 处理

检测到异常后,不能简单删除——在压力测试中,极端值可能包含尾部风险信息。Winsorize(缩尾处理)将极端值替换为指定分位数的边界值,保留样本量同时控制极端影响。

4.5.1 截尾处理(Trimming)

直接删除异常值,适用于明显的数据录入错误或不可恢复的测量噪声。

def trim_outliers(data, lower_percentile=1, upper_percentile=99):
    lower = np.percentile(data, lower_percentile)
    upper = np.percentile(data, upper_percentile)
    return data[(data >= lower) & (data <= upper)]

# 删除极端尾部 1% 的数据
clean_returns = trim_outliers(asset_returns, 1, 99)

4.5.2 Winsorize 处理

将异常值替换为边界值,保留数据量同时抑制极端值影响。金融压力测试中常用 1%/99% 或 5%/95% 分位数作为截断点。

from scipy.stats.mstats import winsorize

def winsorize_features(data, limits=(0.01, 0.01)):
    """
    limits: (lower_fraction, upper_fraction)
    例如 (0.01, 0.01) 表示将底部1%和顶部1%替换为边界值
    """
    return winsorize(data, limits=limits)

# 对压力测试中的风险因子进行缩尾
risk_factor_winsorized = winsorize_features(
    stress_test_factors, 
    limits=(0.025, 0.025)  # 2.5% 缩尾
)
关键区别:截尾会减少样本量,在压力测试中可能导致尾部事件被低估;Winsorize 保留样本量但压缩极端值幅度。建议在压力测试中优先使用 Winsorize,并记录缩尾比例作为敏感性分析参数。
Winsorize 处理前后对比(以 1%/99% 缩尾为例) 处理前:含极端值 原始分布 左尾异常值(<1%) 右尾异常值(>99%) 均值被极端值拉偏 方差被高估 处理后:Winsorize 缩尾 缩尾后分布 左尾替换为 P1 值 右尾替换为 P99 值 均值更稳健 方差反映主体波动 Winsorize 保留样本量,仅压缩极端值幅度 适用于压力测试中尾部风险信息的保留 缩尾参数建议:轻度 (0.01,0.01) | 中度 (0.025,0.025) | 重度 (0.05,0.05) 压力测试中推荐从轻度开始,逐步增加至分布稳定

4.6 金融压力测试中的异常处理流程

结合上述方法,推荐以下标准化处理流程:

  1. 初步筛查:使用 Z-score 和 IQR 对每个风险因子进行单变量异常检测,标记极端值。
  2. 多变量验证:对标记的异常点,使用 LOF 或 Isolation Forest 进行多变量验证,排除因变量交互导致的误判。
  3. 业务审核:将检测结果与压力测试情景(如 2008 年金融危机、2020 年疫情冲击)对比,确认是否为真实市场极端事件。
  4. 修正处理:对确认的异常值,优先使用 Winsorize 处理;对明显错误的数据(如负价格、超范围值)进行截尾删除。
  5. 记录与报告:记录异常检测参数、处理比例、修正前后统计量变化,作为压力测试模型文档的一部分。
实战案例:在某银行信用风险压力测试中,使用 Isolation Forest 检测到 3% 的贷款样本在“失业率-违约率”二维空间中出现异常共变。经 Winsorize 处理后,压力损失估计的波动率降低了 18%,模型稳定性显著提升。

4.7 本章小结

方法核心思想金融应用场景推荐参数
Z-score标准差偏离度收益率、波动率单变量检测阈值 3~4
IQR四分位距信用评分、违约率偏态分布乘数 1.5~3
LOF局部密度比多资产共变异常、市场微观结构n_neighbors=20, contamination=0.03~0.05
Isolation Forest随机切割隔离高维风险因子、压力情景筛选n_estimators=100, contamination=0.02~0.05
Winsorize分位数替换尾部风险保留、压力测试数据清洗limits=(0.01,0.01) 至 (0.05,0.05)