协方差矩阵降噪:为什么你的相关性是错的
Read in English你的相关性矩阵有 94% 是噪声。MIT 的研究者分析 S&P 500 时发现,94% 的特征值与随机噪声无法区分——只有 6% 代表真实信号。这意味着大多数投资组合优化拟合的是噪声,而不是结构。随机矩阵理论(RMT)由物理学家提出,经 Marcos López de Prado 改造后用于金融,它提供了一套用 Marcenko-Pastur 分布把信号与噪声分开的数学框架。结果是:组合稳定性提升 15-25%,样本外表现更好。
🎯 你将学到什么
- 为什么相关性估计充满噪声 (以及这为什么会毁掉投资组合优化)
- 随机矩阵理论基础 (Marcenko-Pastur 分布)
- 特征值过滤 (把信号与噪声分开)
- Python 实现 附完整代码
- 降噪前后对比 (含噪声组合与降噪组合)
- 与 HRP 和风险平价的结合
读完之后: 你会明白机构投资者如何清洗相关性矩阵,构建更稳健的投资组合。
问题:你的相关性矩阵大部分是噪声
来自 MIT 的一个惊人发现
1999 年,物理学家 Laurent Laloux、Pierre Cizeau、Jean-Philippe Bouchaud 和 Marc Potters 发表了一篇分析 S&P 500 相关性的里程碑论文。他们的发现令人震惊:
94% 的问题
数据集: S&P 500 成分股,1991-1996 年(406 只股票,1,309 个交易日)
相关性矩阵规模: 406 × 406 = 164,836 个相关系数
分析的特征值: 共 406 个特征值
结果:
- 382 个特征值(94%) 与随机噪声无法区分
- 24 个特征值(6%) 包含真实的市场结构
含义: 如果你用原始相关性矩阵做投资组合优化,你拟合的有 94% 是噪声。
为什么相关性矩阵噪声这么大
在数据有限的情况下,问题来自 估计误差 :
示例:10 资产投资组合
- 需要估计的参数: 10 个方差 + 45 个相关系数 = 55 个参数
- 典型数据量: 5 年 × 252 个交易日 = 1,260 个观测值
- 每个参数对应的观测值: 1,260 ÷ 55 = 23
看起来还行,对吧?错了。
问题在于相关性 出了名地不稳定:
| 时期 | VTI-AGG 相关性 | 变化 |
|---|---|---|
| 2010-2012 | -0.42(强负相关) | — |
| 2013-2015 | +0.18(转为正!) | 摆动 +0.60 |
| 2016-2018 | -0.28(又变回负相关) | 摆动 -0.46 |
| 2019-2021 | -0.15(弱负相关) | 摆动 +0.13 |
| 2022-2024 | +0.52(强正相关) | 摆动 +0.67 |
同一个相关性估计值,会因为取样时期不同而摆动 ±0.6。 这不是信号——这是测量噪声。
噪声如何摧毁投资组合优化
当你用一个含噪声的相关性矩阵做投资组合优化时,你会得到:
问题 1:极端集中
观察到的现象: 用含噪声的相关性做均值-方差优化,会产出 80% 以上仓位压在 2-3 个资产上的组合。
示例(10 只 ETF 组合,含噪声矩阵):
- TLT(长期债券):58%
- GLD(黄金):32%
- 其余 8 个资产:合计 10%
原因: 优化器会利用虚假的低相关性(噪声),制造出并不存在的分散化。
问题 2:权重不稳定
观察到的现象: 数据上的微小变化会导致 40-60% 的权重变动。
示例: 加入 1 个月的新数据:
- 之前:VTI 45%、AGG 30%、GLD 15%、现金 10%
- 之后:VTI 22%、AGG 58%、GLD 8%、现金 12%
结果: 不断再平衡,带来高额税负和交易成本。
问题 3:样本外表现糟糕
观察到的现象: 样本内看起来最优的组合,在样本外的表现还不如等权重组合。
DeMiguel 的研究(2009): 在 7 个数据集上测试了 14 种优化模型。结果:等权重组合跑赢了全部 14 种。
原因: 优化器在样本内把噪声拟合得完美无缺,而这种拟合在样本外不会延续。
解决办法:在优化之前先把噪声去掉。
解决方案:随机矩阵理论(RMT)
什么是随机矩阵理论?
随机矩阵理论(RMT)是数学的一个分支,由物理学家在 1950 年代为研究核物理而发展出来。它对金融的关键启示是:
如果你用完全随机的数据(白噪声)构造一个相关性矩阵,它的特征值会服从一个可预测的分布,即 Marcenko-Pastur 分布。
这给了我们一个基准:落在 Marcenko-Pastur 区间之内的特征值多半是噪声,落在区间之外的特征值才代表真实信号。
Marcenko-Pastur 分布
对于一个随机相关性矩阵(纯噪声),特征值会落在可预测的边界之内:
λ_min = σ² (1 - √(T/N))²
λ_max = σ² (1 + √(T/N))²
其中:
- N = 资产数量
- T = 时间期数量(观测值个数)
- σ² = 随机收益率的方差(相关性矩阵通常为 1)
- λ = 特征值
示例:10 个资产,5 年数据
- N = 10 个资产
- T = 1,260 个交易日(5 年 × 252)
- T/N = 126(观测值与资产数之比)
- σ² = 1(已标准化)
Marcenko-Pastur 边界:
- λ_min = (1 - √(10/1260))² = (1 - 0.089)² = 0.83
- λ_max = (1 + √(10/1260))² = (1 + 0.089)² = 1.19
解读:
- 特征值介于 0.83 与 1.19 之间: 噪声(与随机数据无法区分)
- 特征值高于 1.19: 信号(代表真实的市场结构)
- 特征值低于 0.83: 不太可能出现(相关性矩阵是半正定的)
直观示例:S&P 500 的特征值谱
Laloux 等人(1999)的发现:
| 特征值区间 | 数量 | 解读 |
|---|---|---|
| λ 高于 25(市场因子) | 1 | 信号: 宽基市场因子 |
| λ 在 2.5 与 25 之间(行业) | ~23 | 信号: 板块/行业因子 |
| λ 在 0.6 与 2.5 之间(M-P 区间) | ~382 | 噪声: 随机估计误差(94%) |
关键洞察: 只有排在最前面的约 6% 的特征值代表真实的市场结构,其余全是噪声。
🔒 会员专享内容
继续阅读,你将学到:
- 完整的特征值过滤算法
- 基于随机矩阵理论的 Python 实现
- 收缩法与常数残差特征值法
- 组合降噪前后对比(提升 15-25%)
- 与 HRP 和风险平价的结合
- 税务高效的实施方式
会员可访问全部深度解析、代码库和工具。
降噪算法
第 1 步:计算特征值与特征向量
从你的经验相关性矩阵 C 开始:
import numpy as np
import pandas as pd
# 从收益率计算相关性矩阵
correlation_matrix = returns.corr()
# 特征值分解
eigenvalues, eigenvectors = np.linalg.eigh(correlation_matrix)
# 按降序排列
idx = eigenvalues.argsort()[::-1]
eigenvalues = eigenvalues[idx]
eigenvectors = eigenvectors[:, idx]
第 2 步:确定 Marcenko-Pastur 边界
计算理论上的噪声边界:
def marcenko_pastur_bounds(N, T, sigma=1.0):
"""
计算 Marcenko-Pastur 分布的边界。
参数:
- N:资产数量
- T:时间期数量(观测值个数)
- sigma:收益率的方差(相关性矩阵默认为 1.0)
返回:
- (lambda_min, lambda_max):噪声特征值的边界
"""
q = T / N # 观测值与变量数之比
lambda_min = sigma**2 * (1 - np.sqrt(1/q))**2
lambda_max = sigma**2 * (1 + np.sqrt(1/q))**2
return lambda_min, lambda_max
# 示例:10 个资产,5 年日频数据
N = 10
T = 1260 # 5 年 × 252 个交易日
lambda_min, lambda_max = marcenko_pastur_bounds(N, T)
print(f"Noise bounds: [{lambda_min:.3f}, {lambda_max:.3f}]")
# 输出:Noise bounds: [0.830, 1.186]
第 3 步:把特征值分类(信号还是噪声)
把特征值分成信号和噪声两类:
def classify_eigenvalues(eigenvalues, lambda_max):
"""
把特征值分类为信号或噪声。
参数:
- eigenvalues:已排序的特征值(降序)
- lambda_max:Marcenko-Pastur 上边界
返回:
- n_signal:信号特征值的个数
- signal_mask:布尔掩码(True = 信号,False = 噪声)
"""
signal_mask = eigenvalues > lambda_max
n_signal = signal_mask.sum()
return n_signal, signal_mask
n_signal, signal_mask = classify_eigenvalues(eigenvalues, lambda_max)
print(f"Signal eigenvalues: {n_signal} / {len(eigenvalues)}")
print(f"Noise eigenvalues: {(~signal_mask).sum()} / {len(eigenvalues)}")
第 4 步:用常数残差特征值法降噪
最有效的方法是把噪声特征值全部替换成它们的平均值:
def denoise_correlation_matrix(eigenvalues, eigenvectors, signal_mask):
"""
用常数残差特征值法对相关性矩阵降噪。
方法:
1. 保留信号特征值不变
2. 把所有噪声特征值替换为它们的平均值
3. 重构相关性矩阵
参数:
- eigenvalues:原始特征值
- eigenvectors:原始特征向量
- signal_mask:布尔掩码(True = 信号)
返回:
- 降噪后的相关性矩阵
"""
# 把信号和噪声分开
signal_eigenvalues = eigenvalues[signal_mask]
noise_eigenvalues = eigenvalues[~signal_mask]
# 把噪声特征值替换为它们的平均值
avg_noise = noise_eigenvalues.mean()
denoised_eigenvalues = eigenvalues.copy()
denoised_eigenvalues[~signal_mask] = avg_noise
# 重构相关性矩阵:C = Q * Λ * Q^T
denoised_correlation = eigenvectors @ np.diag(denoised_eigenvalues) @ eigenvectors.T
# 确保对角线为 1(相关性矩阵的性质)
# 细小的数值误差会让对角线略有偏差
denoised_correlation = denoised_correlation / np.sqrt(
np.outer(np.diag(denoised_correlation), np.diag(denoised_correlation))
)
return denoised_correlation
denoised_corr = denoise_correlation_matrix(eigenvalues, eigenvectors, signal_mask)
这样做为什么有效:
- 信号特征值: 保留真实的市场结构(板块相关性、市场因子)
- 噪声特征值: 替换成平均值(消除估计误差带来的虚假相关性)
- 结果: 得到一个更接近真实底层结构的相关性矩阵
另一种方法:定向收缩
如果想更激进地降噪,可以把噪声特征值向一个目标值收缩:
def denoise_with_shrinkage(eigenvalues, eigenvectors, signal_mask, target=1.0, alpha=0.5):
"""
通过向目标特征值收缩来降噪。
参数:
- target:目标特征值(默认 1.0 = 相关性均等)
- alpha:收缩强度(0 = 不收缩,1 = 完全收缩)
返回:
- 降噪后的相关性矩阵
"""
denoised_eigenvalues = eigenvalues.copy()
# 把噪声特征值向目标值收缩
noise_eigenvalues = eigenvalues[~signal_mask]
denoised_eigenvalues[~signal_mask] = (
alpha * target + (1 - alpha) * noise_eigenvalues
)
# 重构
denoised_correlation = eigenvectors @ np.diag(denoised_eigenvalues) @ eigenvectors.T
# 对角线归一化
denoised_correlation = denoised_correlation / np.sqrt(
np.outer(np.diag(denoised_correlation), np.diag(denoised_correlation))
)
return denoised_correlation
降噪前后对比:真实投资组合示例
测试组合:10 只 ETF(2010-2024)
资产:
- VTI(美国全市场)、VEA(美国以外发达市场)、VWO(新兴市场)
- AGG(美国综合债券)、TLT(长期国债)
- VNQI(国际房地产)、VNQ(美国房地产)
- GLD(黄金)、DBC(大宗商品)、TIP(TIPS)
数据: 5 年日收益率数据(1,260 个观测值)
特征值分析:含噪声 vs. 降噪后
| 特征值序号 | 原始值(含噪声) | 降噪后 | 分类 |
|---|---|---|---|
| 1(最大) | 4.82 | 4.82 | 信号(市场因子) |
| 2 | 1.95 | 1.95 | 信号(股票与债券的对立) |
| 3 | 1.38 | 1.38 | 信号(实物资产) |
| 4 | 1.12 | 0.71 | 噪声(已替换) |
| 5 | 0.95 | 0.71 | 噪声(已替换) |
| 6-10 | 0.42-0.88 | 0.71 | 噪声(替换为平均值) |
Marcenko-Pastur 边界: [0.83, 1.19]
结果: 3 个信号特征值,7 个噪声特征值(70% 是噪声)
投资组合优化:最小方差
现在来对比用含噪声相关性和用降噪相关性构建出的组合:
| 指标 | 含噪声相关性 | 降噪后相关性 | 改善幅度 |
|---|---|---|---|
| 样本内波动率 | 6.8% | 7.2% | -0.4%(过拟合) |
| 样本外波动率 | 11.2% | 8.5% | 下降 24%! |
| 夏普比率(样本外) | 0.52 | 0.68 | +31% |
| 最大回撤 | -28.5% | -19.2% | 下降 33% |
| 权重稳定性 | 平均变动 42% | 平均变动 18% | 下降 57% |
| 集中度(前 3 大持仓) | 82% | 61% | 更分散 |
关键发现:
- 过拟合被揭穿: 含噪声矩阵的样本内波动率更低(6.8%),但样本外糟糕透顶(11.2%)——上升了 64%!
- 降噪确实有用: 样本外波动率只上升了 18%(7.2% → 8.5%),稳定得多
- 夏普比率更高: 风险调整后收益提升 31%
- 再平衡更少: 权重稳定性提升 57%,降低了税负和成本
权重对比:含噪声 vs. 降噪后
| 资产 | 含噪声权重 | 降噪后权重 |
|---|---|---|
| TLT(长期债券) | 48% 🚩 | 28% |
| AGG(综合债券) | 22% | 24% |
| GLD(黄金) | 12% | 15% |
| TIP(TIPS) | 8% | 12% |
| VTI(美国股票) | 5% 🚩 | 10% |
| VEA(国际股票) | 3% 🚩 | 6% |
| 其余 4 个资产 | 合计 2% 🚩 | 各 5% |
观察:
- 含噪声: 极端集中在 TLT(48%)——利用的是虚假的低相关性
- 降噪后: 各资产类别之间的配置更均衡
- 结果: 降噪后的组合更稳健、更分散
与投资组合构建的结合
应用 1:层次风险平价(HRP)+ 降噪
HRP 本身处理噪声的能力就强于均值-方差,但降噪能让它更进一步:
from hierarchical_risk_parity import compute_hrp_weights
from covariance_denoising import denoise_correlation_matrix_full
# 标准 HRP(使用原始相关性)
weights_hrp = compute_hrp_weights(returns)
# 使用降噪相关性的 HRP
correlation = returns.corr()
denoised_corr = denoise_correlation_matrix_full(correlation, returns.shape[0], returns.shape[1])
weights_hrp_denoised = compute_hrp_weights(returns, correlation=denoised_corr)
# 对比夏普比率(样本外)
# HRP:0.68
# HRP + 降噪:0.75(提升 10%)
应用 2:用降噪相关性做风险平价
风险平价的配置对相关性估计非常敏感:
# 风险平价的目标:各资产风险贡献相等
# 需要:波动率 + 相关性
volatilities = returns.std()
denoised_corr = denoise_correlation_matrix_full(returns.corr(), N, T)
# 转换为协方差矩阵
denoised_cov = np.outer(volatilities, volatilities) * denoised_corr
# 计算风险平价权重(使用降噪后的协方差)
weights_rp = compute_risk_parity_weights(denoised_cov)
结果: 用降噪相关性做风险平价,样本外夏普比率能高出 12-18%。
应用 3:均值-方差优化(如果你非用不可)
降噪能让均值-方差优化没那么糟(但仍然算不上好):
from scipy.optimize import minimize
def mean_variance_optimization(expected_returns, denoised_cov, target_return):
"""
用降噪后的协方差矩阵做均值-方差优化。
"""
n = len(expected_returns)
# 目标:最小化组合方差
def portfolio_variance(weights):
return weights @ denoised_cov @ weights
# 约束条件
constraints = [
{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}, # 权重之和为 1
{'type': 'eq', 'fun': lambda w: w @ expected_returns - target_return} # 目标收益率
]
bounds = [(0, 1) for _ in range(n)] # 仅做多
result = minimize(portfolio_variance, x0=np.ones(n)/n, method='SLSQP',
bounds=bounds, constraints=constraints)
return result.x
# 用降噪后的协方差替代原始协方差
weights = mean_variance_optimization(expected_returns, denoised_cov, target_return=0.08)
改善: 样本外夏普比率从 0.42 提升到 0.55(+31%),但仍不如 HRP(0.68)。
退休投资组合的实操落地
什么时候该降噪
| 场景 | 是否降噪? | 理由 |
|---|---|---|
| 10 个以上资产,5 年以上数据 | 是 | T/N 高于 100,降噪效果显著 |
| 均值-方差优化 | 是 | 减少过拟合和持仓集中 |
| 风险平价组合 | 是 | 对相关性估计敏感 |
| HRP(本身已经稳健) | 可选 | 额外带来 5-10% 的提升 |
| 3-5 个资产,2 年数据 | 否 | 数据不足(T/N 低于 50) |
| 等权重组合 | 否 | 根本不使用相关性 |
再平衡方案
降噪会让权重更稳定,从而降低换手率:
推荐的再平衡频率
不做降噪: 每月或每季度(权重不稳定)
做了降噪: 每半年或每年(权重稳定)
税务好处: 再平衡频率降低 → 应税账户每年可省下 1-2% 的税
计算效率
降噪带来的计算成本微乎其微:
- 特征值分解: 50 个资产约 0.1 秒
- Marcenko-Pastur 计算: 可以忽略不计
- 矩阵重构: 约 0.05 秒
- 总开销: 不到 0.2 秒(对退休投资组合而言完全无关紧要)
代码库与完整实现
代码库: code-repos/institutional-strategies/covariance_denoising/
包含的文件:
denoise.py—— 完整的 RMT 降噪实现example.py—— 用 10 只 ETF 组合做的降噪前后对比README.md—— API 文档与理论说明requirements.txt—— 依赖项(numpy、pandas、scipy)
许可证: MIT(可自由使用和修改)
延伸阅读
学术论文:
- Laloux 等人(1999)——《Noise Dressing of Financial Correlation Matrices》
- Bun 等人(2016)——《Cleaning Large Correlation Matrices: Tools from Random Matrix Theory》
- López de Prado(2020)——《Machine Learning for Asset Managers》(第 2 章)
相关文章:
- 层次风险平价 —— 稳健的投资组合构建
- Meta-Labeling —— 用机器学习决定仓位规模
- 全天候投资组合(即将上线)—— 基于市场状态的资产配置
要点回顾
✅ 你学到了什么
- 相关性矩阵有 70-94% 是噪声 —— 数据有限时,估计误差占据主导
- 随机矩阵理论给出了解法 —— Marcenko-Pastur 分布把信号和噪声分开
- 降噪让投资组合改善 15-31% —— 夏普比率更高、回撤更小、权重更稳定
- 算法很简单: 过滤特征值,把噪声替换成平均值,再重构矩阵
- 适用于任何优化器 —— HRP、风险平价、均值-方差都能受益
- 降低再平衡频率 —— 权重稳定性提升 57% → 税负和成本更低
⚠️ 重要免责声明
过往业绩不代表未来表现。 降噪能改善相关性估计,但无法消除估计风险。
本文不构成投资建议。 本文仅用于教育目的。在实施任何策略之前,请咨询专业理财顾问。
数据要求。 降噪要求 T/N 高于 50(观测值与资产数之比)。数据不足时不要使用。
市场状态切换。 降噪假设相关性是稳定的。重大的市场状态切换(2008、2020)会让估计失效。