2026年重磅升级已全面落地!欢迎加入专注财经数据与量化投研的【数据科学实战】知识星球!您将获取持续更新的《财经数据宝典》与《量化投研宝典》,双典协同提供系统化指引;星球内含300篇以上独有高质量文章,深度覆盖策略开发、因子分析、风险管理等核心领域,内容基本每日更新;同步推出的「量化因子专题教程」系列(含完整可运行代码与实战案例),系统详解因子构建、回测与优化全流程,并实现日更迭代。我们持续扩充独家内容资源,全方位赋能您的投研效率与专业成长。无论您是量化新手还是资深研究者,这里都是助您少走弯路、事半功倍的理想伙伴,携手共探数据驱动的投资未来!
引言
在量化金融领域,我们经常会遇到这样一个问题:手上有大量高度相关的特征变量,比如美国国债 1 个月、3 个月、1 年、2 年、5 年、10 年期的收益率——它们几乎在"说同一件事"。把这些高度共线性的变量一股脑喂给模型,不仅会拖慢计算速度,还会让预测模型"犯迷糊"。
怎么办?降维。
本文将带你使用 主成分分析(Principal Component Analysis,PCA) 这一经典的无监督学习方法,对美国国债收益率曲线进行降维处理。更令人惊叹的是,算法会自动从原始数据中"重新发现"债券市场的三大核心驱动力:水平(Level)、斜率(Slope) 和 曲率(Curvature)。
一、为什么需要降维?
想象你要预测经济走势,于是把 100 只科技股的价格全部输入模型。由于科技股通常同涨同跌,你实际上并没有给模型 100 条独立信息,而是把同一条信息重复了 100 遍。这就是多重共线性(Multicollinearity)。
降维技术的核心目标,就是把这 100 个变量压缩成 1~2 个"真正的"底层因子,在保留绝大部分信息的同时,大幅减少变量数量。
二、PCA 是什么?
PCA 是一种数学方法,能将一组相关变量转换为一组更少的、互不相关的新变量,称为主成分(Principal Components)。
它的工作原理可以这样理解:假设有一团 3D 数据点,形状像一根雪茄。PCA 会找到穿过雪茄的最长轴(方差最大的方向),称为"主成分 1";然后找到与第一条轴垂直的第二条轴(捕获次多方差),称为"主成分 2";以此类推。
最终,我们只保留前几个主成分,就能用极少的变量保留 95% 以上的原始信息。
三、实战:对美国国债收益率曲线做 PCA
3.1 获取数据
我们使用 pandas_datareader 从美联储 FRED 数据库下载历史国债收益率数据。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import pandas_datareader.data as web
import datetime
# 定义 FRED 中各期限国债的代码
tickers = [
'DGS1MO', 'DGS3MO', 'DGS6MO', 'DGS1', 'DGS2',
'DGS3', 'DGS5', 'DGS7', 'DGS10', 'DGS20', 'DGS30'
]
# 对应的可读标签
labels = [
'1M', '3M', '6M', '1Y', '2Y',
'3Y', '5Y', '7Y', '10Y', '20Y', '30Y'
]
# 获取 10 年的数据
start_date = datetime.datetime(2016, 1, 1)
end_date = datetime.datetime(2026, 1, 1)
print("正在从 FRED 获取数据...")
yield_data = web.DataReader(tickers, 'fred', start_date, end_date)
# 重命名列并删除缺失值(如节假日)
yield_data.columns = labels
yield_data.dropna(inplace=True)
print(f"数据加载完成:{yield_data.shape[0]} 个交易日,{yield_data.shape[1]} 个期限")
print(yield_data.head())
运行后你会看到类似如下的输出:
数据加载完成:2499 个交易日,11 个期限
1M 3M 6M 1Y 2Y 3Y 5Y 7Y 10Y 20Y 30Y
DATE
2016-01-04 0.17 0.22 0.49 0.61 1.02 1.31 1.73 2.06 2.24 2.64 2.98
2016-01-05 0.20 0.20 0.49 0.68 1.04 1.32 1.73 2.06 2.25 2.67 3.01
3.2 数据预处理:差分 + 标准化
这是一个关键的量化步骤。利率数据是非平稳的(有趋势性),PCA 通常应该在平稳数据上运行。因此我们分析的是收益率的日变动量,而非绝对水平。
from sklearn.preprocessing import StandardScaler
# 第一步:计算日收益率变动
yield_changes = yield_data.diff().dropna()
# 第二步:标准化数据
# PCA 对特征的尺度非常敏感,必须先将数据中心化并缩放
scaler = StandardScaler()
X_scaled = scaler.fit_transform(yield_changes)
# 转回 DataFrame 方便后续绘图
X_scaled_df = pd.DataFrame(
X_scaled,
columns=labels,
index=yield_changes.index
)
print("标准化后的日收益率变动(前 5 行):")
print(X_scaled_df.head())
为什么要做差分? 如果直接对原始收益率做 PCA,模型只会捕捉到十年间的宏观趋势,而非曲线的日常结构性变动。
为什么要标准化? PCA 寻找的是方差最大的方向。如果某个变量的量纲是千级别(如道琼斯指数),另一个是小数级别(如收益率),算法会误以为大数值代表更多方差。标准化让所有变量站在同一起跑线上。
3.3 拟合 PCA 模型
from sklearn.decomposition import PCA
# 初始化 PCA(先保留全部主成分)
pca = PCA()
# 在标准化数据上拟合
pca.fit(X_scaled)
# 获取每个主成分解释的方差比例
explained_variance = pca.explained_variance_ratio_
print("各主成分解释的方差比例:")
for i, var in enumerate(explained_variance):
print(f" PC{i+1}: {var:.4f} ({var*100:.2f}%)")
# 计算累积方差
cumulative_variance = np.cumsum(explained_variance)
print(f"\n前 3 个主成分的累积方差:{cumulative_variance[2]*100:.2f}%")
输出结果:
各主成分解释的方差比例:
PC1: 0.6507 (65.07%)
PC2: 0.1436 (14.36%)
PC3: 0.0893 (8.93%)
PC4: 0.0644 (6.44%)
...
前 3 个主成分的累积方差:88.36%
仅用 3 个主成分就解释了约 88% 的收益率曲线变动!我们成功地将 11 个变量压缩到了 3 个。
3.4 可视化 PCA 载荷
载荷(Loadings)告诉我们每个原始期限对新主成分的贡献权重,是理解主成分含义的关键。
# 提取前 3 个主成分的载荷(特征向量)
loadings = pca.components_[:3]
# 创建 DataFrame 方便绘图
loadings_df = pd.DataFrame(
loadings.T,
columns=['PC1(水平)', 'PC2(斜率)', 'PC3(曲率)'],
index=labels
)
# 绘制载荷图
plt.figure(figsize=(10, 6))
plt.plot(loadings_df['PC1(水平)'], marker='o', label='PC1:水平(平行移动)')
plt.plot(loadings_df['PC2(斜率)'], marker='s', label='PC2:斜率(扭转)')
plt.plot(loadings_df['PC3(曲率)'], marker='^', label='PC3:曲率(蝶式)')
plt.axhline(0, color='black', linestyle='--', alpha=0.5)
plt.title('美国国债收益率曲线的 PCA 载荷')
plt.xlabel('期限')
plt.ylabel('载荷(权重)')
plt.legend()
plt.grid(True)
plt.show()
3.5 解读结果
观察载荷图,三条线分别呈现出鲜明的形态:
PC1(蓝线)——水平(Level):载荷在所有期限上均为正值且相对平坦。这意味着当 PC1 增大时,所有期限的收益率同时上升或下降。算法自动发现了"水平移动"。
PC2(橙线)——斜率(Slope):载荷从短端的正值逐渐变为长端的负值,穿越了零线。这说明短期利率和长期利率在反向运动——曲线在变平或变陡。算法自动发现了"斜率变动"。
PC3(绿线)——曲率(Curvature):载荷呈现驼峰形状,短端和长端为正,中段(6 个月至 5 年)为负。中间部分独立于两端运动。算法自动发现了"曲率变动"。
四、进阶挑战:构建因子时间序列
我们已经知道主成分长什么样,但它们每天的值是多少呢?可以用 pca.transform() 计算:
# 将标准化数据投影到主成分空间,获取每天的因子值
pc_scores = pca.transform(X_scaled)
# 取前 3 个主成分,构建 DataFrame
pc_df = pd.DataFrame(
pc_scores[:, :3],
columns=['PC1(水平)', 'PC2(斜率)', 'PC3(曲率)'],
index=yield_changes.index
)
# 绘制 PC1 的累积值时间序列
plt.figure(figsize=(12, 5))
plt.plot(pc_df['PC1(水平)'].cumsum(), label='PC1 累积值(水平因子)')
plt.title('PC1(水平因子)时间序列(2016–2026)')
plt.xlabel('日期')
plt.ylabel('累积主成分值')
plt.legend()
plt.grid(True)
plt.show()
绘制出的 PC1 累积时间序列,应当与过去十年整体利率的涨落走势高度吻合。
五、PCA 还能用在哪里?
PCA 不仅可以用于收益率曲线分析。如果你对标普 500 成分股的日收益率做 PCA,通常会发现:PC1 几乎完美代表了"大盘方向"(Beta),PC2 可能代表"价值 vs. 成长"风格因子。这就是所谓的统计风险建模(Statistical Risk Modeling)。
总结
本文通过一个完整的实战案例,展示了如何用 PCA 解决量化金融中的"维度灾难"问题。核心要点如下:
PCA 的本质是找到数据方差最大的方向,将高维相关变量压缩为低维不相关的主成分。
预处理至关重要:对非平稳的利率数据先做差分(diff())使其平稳,再用 StandardScaler 标准化消除量纲影响。
实证结果:11 个期限的国债收益率曲线,仅 3 个主成分就解释了约 88% 的变动信息,分别对应债券市场公认的水平、斜率和曲率三大因子。
实际价值:将 3 个主成分(而非 11 个高度相关的收益率)作为模型输入,可以消除多重共线性、减少噪声,构建更稳定的交易模型。
如果你正在学习 Python 量化金融,PCA 是一个必须掌握的工具。希望这篇文章能帮你真正理解它的原理和应用。
参考文章
加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取本文完整研究解析、代码实现细节。财经数据与量化投研知识社区
2026年全面升级已落地!【数据科学实战】知识星球核心权益如下:
- 1. 双典系统赋能:获赠《财经数据宝典》与《量化投研宝典》完整文档,凝练多年实战经验,构建系统化知识框架;
- 2. 量化因子日更教程(2026重磅新增):每日更新「量化因子专题教程」,配套完整可运行代码与实战案例,深度拆解因子构建、回测与优化全流程;
- 3. 量化文章专题教程库:300+篇星球独有高质量教程式文章,系统覆盖策略开发、因子研究、风险管理等核心领域,内容基本每日更新,并配套精选学习资料与实战参考;
- 4. PyBroker实战课程:赠送《PyBroker-入门及实战》视频课程,手把手教学,快速掌握量化策略开发技能;
- 5. 财经数据支持:定期更新国内外财经数据,为策略研发提供精准、可靠的数据基础;
-
6. 顶尖学者与行业专家分享:年度邀请学术界博士与业界资深专家开展前沿论文精讲与实战案例分享,不少于4场,直击研究前沿与产业实践;
专家直连答疑:与核心开发者及领域专家实时互动,高效解决投研实战难题; - 7. 专业社群与专属福利:加入高质量交流社群,获取课程折扣及更多独家资源。
星球已沉淀丰富内容生态——涵盖量化文章专题教程库、因子日更系列、高频数据集、PyBroker实战课程、专家深度分享与实时答疑服务。无论您是初探量化的学习者,还是深耕领域的从业者,这里都是助您少走弯路、高效成长的理想平台。诚邀加入,共探数据驱动的投资未来!