02 表征学习:从高维数据中提取核心洞见

90 分钟学习安排:从尺度到 PCA 结果

  • 目标: 诊断量纲与缺失;手算二维 PCA;解释方差比与载荷;区分 PCA、LDA 与仅用于探索的非线性嵌入。

  • 学习顺序:

    • 预处理 15 分钟 → PCA 直觉、手算和推导 30 分钟 → LDA 比较 15 分钟 → 长三角股票案例 25 分钟 → 总结 5 分钟。

    • MDS、流形学习与稀疏表示可在课后选学。

  • 先修先答: 若变量 A 的标准差是 B 的 100 倍,直接用协方差矩阵做 PCA 会怎样?

  • 反馈: A 可能仅凭量纲主导 PC1;除非单位本身有明确含义,否则标准化器只能在训练期拟合。

欢迎来到第二章:表征学习

今日议程:

  1. 引言: 为何经济与金融学需要“降维”?
  2. 数据预处理: 成功的基石
  3. Part 1: 线性方法 (PCA, LDA, MDS)
  4. Part 2: 非线性流形学习 (Isomap, LLE, t-SNE)
  5. Part 3: 高级主题 (稀疏表征)
  6. 总结: 如何为你的问题选择合适的工具

本章核心问题:为何要在经济金融学中学习“降维”?

想象一下,我们想预测一家公司的股票回报。我们手头可能有多少变量?

  • 公司内部数据: 上百个财务比率 (P/E, ROA, 杠杆率…)
  • 市场数据: 历史价格、交易量、波动率…
  • 宏观经济数据: GDP、利率、通胀率、失业率…
  • 另类数据: 卫星图像、新闻情绪、供应链信息…

我们轻易就会得到一个维度高达数百甚至数千的数据集。

我们正面临“数据丰富,信息贫乏”的困境

数据量的爆炸式增长,不直接等同于洞见的增长。表征学习的目标就是从噪音中提取信号。

我们正面临“数据丰富,信息贫乏”的困境 图中以“应对维度灾难 (The Curse of Dimensionality)、高维空间、充满噪声与冗余 (Noisy & Redundant)、表征学习、发现有意义的结构”呈现“我们正面临“数据丰富,信息贫乏”的困境”涉及的对象、方向或比较关系。 应对维度灾难 (The Curse of Dimensionality) 高维:噪声与冗余 表征学习 提取有效结构 低维:结构清晰

这就是所谓的维度灾难(Curse of Dimensionality)

什么是“维度灾难”?

  • 随着维度 d 的增加,固定的样本量会变得越来越稀疏;

  • 若希望维持相同的覆盖分辨率,所需网格单元数与样本量可能随维度呈指数增长。

  • 距离是否“集中”还取决于分布、度量与标准化,不能只凭维度作结论。

什么是“维度灾难”? 图中以“维度灾难 (Curse of Dimensionality)、1D 空间、数据高度密集、2D 空间、数据开始稀疏”呈现“什么是“维度灾难”?”涉及的对象、方向或比较关系。 维度灾难 (Curse of Dimensionality) 1D 空间 数据高度密集 2D 空间 数据开始稀疏 3D 空间 数据极其稀疏

“维度灾难”是建模与分析的共同敌人

当数据维度 d 过高时,会出现一系列严重问题:

问题类别 具体表现 对经济学研究的影响
计算效率 网格搜索或穷举的状态数可能呈指数增长;许多具体算法本身仍是多项式复杂度 必须区分样本需求、搜索空间与实际算法复杂度。
数据稀疏性 固定数量的样本在高维空间中变得极其稀疏 样本不具有代表性,难以找到统计上显著的关系。
模型过拟合 模型学习到了样本中的噪声,而非真实的规律 模型在样本内表现完美,但在样本外(预测)时表现极差。
多重共线性 许多特征高度相关 难以识别单个变量的真实影响,参数估计不稳定。

表征学习(或称降维)正是解决这一问题的关键钥匙。

表征学习的目标:信息损失最小,化繁为简

我们的目标是将一个高维的样本集 \(X \in \mathbb{R}^{d \times N}\) 映射到一个低维空间 \(Z \in \mathbb{R}^{l \times N}\),其中 \(l \ll d\)

\[ \large{ \underbrace{ \begin{pmatrix} z_{1,n} \\ \vdots \\ z_{l,n} \end{pmatrix} }_{Z_n \in \mathbb{R}^{l \times 1}} = \underbrace{ \begin{pmatrix} w_{1,1} & \cdots & w_{1,d} \\ \vdots & \ddots & \vdots \\ w_{l,1} & \cdots & w_{l,d} \end{pmatrix} }_{W^T \in \mathbb{R}^{l \times d}} \underbrace{ \begin{pmatrix} x_{1,n} \\ \vdots \\ x_{d,n} \end{pmatrix} }_{X_n \in \mathbb{R}^{d \times 1}} } \]

核心要求

降维后的新表征 \(Z\) 必须保留原始数据 \(X\) 中最重要的“结构”或“信息”。不同的算法对“结构”的定义不同,从而产生了不同的降维方法。

动工前的准备:数据预处理是模型成功的基石

在我们应用任何复杂的降维算法之前,必须对原始数据进行清洗。这就像盖楼前必须打好地基。

数据预处理步骤 A three-step flowchart: Raw Data -> Clean & Impute -> Standardize -> Ready Data. 原始数据离群点 · 缺失异量纲 1. 清洗填充异常与缺失 2. 标准化统一量纲 准备就绪

预处理问题1:离群点 (Outliers)

极端值会严重扭曲模型的方差计算(例如PCA),使其偏向离群点的方向。

预处理问题1:离群点 (Outliers) 图中以“离群点对主成分分析 (PCA) 的影响、无离群点 (No Outliers)、PC1 (最大方差方向)、有离群点 (With Outliers)、离群点”呈现“预处理问题1:离群点 (Outliers)”涉及的对象、方向或比较关系。 离群点对主成分分析 (PCA) 的影响 无离群点 (No Outliers) PC1 (最大方差方向) 有离群点 (With Outliers) 离群点 被扭曲的 PC1

常见处理方法: Winsorization(缩尾)、对数变换、或直接移除。

预处理问题2 & 3:缺失值与量纲

  • 数据丢失 (Missing Data): 大多数算法无法处理缺失值 NaN
    • 常用策略:
      1. 删除: 如果缺失比例很小,直接删除该行或列。
      2. 填充: 用均值、中位数、或更复杂的模型(如K-近邻)进行填充。
  • 量纲不一致 (Inconsistent Scales): 如果“公司市值”(万亿)和“市盈率”(几十)放在一起分析,市值会完全主导结果。
    • 解决方案: 特征缩放。最常用的是标准化 (Standardization),将数据处理为均值为0,方差为1。
    • 公式: \(x'_{i} = \large{\frac{x_i - \mu_i}{\sigma_i}}\)

Part 1: 线性降维方法

主成分分析(PCA): 寻找数据变化最大的方向

PCA是最经典、最常用的线性降维方法。

  • 核心思想: 旋转坐标系,使得新的坐标轴(主成分)能最大化地解释数据的方差。
  • 目标: 保留最大的样本方差;这不等于自动保留与预测、因果识别或经济解释最相关的信息。

PCA 几何:PC1 沿最大方差方向

Principal Component Analysis Intuition A scatter plot showing PC1 aligned with the maximum variance direction. PC1 (最大方差方向) PC2

PCA的目标函数

PCA的目标是找到一个投影方向(一个单位向量 \(w\)),使得原始数据 \(X\) 在该方向上的投影的方差最大。

  • 单方向投影:\(X\in\mathbb{R}^{d\times N}\) 的“特征×样本”约定下,\(\mathbf z=X^T\mathbf w\in\mathbb{R}^{N}\)
  • 投影方差: \(\operatorname{Var}(\mathbf z)=\mathbf w^T S\mathbf w\),其中 \(S=XX^T/N\in\mathbb{R}^{d\times d}\) 是中心化数据的协方差矩阵。

优化问题可以写成:

\[ \large{\max_{w} \quad w^T S w} \]

\[ \large{\text{s.t.} \quad w^T w = 1} \]

PCA 推导:先写拉格朗日函数

我们使用拉格朗日乘子法来求解这个带约束的优化问题。

第 1 步

在单位向量约束下,把最大化投影方差写为拉格朗日函数:

\[ \large{L(w, \lambda) = w^T S w - \lambda(w^T w - 1)} \]

PCA 推导:一阶条件连接约束与方向

第 2 步:\(w\) 求导并令其为 0:

\[ \large{\frac{\partial L}{\partial w} = 2Sw - 2\lambda w = 0} \]

PCA 推导:得到特征值问题

  • 第 3 步: 整理一阶条件:

\[ \large{Sw = \lambda w} \]

  • 结论:
    • 最优的投影方向(主成分)\(w\) 就是协方差矩阵 \(S\)特征向量,对应的方差大小就是特征值 \(\lambda\)

    • 最大的特征值对应的特征向量,就是第一主成分。

PCA 的五步工作流

将抽象的数学理论转化为一个清晰的操作流程。

PCA 五步工作流 两行五卡片流程:标准化、协方差、特征分解、选择主成分、转换数据。 1. 标准化原始数据 2. 计算协方差矩阵S 3. 求解特征值与特征向量 4. 选择前 ℓ 个主成分 5. 转换数据Z = WᵀX

PCA 手算:先预测主方向

给定三个二维观测 \(\mathbf{x}_1=(2,1)^\top\)\(\mathbf{x}_2=(0,0)^\top\)\(\mathbf{x}_3=(-2,-1)^\top\)

  1. 计算均值 \(\bar{\mathbf{x}}\) 与样本协方差 \(\mathbf{S}\)
  2. 比较单位方向 \(\mathbf{v}_1=(2,1)^\top/\sqrt5\)\(\mathbf{v}_2=(-1,2)^\top/\sqrt5\)
  3. 计算投影 \(z_i=\mathbf{v}^\top(\mathbf{x}_i-\bar{\mathbf{x}})\) 的样本方差。

先预测

哪条方向保留更多方差?独立算完再进入答案页。

PCA 手算:逐步答案

均值为 \(\bar{\mathbf{x}}=(0,0)^\top\)。以 \(n-1=2\) 为分母:

\[ \large{\mathbf{S}=\frac{1}{2}\sum_{i=1}^{3}\mathbf{x}_i\mathbf{x}_i^\top=\begin{bmatrix}4&2\\2&1\end{bmatrix}} \]

  • 沿 \(\mathbf{v}_1\)\(z=(\sqrt5,0,-\sqrt5)\)\(s_z^2=(5+0+5)/2=5\)
  • 沿 \(\mathbf{v}_2\)\(z=(0,0,0)\)\(s_z^2=0\)
  • 确认:\(\mathbf{S}\mathbf{v}_1=5\mathbf{v}_1\)\(\mathbf{S}\mathbf{v}_2=0\mathbf{v}_2\)

所以 PC1 为 \(\mathbf{v}_1\),解释方差比 \(5/(5+0)=100\%\);它也高于只投影到横轴所得的方差 \(4\)

线性判别分析(LDA): 为分类而生的降维

  • LDA是一种监督学习的降维算法。

  • 与PCA寻找最大方差不同,LDA的目标是找到一个投影方向,使得不同类别的数据点尽可能分开,相同类别的数据点尽可能聚集

LDA Objective LDA aims to maximize between-class distance and minimize within-class distance. 最大化“类间”距离 最小化“类内”距离

LDA的目标函数

  • 类内散布矩阵 (Within-class Scatter): \(S_w = \sum_{c=1}^{C} \sum_{x_i \in c} (x_i - \mu_c)(x_i - \mu_c)^T\)

    • 衡量每个类别内部数据的离散程度。我们希望它小。
  • 类间散布矩阵 (Between-class Scatter): \(S_b = \sum_{c=1}^{C} N_c (\mu_c - \mu)(\mu_c - \mu)^T\)

    • 衡量不同类别中心之间的离散程度。我们希望它大。
  • 对单个投影方向 \(w\),Fisher 准则是广义 Rayleigh 商;

  • 对多维投影,通常取广义特征问题中最大的若干特征方向,并在 \(W^TS_wW=I\) 的约束下最大化投影后的类间散布:

\[ \begin{aligned} J(w)&=\frac{w^T S_b w}{w^T S_w w},\\ \max_W\;&\operatorname{tr}(W^T S_b W) \quad\text{s.t.}\quad W^T S_w W=I. \end{aligned} \]

\(S_w\) 奇异时,应使用正则化或广义特征值/SVD 求解,而不是直接求逆。

PCA:最大方差仍可能保留类别重叠

PCA:只最大化整体方差;本例的水平 PC1 仍让两类大量重叠。

PCA vs. LDA:一个直观的对比 图中以“PC1”呈现“PCA vs. LDA:一个直观的对比”涉及的对象、方向或比较关系。 PC1

LDA:监督信息把投影转向类别分离

LDA 提高类间相对类内散布,因而更利于区分类别,但不保证完美分开。

PCA vs. LDA:一个直观的对比 图中以“LD1”呈现“PCA vs. LDA:一个直观的对比”涉及的对象、方向或比较关系。 LD1

LDA的数学求解:一个广义特征值问题

最大化 \(J(W)\) 的问题,最终可以转化为求解一个广义特征值问题

\[ \large{S_b w = \lambda S_w w} \]

两边同乘 \(S_w^{-1}\),可以得到一个更熟悉的形式:

\[ \large{S_w^{-1} S_b w = \lambda w} \]

结论

LDA的最优投影方向 \(w\),是矩阵 \(S_w^{-1} S_b\) 的特征向量。

多维缩放(MDS): 从距离重构“地图”

学习提示:完成 PCA/LDA 比较后,先进入长三角股票案例;MDS、非线性方法与稀疏表示可在课后选学。

MDS与PCA和LDA的出发点完全不同。它不直接处理特征矩阵 \(X\),而是从一个已知的距离(或不相似度)矩阵 \(D\) 出发。

  • 核心思想: 在低维空间中寻找一组点 \(Z\),使得这些点之间的欧氏距离与原始的距离矩阵 \(D\) 尽可能一致。
  • 应用场景:
    • 当我们无法得到原始特征,但能度量对象间的不相似性时。

    • 例如,问卷调查中“品牌A和品牌B的相似度”,或者基因序列间的“编辑距离”。

MDS的直观类比:绘制城市地图

想象一下,你只知道国内几个主要城市之间的直线飞行距离,但没有任何经纬度信息。

MDS Analogy with Chinese Cities An illustration showing the concept of reconstructing a map of Chinese cities from a distance matrix using MDS. 输入: 距离矩阵 (千米) 北京 上海 北京 上海 0 1080 1080 0 MDS 输出: 2D坐标 (地图) 北京 上海 成都

MDS的目标就是根据这个距离矩阵,反推出每个城市在二维地图上的最佳坐标。

Part 2: 非线性降维方法(流形学习)

线性方法的局限:当数据结构是弯曲的

PCA, LDA等线性方法假设数据分布在一个平坦的超平面上。但如果数据的内在结构是弯曲的呢?

线性方法的局限:当数据结构是弯曲的 图中以“1. 三维“瑞士卷”流形、数据内在结构是弯曲的、A点、B点、沿流形距离 (Geodesic Distance) 很远”呈现“线性方法的局限:当数据结构是弯曲的”涉及的对象、方向或比较关系。 1. 三维“瑞士卷”流形 数据内在结构是弯曲的 A点 B点 沿流形的测地距离很远 线性投影 (PCA) 2. 线性PCA投影 (错误) 丢失了非线性结构 A' B' 投影后欧氏距离被错误拉近

线性方法PCA会错误地将欧氏距离很远的点(如A和B)投影到一起,无法“展开”这个卷。

流形学习的核心思想:数据镶嵌在低维流形上

  • 流形(Manifold)假设:
    • 生成机制:高维观测由少数潜在变量(内在维度)生成。

    • 几何结构:样本点位于嵌入高维空间的低维流形上。

  • 目标: “展开”这个流形,找到能反映数据真实邻近关系的低维坐标。
  • 与线性方法的区别: 流形学习关注局部结构,认为只有邻近点之间的欧氏距离是可信的。

Isomap: 沿着“表面”测量距离

Isomap是对MDS的一个巧妙改进,它用测地线距离 (Geodesic Distance) 代替了欧氏距离。

Isomap: 沿着“表面”测量距离 两个完整框架对比平面空间中的欧氏直线距离,以及弯曲流形上的测地线距离与无效捷径。 1. 平面空间 AB 欧氏距离 最短路径是一条直线 2. 弯曲流形 AB 测地线:沿表面 欧氏捷径:对 Isomap 无效

步骤:

  1. 构建邻域图: 对每个点,只连接它与最近的K个邻居。
  2. 计算最短路径: 使用图算法(如Dijkstra)计算图中任意两点间的最短路径长度,作为测地线距离的近似。
  3. 应用MDS: 将计算出的最短路径距离矩阵作为输入,应用经典的MDS算法进行降维。

局部线性嵌入(LLE): 保持局部线性关系

LLE的假设是,每个数据点都可以由其近邻点线性重构,并且这个局部几何关系在低维空间中也应该保持不变。

局部线性嵌入(LLE): 保持局部线性关系 图中以“局部线性嵌入 (LLE): “展开”流形、1. 在高维空间中定义局部关系、Xᵢ、高维流形、计算重构权重 Wᵢⱼ”呈现“局部线性嵌入(LLE): 保持局部线性关系”涉及的对象、方向或比较关系。 局部线性嵌入 (LLE): “展开”流形 1. 高维空间:重构邻域 Xᵢ 高维流形 计算重构权重 Wᵢⱼ LLE 嵌入 2. 低维空间:保持权重 Zᵢ 低维嵌入 保持 Wᵢⱼ,而非距离 局部形状可以改变

LLE的核心: 保持重构权重, 而非距离

LLE的核心: 保持重构权重, 而非距离 图中以“LLE的核心: 保持重构权重 (Wᵢⱼ), 而非距离、1. 原始高维邻域、M₁、Xᵢ、在此计算权重 W (决定了相对位置)”呈现“LLE的核心: 保持重构权重, 而非距离”涉及的对象、方向或比较关系。 LLE的核心: 保持重构权重 (Wᵢⱼ), 而非距离 1. 原始邻域 M₁ Xᵢ 由相对位置计算 W 1 2 2. LLE:保持权重 M₂ Zᵢ 形状改变,比例不变 Zᵢ = Σ Wᵢⱼ Zⱼ 1 2 3. 刚性对比 保持距离 非 LLE 目标

t-SNE: 数据可视化的瑞士军刀

t-SNE(t-distributed Stochastic Neighbor Embedding)是一种常用的高维数据探索性可视化工具,可将局部邻域关系嵌入到 2D 或 3D;它不提供“最强”或聚类正确性的证据。

  • 核心思想(概率匹配):
    1. 在高维空间中,将点与点之间的欧氏距离转化为一个条件概率,表示点i会选择点j作为其邻居的可能性(使用高斯分布)。
    2. 在低维空间中,也定义一个类似的条件概率(使用更“长尾”的t分布)。
    3. 通过优化,调整低维空间中点的位置,使得两个空间的概率分布尽可能相似(最小化KL散度)。
  • 优势:常能帮助观察局部邻域与可能的群组结构;是否真正分簇仍须在原空间用预先定义的指标验证。

t-SNE 关键参数与注意事项

  • Perplexity (困惑度):
    • 这是最重要的参数,大致可以理解为每个点考虑的“有效近邻数”。
    • 一般取值在 5 到 50 之间。较低的值关注局部结构,较高的值关注全局结构。
  • 注意事项 (非常重要!):
    1. 不要过分解读簇间距离: t-SNE图上两个簇离得远,不代表它们在原始空间中就“更”远。
    2. 不要过分解读簇的大小: 某个簇在图上面积大,不代表它包含更多的数据点或方差更大。
    3. t-SNE是用于可视化的探索性工具,不是用于严格的聚类分析。

Part 3: 高级主题:稀疏表征

稀疏表征:用最少的“积木”来搭建信号

前面的方法旨在“压缩”数据,而稀疏表征的出发点不同。

  • 核心思想: 任何一个信号(如一段经济时间序列),都可以被看作是由一个“字典” \(\Psi\) 中的少数几个“原子”(基向量)线性组合而成的。

    \[ \large{x = \Psi s} \]

    其中 \(s\) 是一个稀疏向量,意味着它的大部分元素都为零。

图解:字典乘以稀疏系数形成信号

Sparse Representation Analogy A complex signal is constructed by a few active elements from a large dictionary. 信号 x = 字典 Ψ × 稀疏系数 s 0.8 1.2

稀疏表征:经济学直觉

经济学直觉

市场的复杂动态可能只是由少数几个“潜在经济状态”或“冲击”组合驱动的。稀疏表征旨在找到这些最核心的驱动因子。

压缩感知:用更少的采样恢复完整信号

稀疏性假设带来一个惊人的推论:压缩感知

  • 恢复条件:
    • 系数 \(s\)\(k\)-稀疏,且感知矩阵 \(\Theta=\Phi\Psi\) 满足 RIP 或足够不相干。

    • 测量数约需满足 \(l\gtrsim Ck\log(d/k)\),才能支持稳定重构。

  • 无噪声且求解器条件满足时可以精确恢复;有噪声时只能保证误差受控。

\[ \large{z = \Phi x = \Phi \Psi s = \Theta s} \]

  • \(z\): 少量观测值 (\(l \times 1\))
  • \(\Phi\): 观测矩阵 (\(l \times d\), \(l \ll d\))
  • \(\Theta\): 感知矩阵

压缩感知:恢复条件与失败边界

  • 恢复条件:稀疏度、测量矩阵、测量数与求解器必须共同满足定理条件;“稀疏”本身不够。
  • 失败情形:测量与字典高度相干、\(l\) 太小、噪声过大或信号仅近似稀疏时,恢复可能偏误或不唯一。
  • 目标: 已知 \(z\), \(\Theta\),求解稀疏向量 \(s\)。这是现代信号处理和MRI等领域的基石。

重构算法:匹配追踪(Matching Pursuit)

如何从 \(z\)\(\Theta\) 中找到稀疏的 \(s\) 是一个NP-hard问题。匹配追踪是一种贪心算法,用迭代的方式来逼近解。

  1. 初始化: 残差 \(r_0 = z\),稀疏解 \(s=0\)
  2. 寻找最相关原子: 在字典 \(\Theta\) 中,找到与当前残差 \(r\) 最相关的原子(内积最大)。
  3. 更新解: 将该原子的贡献加入到解 \(s\) 中。
  4. 更新残差: 从当前残差 \(r\) 中减去该原子的贡献。
  5. 迭代: 重复步骤2-4,直到残差足够小或达到迭代次数。

经济学应用:筛查稀疏跳跃与离群点

单位字典下的一阶差分稀疏化只能筛查异常跳跃,不能单凭尖峰确认结构性断点。

  • 信号 (x): 经济时间序列的一阶差分。

  • 字典 (Ψ): 一个单位矩阵。

  • 稀疏系数 (s): 单位字典下,s 就是差分序列;大的非零项标记候选跳跃。

  • 普通创新、离群值、季节性或波动率变化也会产生尖峰。

  • 若要声称“制度变化”,必须另设变点模型,说明发生变化的参数、噪声与依赖假设,并在独立窗口控制误报。

选学内容结束:下面进入最终思考

核心内容与学习目标回顾

  • 核心必会(90 分钟): 预处理 → PCA → LDA → 评价与解释。课后拓展:MDS、Isomap、LLE、t-SNE、稀疏表征与压缩感知。

回顾核心内容开场目标:①诊断量纲与缺失问题;②从特征值解释 PCA 方差;③区分无监督 PCA 与监督 LDA;④用测试期评价表征。

  • 回顾题: 若变量 A 的标准差是变量 B 的 100 倍,直接对协方差矩阵做 PCA 会怎样?
  • 答案: A 可能凭量纲主导第一主成分;除非单位本身有明确经济含义,否则应仅用训练期均值和标准差进行标准化。

形成性检查 1:PCA 数值确认

二维标准化数据的协方差矩阵特征值为 1.6 与 0.4。保留一个主成分时解释方差比是多少?

答案

\(1.6/(1.6+0.4)=0.8\),即 80%。特征向量给出投影方向,特征值给出该方向上的方差。

主要案例:长三角股票 PCA

  • 本例数据:
    • 来源:data/stock/stock_price_pre_adjusted.h5,key=data,4 只长三角代表性 A 股。

    • 口径:2018–2024 年的前复权 close;按交易日对齐并删除缺失日。

    • 边界:仅在 2018–2022 年训练期拟合标准化器与 PCA。

  • 邻近方法来源: Jolliffe & Cadima (2016), PCA 综述;以下载荷和解释方差均只由训练期估计。
Code
from pathlib import Path  # 使用统一路径对象定位数据文件

import pandas as pd  # 导入表格工具以读取并对齐本地行情
from sklearn.preprocessing import StandardScaler  # 在训练期统一各股票收益率尺度
from sklearn.decomposition import PCA  # 用主成分提取共同波动方向
# 公网下载:https://assets.qiufei.site/data/stock/stock_price_pre_adjusted.h5
# 下载后把下一行改为本机文件位置;按课程结构存放时可用 Path("data/stock/stock_price_pre_adjusted.h5")。
# Windows:Path(r"C:\qiufei\data\stock\stock_price_pre_adjusted.h5")
# macOS:Path("/Users/你的用户名/data/stock/stock_price_pre_adjusted.h5")
# Linux:Path("/home/你的用户名/data/stock/stock_price_pre_adjusted.h5")
price_path = Path("/home/ubuntu/r2_data_mount/data/stock/stock_price_pre_adjusted.h5")
company_ids = ['600276.XSHG', '600660.XSHG', '002648.XSHE', '002920.XSHE']  # 选择长三角代表性上市公司代码
price_parts = [pd.read_hdf(price_path, key='data', where=[f'order_book_id=="{company_id}"', 'date>=Timestamp("2018-01-01")', 'date<=Timestamp("2024-12-31")'], columns=['close']) for company_id in company_ids]  # 按公司与时期选择性载入收盘价
price_panel = pd.concat(price_parts).reset_index().pivot(index='date', columns='order_book_id', values='close')  # 构造日期乘公司的价格面板
return_panel = price_panel.pct_change(fill_method=None).dropna()  # 计算共同交易日收益率并删除缺失行
training_returns = return_panel.loc[:'2022-12-31']  # 固定 2018 至 2022 年为训练期
return_scaler = StandardScaler().fit(training_returns)  # 仅用训练期估计均值与标准差
scaled_training_returns = return_scaler.transform(training_returns)  # 将训练收益率转换为可比尺度
return_pca = PCA(n_components=2).fit(scaled_training_returns)  # 提取前两个共同波动主成分
pca_loadings = pd.DataFrame(return_pca.components_.T, index=training_returns.columns, columns=['PC1', 'PC2'])  # 将载荷映射回真实股票代码
pd.concat([pd.Series(return_pca.explained_variance_ratio_, index=['PC1', 'PC2'], name='variance_ratio'), pca_loadings.stack().rename('loading')], axis=0)  # 输出方差证据与载荷供解释
PC1                   0.471032
PC2                   0.206372
(002648.XSHE, PC1)    0.483942
(002648.XSHE, PC2)   -0.322402
(002920.XSHE, PC1)    0.515698
(002920.XSHE, PC2)   -0.390399
(600276.XSHG, PC1)    0.426722
(600276.XSHG, PC2)    0.862146
(600660.XSHG, PC1)    0.563705
(600660.XSHG, PC2)   -0.018706
dtype: float64

形成性检查 2:图能否支持结论?

t-SNE 图上两个簇相距很远,能否断言原高维空间中两类也同样远?

答案

不能。t-SNE 优先保持局部邻域,簇间全局距离、面积和方向通常不可作定量解释;应比较不同随机种子/困惑度并回到原空间验证。

分步练习:标准化的作用

  • 任务: 用同一训练期分别对原始收益率与标准化收益率做 PCA,比较 PC1 方差比和载荷排序。
  • 完整解答:
    • 建立 raw_pca = PCA(2).fit(training_returns),把 raw_pca.explained_variance_ratio_ 与 前面的案例 的结果并排;再比较两个 components_[0] 的绝对值排序。

    • 切分期必须相同。

    • 若排序改变,应解释为变量尺度/波动率影响,而不能宣称某公司“因果上更重要”。

Code
raw_pca = PCA(n_components=2).fit(training_returns)  # 在同一训练日期上拟合未标准化 PCA
raw_rank = training_returns.columns[abs(raw_pca.components_[0]).argsort()[::-1]].tolist()  # 按 PC1 绝对载荷排列原始收益变量
scaled_rank = training_returns.columns[abs(return_pca.components_[0]).argsort()[::-1]].tolist()  # 按 PC1 绝对载荷排列标准化变量
pd.DataFrame({'输入版本': ['原始收益率', '标准化收益率'], 'pc1_variance_ratio': [raw_pca.explained_variance_ratio_[0], return_pca.explained_variance_ratio_[0]], 'absolute_loading_rank': [raw_rank, scaled_rank]})  # 并排比较两次 PCA 的结果
Table 1
输入版本 pc1_variance_ratio absolute_loading_rank
0 原始收益率 0.500617 [002920.XSHE, 002648.XSHE, 600660.XSHG, 600276...
1 标准化收益率 0.471032 [600660.XSHG, 002920.XSHE, 002648.XSHE, 600276...

综合练习

  • 从本地 financial_statement.h5financial_data 选择 4 家长三角公司、至少 12 个季度与 5 个财务比率,对比 PCA 和 LDA 的二维表示;

  • 本文件的利润表字段是年初至今累计口径,目标定义为严格下一自然季度披露的累计净利润是否为正。

完整答案提醒

  • 说明字段、单位和信息可得时点;预处理只在训练期拟合;报告 PCA 方差与载荷、LDA 标签和样本外分类结果;最后说明局限与不确定性。

  • 特征只能使用决策时已经披露的版本,训练标签也必须在训练截止日前实现,不能使用未来重述值或全样本均值。

综合练习完整答案:财务比率面板

Table 2
Code
from pathlib import Path  # 使用统一路径对象定位数据文件

import pandas as pd  # 读取并整理本地季度财务报表
from sklearn.preprocessing import StandardScaler  # 仅以训练期矩估计统一比率尺度
from sklearn.decomposition import PCA  # 提取无监督的二维财务表征
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis  # 估计监督式线性判别方向
# 公网下载:https://assets.qiufei.site/data/stock/financial_statement.h5
# 下载后把下一行改为本机文件位置;按课程结构存放时可用 Path("data/stock/financial_statement.h5")。
# Windows:Path(r"C:\qiufei\data\stock\financial_statement.h5")
# macOS:Path("/Users/你的用户名/data/stock/financial_statement.h5")
# Linux:Path("/home/你的用户名/data/stock/financial_statement.h5")
statement_path = Path("/home/ubuntu/r2_data_mount/data/stock/financial_statement.h5")
transfer_ids = ['600418.XSHG', '600460.XSHG', '600537.XSHG', '600596.XSHG']  # 选择四家长三角公司
statement_columns = ['order_book_id', 'quarter', 'info_date', 'operating_revenue', 'net_profit', 'total_assets', 'total_liabilities', 'equity_parent_company']  # 声明原始字段
statement_parts = [pd.read_hdf(statement_path, key='financial_data', where=f'order_book_id=="{company_id}"', columns=statement_columns) for company_id in transfer_ids]  # 按公司选择性载入必要列
statement_frame = pd.concat(statement_parts, ignore_index=True)  # 合并四家公司为季度面板
Table 3
Code
statement_frame['info_date'] = pd.to_datetime(statement_frame['info_date'])  # 统一披露日期类型
statement_frame['quarter_period'] = pd.PeriodIndex(statement_frame['quarter'], freq='Q')  # 将季度标签转为可排序期间
statement_frame = statement_frame[statement_frame['quarter_period'] <= pd.Period('2024Q4')]  # 确定截至 2024Q4 的报表
statement_frame = statement_frame.sort_values(['order_book_id', 'quarter_period', 'info_date']).drop_duplicates(['order_book_id', 'quarter_period'], keep='first')  # 每季只保留最早披露版本,禁止使用后来重述值
ratio_definitions = {'profit_margin': ('net_profit', 'operating_revenue'), 'roa': ('net_profit', 'total_assets'), 'debt_ratio': ('total_liabilities', 'total_assets'), 'asset_turnover': ('operating_revenue', 'total_assets'), 'equity_turnover': ('operating_revenue', 'equity_parent_company')}  # 定义五个无量纲比率
for ratio_name, (numerator_name, denominator_name) in ratio_definitions.items():  # 逐项按同一口径构造比率
    statement_frame[ratio_name] = statement_frame[numerator_name] / statement_frame[denominator_name]  # 用报表原值计算比率
statement_frame = statement_frame.sort_values(['order_book_id', 'quarter_period'])  # 在公司内部保持季度顺序
statement_frame['target_quarter'] = statement_frame.groupby('order_book_id')['quarter_period'].shift(-1)  # 保留同一公司下一条记录的季度以确认自然季度相邻性
statement_frame['next_profit'] = statement_frame.groupby('order_book_id')['net_profit'].shift(-1)  # 保留下季度净利润连续值
statement_frame['target_available_at'] = statement_frame.groupby('order_book_id')['info_date'].shift(-1)  # 记录下一季度标签首次可以检查的披露时点
statement_frame = statement_frame.replace([float('inf'), float('-inf')], pd.NA).dropna()  # 删除缺失比率、未知标签与不可计算记录
statement_frame = statement_frame[(statement_frame['target_quarter'] == statement_frame['quarter_period'] + 1) & (statement_frame['info_date'] < statement_frame['target_available_at'])]  # 同时排除跨季缺口与标签先于特征的异常任务
statement_frame['next_profit_positive'] = (statement_frame['next_profit'] > 0).astype(int)  # 仅对已观测利润构造符号标签
assert (statement_frame['target_quarter'] == statement_frame['quarter_period'] + 1).all()  # 确认每个标签来自严格下一自然季度而非下一条可用记录
assert (statement_frame['info_date'] < statement_frame['target_available_at']).all()  # 确认每条特征记录均先于其标签实现时点
  • 五个比率均为无量纲;原始金额字段延续 HDF 数据字典中的人民币单位。

  • operating_revenuenet_profit 按本地财务报表文件的年初至今累计口径使用,因此标签不是单季利润,而是严格下一自然季度披露的累计净利润符号。

综合练习完整答案:PCA 与 LDA 证据

Code
from sklearn.metrics import balanced_accuracy_score, confusion_matrix  # 评价测试期的分类表现
ratio_names = list(ratio_definitions)  # 固定五维模型输入顺序
statement_train = statement_frame[statement_frame['target_available_at'] <= pd.Timestamp('2022-12-31')]  # 训练截止日之前必须同时获得特征与下一期标签
statement_test = statement_frame[(statement_frame['info_date'] >= pd.Timestamp('2023-01-01')) & (statement_frame['target_available_at'] <= pd.Timestamp('2024-12-31'))]  # 按信息可得时点确定 2023—2024 评价样本
assert statement_train['target_available_at'].max() < statement_test['info_date'].min()  # 确认训练标签实现早于测试特征首次可得时点
ratio_scaler = StandardScaler().fit(statement_train[ratio_names])  # 只由训练期估计尺度
scaled_statement_train = ratio_scaler.transform(statement_train[ratio_names])  # 变换训练期比率
scaled_statement_test = ratio_scaler.transform(statement_test[ratio_names])  # 原样变换测试期比率
statement_pca = PCA(n_components=2).fit(scaled_statement_train)  # 只在训练期提取两个主成分
statement_test_scores = statement_pca.transform(scaled_statement_test)  # 为测试期生成二维坐标
statement_lda = LinearDiscriminantAnalysis().fit(scaled_statement_train, statement_train['next_profit_positive'])  # 只在训练期学习监督方向
statement_lda_prediction = statement_lda.predict(scaled_statement_test)  # 对测试期预测利润符号
pd.Series({'train_n': len(statement_train), 'test_n': len(statement_test), 'pc1_share': statement_pca.explained_variance_ratio_[0], 'pc2_share': statement_pca.explained_variance_ratio_[1], 'lda_balanced_accuracy': balanced_accuracy_score(statement_test['next_profit_positive'], statement_lda_prediction), 'confusion_matrix': confusion_matrix(statement_test['next_profit_positive'], statement_lda_prediction).tolist(), 'first_test_score': statement_test_scores[0].round(3).tolist()})  # 输出真实关键结果与二维坐标样例
Table 4
train_n                                174
test_n                                  18
pc1_share                         0.487445
pc2_share                         0.336838
lda_balanced_accuracy                  0.5
confusion_matrix         [[0, 5], [0, 13]]
first_test_score           [-1.293, 1.121]
dtype: object
  • 真实输出为训练 174、测试 18;PC1/PC2 分别解释 0.4874/0.3368,LDA 平衡准确率 0.5000,混淆矩阵为 \([[0,5],[0,13]]\)

  • 模型把所有测试季度都判为正利润,完全漏掉亏损季度,不能宣称稳健预测。

形成性检查 3:压缩感知的条件

“信号稀疏,所以 3 次任意测量一定能恢复 100 维信号。”对还是错?

答案:错。 还需要测量数随 \(k\log(d/k)\) 增长、感知矩阵满足 RIP/不相干性,并区分无噪声精确恢复与有噪声稳定恢复。

来源与延伸阅读

  • Jolliffe & Cadima (2016), “Principal component analysis: a review and recent developments”。
  • van der Maaten & Hinton (2008), “Visualizing Data using t-SNE”。
  • Candès & Tao (2005/2006), compressed sensing 与 RIP 原始论文。
  • 数据:本地 data/stock/financial_statement.h5,HDF key=financial_data,字段与累计口径如迁移任务所列;PCA 前面的案例 另使用本地 A 股前复权行情数据。

核心内容总结:PCA 与 LDA 的选择

课后选学

完成核心内容后,可以继续学习MDS、流形学习与稀疏表示,随后进入最终思考

方法 类型 核心思想 优点 缺点
PCA 线性, 无监督 最大化方差 简单、快速、可解释性强 无法处理非线性结构
LDA 线性, 有监督 最大化类别可分性 对分类问题效果好 需要类别标签,对类别分布有假设

拓展内容 总结:距离、流形与稀疏方法

方法 核心保留对象 关键边界
MDS 成对距离 依赖距离度量,计算量大
Isomap / LLE 测地线 / 局部重构 对邻域和噪声敏感
t-SNE 局部邻域概率 仅作探索图;全局距离不可定量解释
稀疏 / 压缩感知 少数原子 需要测量几何、样本数与求解条件

最终思考:降维非目的,而是理解数据的手段

在本章中,我们学习了从线性到非线性的多种表征学习(降维)方法。

  • 它们是探索性数据分析的强大工具,能帮助我们从看似混乱的高维数据中发现隐藏的结构,如因子、簇和低维流形。
  • 它们也是构建预测模型的关键预处理步骤,能有效提升模型的稳定性和泛化能力。

关键在于,始终要结合你的领域知识(经济学、金融学)来解释降维后的结果,赋予这些抽象的维度和结构现实的意义。

谢谢!

问题与讨论