第 3 章 · 04 收缩估计 Ledoit-Wolf 与 OAS


文档摘要

第 3 章 · 04 收缩估计 Ledoit-Wolf 与 OAS 本节摘要:本节是「风险模型」的重头戏,讲 PyPortfolioOpt 文档反复强调的生产默认——收缩估计(shrinkage)。样本协方差虽无偏但噪声大,在「资产数 N 接近样本数 T」时严重失真。收缩估计把样本协方差 S 向一个结构化但偏差大的目标 F 拉近: ,通过偏差-方差权衡显著降噪。 的 类提供三种 Ledoit-Wolf 收缩目标(constantvariance、singlefactor、constantcorrelation)以及 Oracle Approximating Shrinkage(OAS)。

第 3 章 · 04 收缩估计 Ledoit-Wolf 与 OAS

本节摘要:本节是「风险模型」的重头戏,讲 PyPortfolioOpt 文档反复强调的生产默认——收缩估计(shrinkage)。样本协方差虽无偏但噪声大,在「资产数 N 接近样本数 T」时严重失真。收缩估计把样本协方差 S 向一个结构化但偏差大的目标 F 拉近:Σ̂ = δF + (1-δ)S,通过偏差-方差权衡显著降噪。risk_models.pyCovarianceShrinkage 类提供三种 Ledoit-Wolf 收缩目标(constant_variance、single_factor、constant_correlation)以及 Oracle Approximating Shrinkage(OAS)。本节拆解收缩原理、三种目标的差异、delta 收缩常数的自动选择,以及作者的实务建议——默认用 Ledoit-Wolf

内容来源:原项目源码 pypfopt/risk_models.py(类 CovarianceShrinkage)、文档 docs/RiskModels.rst,汉化并套用体系化模板。

学习目标

阅读完本节,你应当能够:

  1. 写出收缩公式 Σ̂ = δF + (1-δ)S,解释偏差-方差权衡。
  2. 区分 Ledoit-Wolf 的三种收缩目标及各自结构假设。
  3. 解释 delta(收缩常数)的含义与自动估计原理。
  4. CovarianceShrinkage 类调用 Ledoit-Wolf 与 OAS。
  5. 复述作者「默认用 Ledoit-Wolf」的实务建议。

一、收缩的偏差-方差权衡

样本协方差 S 是无偏估计(E(S) = Σ),但估计误差(方差)大——它有 N(N+1)/2 个独立元素要估,样本不够时矩阵充满噪声。

收缩的思路:把 S 与一个结构化、低方差但有偏的估计 F 混合:

Σ̂ = δ · F + (1 - δ) · S
  • δ = 0:完全用样本,无偏但高方差(原始 S)。
  • δ = 1:完全用结构 F,低方差但有偏。
  • δ ∈ (0, 1):权衡——稍增偏差换大幅降方差,总均方误差(MSE)更小。

直觉:F 是「猜一个简单结构」(如「所有方差相等、相关性为 0」),它肯定不准,但很稳;S 是「让数据说话」,它准但很跳。收缩就是「在数据与先验之间找平衡」。

💡 核心心法:这与机器学习里的 L2 正则、贝叶斯先验是同一思想——「数据不够时,引入结构先验」。在金融里,样本永远不够(N 大、T 相对小),所以收缩几乎总是更优。

二、三种 Ledoit-Wolf 收缩目标

docs/RiskModels.rst 列出 PyPortfolioOpt 支持的三种 F:

2.1 constant_variance(默认)

F = μ · I (μ = trace(S)/N,即平均样本方差)

目标结构:所有对角元素相等(=平均方差)、所有非对角元素为 0(完全不相关)。这是最简单的结构——假设资产之间独立,只用一个标量描述风险。Ledoit-Wolf 2004 年论文证明了这种收缩的最优 δ 有解析解,sklearn 的 LedoitWolf 实现就是它。CovarianceShrinkage.ledoit_wolf() 默认用这个。

2.2 single_factor

基于 Sharpe 单指数模型:假设资产收益只受市场单一因子驱动,资产间的协方差来自它们对市场的 beta:

F_ij = β_i · β_j / σ²_mkt (非对角) F_ii = S_ii (对角保留样本方差)

源码里 _ledoit_wolf_single_factor 实现了 Ledoit-Wolf 2001 年的版本——用资产等权均值代理市场,估 beta,构造 F。适合「市场因子主导」的资产池(如大盘成分股)。

2.3 constant_correlation

假设所有资产对的相关性相等(等于平均相关性 ),但方差保留:

F_ij = r̄ · σ_i · σ_j (非对角) F_ii = S_ii (对角保留)

_ledoit_wolf_constant_correlation 实现了 Ledoit-Wolf 2003 年的版本——估 ,构造 F。适合「相关性结构相对均匀」的资产池(如同一板块的股票)。

目标 结构假设 论文 适用
constant_variance 资产独立、方差相等 Ledoit-Wolf 2004 通用默认
single_factor 单一市场因子驱动 Ledoit-Wolf 2001 大盘成分股
constant_correlation 相关性均匀 Ledoit-Wolf 2003 板块内股票

三、delta 收缩常数

每种目标 F 都对应一个最优 δ——它决定「拉多近」。Ledoit-Wolf 的核心贡献是给出了 δ 的渐近最优解析估计:

  • δ 过小:噪声没降够。
  • δ 过大:过度结构化,丢失真实联动信号。

源码里 _ledoit_wolf_constant_correlation 的最后几行就是这套公式的实现:

kappa_hat = (pi_hat - rho_hat) / gamma_hat delta = max(0.0, min(1.0, kappa_hat / t)) # 截断到 [0, 1] shrunk_cov = delta * F + (1 - delta) * S

三个量 pi_hat(样本协方差的方差)、rho_hat(协方差估计的渐进协方差)、gamma_hat(S 与 F 的距离)共同决定 kappa_hat,再除以样本数 t 得 δ。这套公式让收缩强度自适应数据——样本越少、噪声越大,δ 自动越大,拉得越近。

💡 实例属性 delta:CovarianceShrinkage 实例的 .delta 属性会保存最后求出的收缩常数,可以打印出来看「这次收缩拉了多近」。δ 接近 0 说明样本协方差已足够好;接近 1 说明样本噪声太大,几乎完全用结构 F。

四、OAS:Oracle Approximating Shrinkage

oracle_approximating 方法用 Chen et al. (2010) 的 OAS 估计器,sklearn 的 covariance.OAS 实现:

def oracle_approximating(self): X = np.nan_to_num(self.X.values) shrunk_cov, self.delta = self.covariance.oas(X) return self._format_and_annualize(shrunk_cov)

OAS 的目标与 Ledoit-Wolf 一致(收缩到 constant_variance 目标),但它对样本是高斯或近高斯的情形有更低的均方误差。文档原话:

OAS 由 Chen et al. (2010) 提出,在样本是高斯或近高斯时,比 Ledoit-Wolf 收缩的均方误差更低。

实务上,资产收益往往有厚尾(非高斯),所以 Ledoit-Wolf 仍是更稳健的默认。OAS 适合「你确信收益分布接近高斯」或想试不同收缩做敏感性分析的场景。

五、手动收缩

CovarianceShrinkage 还提供 shrunk_covariance(delta=0.2)——手动指定 δ,不自动估。结构 F 固定为 constant_variance(对角 = 平均方差,非对角 = 0):

def shrunk_covariance(self, delta=0.2): self.delta = delta N = self.S.shape[1] mu = np.trace(self.S) / N F = np.identity(N) * mu shrunk_cov = delta * F + (1 - delta) * self.S return self._format_and_annualize(shrunk_cov)

用途:做敏感性分析(扫不同 δ 看权重如何变化)、或你有先验知识想固定收缩强度。

六、用法示例

6.1 默认 Ledoit-Wolf(constant_variance)

from pypfopt import risk_models S = risk_models.CovarianceShrinkage(df).ledoit_wolf() print(cs.delta) # 查看收缩强度

这是 UserGuide 与 cookbook 反复推荐的生产默认:

from pypfopt.expected_returns import mean_historical_return from pypfopt.risk_models import CovarianceShrinkage mu = mean_historical_return(df) S = CovarianceShrinkage(df).ledoit_wolf()

6.2 单因子 / 常数相关目标

cs = risk_models.CovarianceShrinkage(df) S_sf = cs.ledoit_wolf(shrinkage_target="single_factor") S_cc = cs.ledoit_wolf(shrinkage_target="constant_correlation")

6.3 OAS

S_oas = risk_models.CovarianceShrinkage(df).oracle_approximating()

6.4 统一入口

risk_matrix 函数支持所有收缩方法:

risk_models.risk_matrix(df, method="ledoit_wolf") risk_models.risk_matrix(df, method="ledoit_wolf_constant_variance") # 同上 risk_models.risk_matrix(df, method="ledoit_wolf_single_factor") risk_models.risk_matrix(df, method="ledoit_wolf_constant_correlation") risk_models.risk_matrix(df, method="oracle_approximating")

七、实务建议

docs/RiskModels.rst 在结尾给出明确建议:

对多数用例,我会直接选 Ledoit-Wolf 收缩——正如 Quantopian 在其量化金融系列讲座里所推荐的。

理由汇总:

  1. 偏差-方差更优:在金融「N 接近 T」的典型困境下,收缩几乎总是比样本协方差 MSE 更低。
  2. 数值更稳:收缩后的矩阵更接近 PSD,优化器求解更可靠。
  3. 经验验证:Quantopian(知名量化平台)的教程也主推 Ledoit-Wolf。
  4. API 简洁:CovarianceShrinkage(df).ledoit_wolf() 一行搞定。

⚠️ 依赖 scikit-learn:CovarianceShrinkage 内部用 sklearn.covarianceledoit_wolfOAS,源码里检查依赖:

if not _check_soft_dependencies(["scikit-learn"], severity="none"): raise ImportError("scikit-learn is required ...")

请确保环境装了 scikit-learn。

本节要点回顾

  1. 收缩公式:Σ̂ = δ·F + (1-δ)·S,偏差-方差权衡——稍增偏差换大幅降方差。
  2. 三种目标:constant_variance(资产独立,默认)、single_factor(市场因子)、constant_correlation(相关性均匀)。
  3. delta 自动估计:Ledoit-Wolf 给出渐近最优解析公式;cs.delta 属性可查看。
  4. OAS:Chen 2010,高斯样本下 MSE 更低;但资产收益厚尾,Ledoit-Wolf 仍是更稳默认。
  5. 手动收缩:shrunk_covariance(delta=0.2),固定 δ 做敏感性分析。
  6. 生产默认:CovarianceShrinkage(df).ledoit_wolf(),文档与 Quantopian 都主推。

下一节是本章最后一节——最小行列式协方差(MCD),用极大似然的鲁棒估计应对异常值。


发布者: 作者: 灏天文库 转发
评论区 (0)
U