主成分分析
PCA 找到高维数据中方差最大的方向。它是量化金融中因子提取、风险分解和数据可视化的主力工具。
目标:找到重要的方向
当你有 500 个资产时,一个 协方差矩阵包含 个独特的数字(对角线加上上三角或下三角)。其中大部分是噪声——不代表真实关系的结构。主成分分析(PCA) 找到数据中实际包含信号的几个方向,丢弃其余的。
核心思想很简单:任何数据集中,有些方向的变化大于其他方向。最大方差方向是最具信息量的方向——它以最少的维度捕获最多的结构。PCA 找到所有方差递减的正交方向,然后让你只保留前 个。
“正交”意味着这些方向互不相关——它们指向数据特征空间中独立的方向。
PCA 的五个步骤
给定具有 个观测值(行)和 个变量(列)的数据矩阵 :
步骤 1:中心化数据。 减去每列的均值,使每个变量的均值都为零。这确保第一个主成分不仅仅指向数据的平均位置。
步骤 2:计算协方差矩阵。 对于中心化数据,这就是:
步骤 3:求 的特征向量和特征值。 每个特征向量是一个主成分方向,其特征值告诉你沿该方向有多少方差。
步骤 4:按特征值排序(从大到小)。 最大特征值的特征向量指向最大方差方向。第二大特征值给出下一个正交方向,以此类推。
步骤 5:选择 个成分并投影数据。 第 个成分解释的方差比例为:
用 Python 实现
import numpy as np
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
np.random.seed(42)
n_assets = 20
n_days = 500
# 使用 Cholesky 分解生成相关收益率
L = np.random.randn(n_assets, n_assets) * 0.3
Sigma = L @ L.T + np.eye(n_assets) * 0.5 # 正定
returns = np.random.randn(n_days, n_assets) @ np.linalg.cholesky(Sigma).T
# 手动 PCA
returns_centered = returns - returns.mean(axis=0)
cov_matrix = np.cov(returns_centered.T)
eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
eigenvalues = eigenvalues[::-1] # 降序
# 解释方差
total_var = eigenvalues.sum()
explained = eigenvalues / total_var
cumulative = np.cumsum(explained)
# 绘制解释方差图
plt.figure(figsize=(10, 5))
plt.bar(range(1, n_assets + 1), explained * 100, alpha=0.6, label="Individual")
plt.plot(range(1, n_assets + 1), cumulative * 100, "ro-", label="Cumulative")
plt.axhline(y=95, color="g", linestyle="--", label="95% threshold")
plt.xlabel("Principal Component")
plt.ylabel("Variance Explained (%)")
plt.title("PCA: Variance Explained by Component")
plt.legend()
plt.show()
# 多少成分才能达到 95%?
k_95 = np.argmax(cumulative >= 0.95) + 1
print(f"解释 95% 方差所需的成分数: {k_95}")
提示词
用 numpy 和 matplotlib 手动实现 PCA:模拟相关收益,算协方差矩阵,做特征分解,画解释方差柱状图,找出达到 95% 方差需要的成分数。
使用 sklearn 使这更加简洁:
pca = PCA(n_components=0.95) # 保留 95% 的方差
reduced = pca.fit_transform(returns)
print(f"原始形状: {returns.shape}")
print(f"降维后形状: {reduced.shape}")
print(f"使用的成分数: {pca.n_components_}")
提示词
用 sklearn.decomposition.PCA(n_components=0.95) 对 20 资产 500 天的模拟收益做降维,打印原始形状、降维后形状和自动选的成分数。
金融应用:降维 500 股票相关矩阵
量化金融中的经典应用是将大规模相关矩阵缩减为其本质因子。PCA 可能会发现,仅 5 个主成分就能解释 80% 的变异——而不是追踪 500 只股票中每只与另外 499 只的相对变动。这些成分对应于可解释的市场因子,如市场贝塔、规模、价值、动量和波动率。
这并非巧合。经济和金融中的因子模型之所以发展,部分是因为同样的直觉——金融数据的大部分变异可以由少数潜在因子解释——这早于 PCA 但在数学上与之等价。
import numpy as np
# 模拟 100 资产月收益率
np.random.seed(0)
returns = np.random.randn(120, 100) * 0.02
# 相关矩阵
corr = np.corrcoef(returns.T)
# 相关矩阵上的 PCA
eigenvalues, _ = np.linalg.eigh(corr)
eigenvalues = eigenvalues[::-1]
# 解释方差
var_explained = eigenvalues / eigenvalues.sum()
cum_var = np.cumsum(var_explained)
# 多少成分解释 50%、70%、90%?
for threshold in [0.50, 0.70, 0.90]:
k = np.argmax(cum_var >= threshold) + 1
print(f"{threshold*100:.0f}% 方差: {k} 个成分")
提示词
用 numpy 演示 PCA 在金融中怎么用:模拟 100 资产 120 个月收益,算相关矩阵做 PCA,报告达到 50%、70%、90% 方差需要几个成分。
过拟合:成分过多或过少的风险
PCA 是一个工具,像任何工具一样,它可能被误用。保留太多成分(接近 )会同时保留噪声和信号。样本协方差矩阵本身是对真实协方差的有噪声估计,对它进行特征分解并不能消除这种噪声。事实上,样本协方差矩阵的最小的特征值大部分是噪声。
保留太少成分会丢弃真实结构。如果真正的数据生成过程有 20 个有意义的因子,但你只保留 3 个,你就欠拟合了——失去了影响收益的真实关系。
一个实用规则:在解释方差曲线中寻找”肘部”——添加更多成分收益递减的点。或者,保留足够解释 70–90% 方差的成分,视具体情况而定。
参考文献
Jolliffe, Principal Component Analysis, 2nd edition, Springer, Chapters 1–2. ISBN: 978-0387954424.
Hastie, Tibshirani & Friedman, The Elements of Statistical Learning, 2nd edition, Springer, Chapter 3. ISBN: 978-0387848570.