
2026年重磅升级已全面落地!欢迎加入专注财经数据与量化投研的【数据科学实战】知识星球!您将获取持续更新的《财经数据宝典》与《量化投研宝典》,双典协同提供系统化指引;星球内含300篇以上独有高质量文章,深度覆盖策略开发、因子分析、风险管理等核心领域,内容基本每日更新;同步推出的「量化因子专题教程」系列(含完整可运行代码与实战案例),系统详解因子构建、回测与优化全流程,并实现日更迭代。我们持续扩充独家内容资源,全方位赋能您的投研效率与专业成长。无论您是量化新手还是资深研究者,这里都是助您少走弯路、事半功倍的理想伙伴,携手共探数据驱动的投资未来!
在量化金融领域,我们经常会遇到这样一个问题:手上有大量高度相关的特征变量,比如美国国债 1 个月、3 个月、1 年、2 年、5 年、10 年期的收益率——它们几乎在"说同一件事"。把这些高度共线性的变量一股脑喂给模型,不仅会拖慢计算速度,还会让预测模型"犯迷糊"。
怎么办?降维。
本文将带你使用 主成分分析(Principal Component Analysis,PCA) 这一经典的无监督学习方法,对美国国债收益率曲线进行降维处理。更令人惊叹的是,算法会自动从原始数据中"重新发现"债券市场的三大核心驱动力:水平(Level)、斜率(Slope) 和 曲率(Curvature)。
想象你要预测经济走势,于是把 100 只科技股的价格全部输入模型。由于科技股通常同涨同跌,你实际上并没有给模型 100 条独立信息,而是把同一条信息重复了 100 遍。这就是多重共线性(Multicollinearity)。
降维技术的核心目标,就是把这 100 个变量压缩成 1~2 个"真正的"底层因子,在保留绝大部分信息的同时,大幅减少变量数量。
PCA 是一种数学方法,能将一组相关变量转换为一组更少的、互不相关的新变量,称为主成分(Principal Components)。
它的工作原理可以这样理解:假设有一团 3D 数据点,形状像一根雪茄。PCA 会找到穿过雪茄的最长轴(方差最大的方向),称为"主成分 1";然后找到与第一条轴垂直的第二条轴(捕获次多方差),称为"主成分 2";以此类推。
最终,我们只保留前几个主成分,就能用极少的变量保留 95% 以上的原始信息。
我们使用 pandas_datareader 从美联储 FRED 数据库下载历史国债收益率数据。
import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport pandas_datareader.data as webimport 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 = labelsyield_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 30YDATE2016-01-04 0.17 0.22 0.49 0.61 1.02 1.31 1.73 2.06 2.24 2.64 2.982016-01-05 0.20 0.20 0.49 0.68 1.04 1.32 1.73 2.06 2.25 2.67 3.01这是一个关键的量化步骤。利率数据是非平稳的(有趋势性),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 寻找的是方差最大的方向。如果某个变量的量纲是千级别(如道琼斯指数),另一个是小数级别(如收益率),算法会误以为大数值代表更多方差。标准化让所有变量站在同一起跑线上。
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 个。
载荷(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()观察载荷图,三条线分别呈现出鲜明的形态:
PC1(蓝线)——水平(Level):载荷在所有期限上均为正值且相对平坦。这意味着当 PC1 增大时,所有期限的收益率同时上升或下降。算法自动发现了"水平移动"。
PC2(橙线)——斜率(Slope):载荷从短端的正值逐渐变为长端的负值,穿越了零线。这说明短期利率和长期利率在反向运动——曲线在变平或变陡。算法自动发现了"斜率变动"。
PC3(绿线)——曲率(Curvature):载荷呈现驼峰形状,短端和长端为正,中段(6 个月至 5 年)为负。中间部分独立于两端运动。算法自动发现了"曲率变动"。
我们已经知道主成分长什么样,但它们每天的值是多少呢?可以用 pca.transform() 计算:
# 将标准化数据投影到主成分空间,获取每天的因子值pc_scores = pca.transform(X_scaled)# 取前 3 个主成分,构建 DataFramepc_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 不仅可以用于收益率曲线分析。如果你对标普 500 成分股的日收益率做 PCA,通常会发现:PC1 几乎完美代表了"大盘方向"(Beta),PC2 可能代表"价值 vs. 成长"风格因子。这就是所谓的统计风险建模(Statistical Risk Modeling)。
本文通过一个完整的实战案例,展示了如何用 PCA 解决量化金融中的"维度灾难"问题。核心要点如下:
PCA 的本质是找到数据方差最大的方向,将高维相关变量压缩为低维不相关的主成分。
预处理至关重要:对非平稳的利率数据先做差分(diff())使其平稳,再用 StandardScaler 标准化消除量纲影响。
实证结果:11 个期限的国债收益率曲线,仅 3 个主成分就解释了约 88% 的变动信息,分别对应债券市场公认的水平、斜率和曲率三大因子。
实际价值:将 3 个主成分(而非 11 个高度相关的收益率)作为模型输入,可以消除多重共线性、减少噪声,构建更稳定的交易模型。
如果你正在学习 Python 量化金融,PCA 是一个必须掌握的工具。希望这篇文章能帮你真正理解它的原理和应用。
2026年全面升级已落地!【数据科学实战】知识星球核心权益如下:
星球已沉淀丰富内容生态——涵盖量化文章专题教程库、因子日更系列、高频数据集、PyBroker实战课程、专家深度分享与实时答疑服务。无论您是初探量化的学习者,还是深耕领域的从业者,这里都是助您少走弯路、高效成长的理想平台。诚邀加入,共探数据驱动的投资未来!
好文推荐
1. 用 Python 打造股票预测系统:Transformer 模型教程(一)
2. 用 Python 打造股票预测系统:Transformer 模型教程(二)
3. 用 Python 打造股票预测系统:Transformer 模型教程(三)
4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)
6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用