本文为 Python 60 Days Challenge 课程学习整理,原作者与原 Notebook 链接见「课程资料」。代码按章节顺序运行;语法示意和故意报错的反例已单独标注。
文中保留的截图、性能表和数值属于原讲义的历史示例,不是本次修订后的重新训练结果。实际输出受数据、版本、随机种子和训练预算影响。
打卡任务
- 阅读本节讲义或 Notebook
- 跑通示例代码
- 整理 3 个关键点
- 完成当日打卡输出
课程资料
- 训练营讲义:https://docs.qq.com/doc/DTFhndExSRGNHS3B6?nlc=1
- GitHub 仓库:https://github.com/cheer932041235/Python60DaysChallenge
- 本日 Notebook:day20 奇异值分解.ipynb
学习内容
DAY 20
今天的公式很多,如果有的同学你的vscode的ipynb文件中markdown的单元格无法渲染latex格式的公式,你需要去插件市场安装插件 markdown all in one 然后重启你的vscode

今天的打卡内容介绍下特征降维中非特征筛选的方法
首先需要介绍一个经典的工具SVD奇异值分解,他是很多降维算法的基础
相信大家在考研期间都考过线性代数,今天我们来回顾一下经典的考研题目,你就会知道之前的线性代数就是在为这里埋下伏笔。
当然可以!在考研数学中,特征值分解(Eigenvalue Decomposition)相关的内容通常出现在线性代数部分,常见题目类型包括求矩阵的特征值和特征向量、判断矩阵是否可对角化、以及利用特征值分解进行矩阵的对角化。这些题目往往以计算题或证明题的形式出现。
考研数学线性代数典型题目:特征值分解相关
题目 1:求矩阵的特征值和特征向量
题目:给定矩阵
$$ A = \begin{bmatrix} 4 & 1 \ 2 & 3 \end{bmatrix} $$
求矩阵 $A$ 的特征值和对应的特征向量。
解答:
求特征值
特征值 $\lambda$ 满足特征方程 $\det(A - \lambda I) = 0$。
计算 $A - \lambda I$:$$ A - \lambda I = \begin{bmatrix} 4 - \lambda & 1 \ 2 & 3 - \lambda \end{bmatrix} $$
求行列式:
$$ \det(A - \lambda I) = (4 - \lambda)(3 - \lambda) - 1 \cdot 2 = \lambda^2 - 7\lambda + 10 = 0 $$
解二次方程:
$$ \lambda^2 - 7\lambda + 10 = 0 \implies \lambda = \frac{7 \pm \sqrt{49 - 40}}{2} = \frac{7 \pm 3}{2} $$
因此,特征值为:
$$ \lambda_1 = 5, \quad \lambda_2 = 2 $$
求特征向量
对于 $\lambda_1 = 5$:
代入 $A - \lambda_1 I$,解方程 $(A - 5I)\mathbf{x} = 0$:$$ A - 5I = \begin{bmatrix} -1 & 1 \ 2 & -2 \end{bmatrix} $$
解线性方程组:
$$ -x_1 + x_2 = 0 \implies x_2 = x_1 $$
取 $x_1 = 1$,则特征向量为:
$$ \mathbf{x}_1 = \begin{bmatrix} 1 \ 1 \end{bmatrix} $$
对于 $\lambda_2 = 2$:
代入 $A - \lambda_2 I$,解方程 $(A - 2I)\mathbf{x} = 0$:$$ A - 2I = \begin{bmatrix} 2 & 1 \ 2 & 1 \end{bmatrix} $$
解线性方程组:
$$ 2x_1 + x_2 = 0 \implies x_2 = -2x_1 $$
取 $x_1 = 1$,则特征向量为:
$$ \mathbf{x}_2 = \begin{bmatrix} 1 \ -2 \end{bmatrix} $$
答案:
特征值:$\lambda_1 = 5$,$\lambda_2 = 2$
特征向量:对应 $\lambda_1 = 5$ 的特征向量为 $\begin{bmatrix} 1 \ 1 \end{bmatrix}$,对应 $\lambda_2 = 2$ 的特征向量为 $\begin{bmatrix} 1 \ -2 \end{bmatrix}$。
题目 2:矩阵对角化
题目:给定矩阵
$$ A = \begin{bmatrix} 5 & -2 \ -2 & 5 \end{bmatrix} $$
判断矩阵 $A$ 是否可对角化,若可对角化,求对角矩阵 $\Lambda$ 和可逆矩阵 $Q$,使得 $A = Q \Lambda Q^{-1}$。
解答:
求特征值
计算特征方程 $\det(A - \lambda I) = 0$:$$ A - \lambda I = \begin{bmatrix} 5 - \lambda & -2 \ -2 & 5 - \lambda \end{bmatrix} $$
行列式:
$$ \det(A - \lambda I) = (5 - \lambda)^2 - 4 = \lambda^2 - 10\lambda + 21 = 0 $$
解方程:
$$ \lambda^2 - 10\lambda + 21 = 0 \implies \lambda = \frac{10 \pm \sqrt{100 - 84}}{2} = \frac{10 \pm 4}{2} $$
特征值:
$$ \lambda_1 = 7, \quad \lambda_2 = 3 $$
求特征向量
对于 $\lambda_1 = 7$:
$$ A - 7I = \begin{bmatrix} -2 & -2 \ -2 & -2 \end{bmatrix} $$
解 $(A - 7I)\mathbf{x} = 0$:
$$ -2x_1 - 2x_2 = 0 \implies x_1 + x_2 = 0 \implies x_2 = -x_1 $$
取 $x_1 = 1$,特征向量:
$$ \mathbf{x}_1 = \begin{bmatrix} 1 \ -1 \end{bmatrix} $$
对于 $\lambda_2 = 3$:
$$ A - 3I = \begin{bmatrix} 2 & -2 \ -2 & 2 \end{bmatrix} $$
解 $(A - 3I)\mathbf{x} = 0$:
$$ 2x_1 - 2x_2 = 0 \implies x_1 = x_2 $$
取 $x_1 = 1$,特征向量:
$$ \mathbf{x}_2 = \begin{bmatrix} 1 \ 1 \end{bmatrix} $$
判断是否可对角化
矩阵 $A$ 有两个不同的特征值,且每个特征值对应的特征向量线性无关(因为 $\mathbf{x}_1$ 和 $\mathbf{x}_2$ 不成比例),因此矩阵 $A$ 可对角化。构造对角矩阵 $\Lambda$ 和矩阵 $Q$
对角矩阵 $\Lambda$ 由特征值构成:$$ \Lambda = \begin{bmatrix} 7 & 0 \ 0 & 3 \end{bmatrix} $$
矩阵 $Q$ 由特征向量按列排列:
$$ Q = \begin{bmatrix} 1 & 1 \ -1 & 1 \end{bmatrix} $$
验证 $A = Q \Lambda Q^{-1}$
先求 $Q^{-1}$。$Q$ 的行列式:$$ \det(Q) = 1 \cdot 1 - (-1) \cdot 1 = 2 $$
因此:
$$ Q^{-1} = \frac{1}{2} \begin{bmatrix} 1 & -1 \ 1 & 1 \end{bmatrix} $$
计算 $Q \Lambda Q^{-1}$(略去具体计算步骤,结果应为原矩阵 $A$)。
答案:
矩阵 $A$ 可对角化,对角矩阵 $\Lambda = \begin{bmatrix} 7 & 0 \ 0 & 3 \end{bmatrix}$,可逆矩阵 $Q = \begin{bmatrix} 1 & 1 \ -1 & 1 \end{bmatrix}$。
题目 3:利用特征值分解求矩阵幂
题目:已知矩阵
$$ A = \begin{bmatrix} 3 & 1 \ 1 & 3 \end{bmatrix} $$
利用特征值分解求 $A^{10}$。
解答:
求特征值和特征向量
特征方程:$$ \det(A - \lambda I) = \det\begin{bmatrix} 3 - \lambda & 1 \ 1 & 3 - \lambda \end{bmatrix} = (3 - \lambda)^2 - 1 = \lambda^2 - 6\lambda + 8 = 0 $$
解得:
$$ \lambda_1 = 4, \quad \lambda_2 = 2 $$
对于 $\lambda_1 = 4$,特征向量:
$$ \mathbf{x}_1 = \begin{bmatrix} 1 \ 1 \end{bmatrix} $$
对于 $\lambda_2 = 2$,特征向量:
$$ \mathbf{x}_2 = \begin{bmatrix} 1 \ -1 \end{bmatrix} $$
构造 $Q$ 和 $\Lambda$
$$ Q = \begin{bmatrix} 1 & 1 \ 1 & -1 \end{bmatrix}, \quad \Lambda = \begin{bmatrix} 4 & 0 \ 0 & 2 \end{bmatrix} $$
求 $A^{10}$
因为 $A = Q \Lambda Q^{-1}$,所以:$$ A^{10} = (Q \Lambda Q^{-1})^{10} = Q \Lambda^{10} Q^{-1} $$
计算 $\Lambda^{10}$:
$$ \Lambda^{10} = \begin{bmatrix} 4^{10} & 0 \ 0 & 2^{10} \end{bmatrix} = \begin{bmatrix} 1048576 & 0 \ 0 & 1024 \end{bmatrix} $$
求 $Q^{-1}$:
$$ \det(Q) = -2, \quad Q^{-1} = \frac{1}{-2} \begin{bmatrix} -1 & -1 \ -1 & 1 \end{bmatrix} = \begin{bmatrix} 0.5 & 0.5 \ 0.5 & -0.5 \end{bmatrix} $$
计算 $A^{10} = Q \Lambda^{10} Q^{-1}$(具体计算略,结果如下):
$$ A^{10} = \begin{bmatrix} 524800 & 523776 \ 523776 & 524800 \end{bmatrix} $$
答案:
$$ A^{10} = \begin{bmatrix} 524800 & 523776 \ 523776 & 524800 \end{bmatrix} $$
总结
考研数学中与特征值分解相关的题目主要集中在以下几类:
- 计算特征值和特征向量:通过特征方程求解。
- 矩阵对角化:判断矩阵是否可对角化,并求对角化矩阵。
- 利用特征值分解求矩阵幂或函数:通过分解简化高次幂计算。
- 证明题:如证明某些矩阵性质与特征值的关系。
线性代数基本概念回顾
上述题目应该勾起了你们的一些回忆,我们再来回顾下其中的一些基本概念。
1. 正交矩阵(Orthogonal Matrix)
定义
正交矩阵是指一个方阵 $Q$,满足其转置矩阵与自身的乘积为单位矩阵,即:
$$ Q^T Q = I $$
其中:
- $Q^T$ 是 $Q$ 的转置矩阵。
- $I$ 是单位矩阵(对角线为 1,其余为 0)。
这意味着正交矩阵的列向量(或行向量)是单位向量且两两正交。
性质
- 正交矩阵的逆矩阵等于其转置矩阵:$Q^{-1} = Q^T$。
- 正交矩阵的行列式值为 $+1$ 或 $-1$。
- 正交矩阵表示旋转或反射变换,不会改变向量的长度(保持欧几里得范数)。
简单案例
考虑一个 2×2 的正交矩阵(表示二维平面上的旋转):
$$ Q = \begin{bmatrix} \cos\theta & -\sin\theta \ \sin\theta & \cos\theta \end{bmatrix} $$
验证其正交性:
$$ Q^T Q = \begin{bmatrix} \cos\theta & \sin\theta \ -\sin\theta & \cos\theta \end{bmatrix} \begin{bmatrix} \cos\theta & -\sin\theta \ \sin\theta & \cos\theta \end{bmatrix} = \begin{bmatrix} \cos^2\theta + \sin^2\theta & -\cos\theta\sin\theta + \sin\theta\cos\theta \ -\sin\theta\cos\theta + \sin\theta\cos\theta & \sin^2\theta + \cos^2\theta \end{bmatrix} = \begin{bmatrix} 1 & 0 \ 0 & 1 \end{bmatrix} = I $$
这个矩阵表示一个角度为 $\theta$ 的旋转,旋转不改变向量长度,符合正交矩阵的性质。
在 SVD 中的作用
在 SVD 中,$U$ 和 $V$ 都是正交矩阵,分别对输入和输出空间进行旋转或反射。
2. 特征值与特征向量(Eigenvalue and Eigenvector)
定义
对于一个方阵 $A$,如果存在一个非零向量 $v$ 和一个标量 $\lambda$,使得:
$$ A v = \lambda v $$
则:
- $\lambda$ 称为 $A$ 的特征值(eigenvalue)。
- $v$ 称为 $A$ 的特征向量(eigenvector)。
特征向量表示矩阵 $A$ 在某些方向上只进行缩放(不改变方向)的向量,特征值表示缩放的比例。
性质
- 特征向量可以有多个,每个特征向量对应一个特征值。
- 特征值可以是实数或复数,取决于矩阵 $A$ 的性质。
- 如果 $A$ 是对称矩阵(见下文),其特征值是实数,且特征向量可以正交化。
简单案例
考虑一个 2×2 矩阵:
$$ A = \begin{bmatrix} 4 & 0 \ 0 & 2 \end{bmatrix} $$
求解特征值和特征向量:
特征值通过求解特征方程 $\det(A - \lambda I) = 0$ 得到:
$$ \det\begin{bmatrix} 4 - \lambda & 0 \ 0 & 2 - \lambda \end{bmatrix} = (4 - \lambda)(2 - \lambda) = 0 $$
解得 $\lambda_1 = 4$,$\lambda_2 = 2$。
对于 $\lambda_1 = 4$,代入 $A - \lambda I$ 求解 $v$:
$$ \begin{bmatrix} 0 & 0 \ 0 & -2 \end{bmatrix} v = 0 \quad \Rightarrow \quad v_1 = \begin{bmatrix} 1 \ 0 \end{bmatrix} $$
对于 $\lambda_2 = 2$:
$$ \begin{bmatrix} 2 & 0 \ 0 & 0 \end{bmatrix} v = 0 \quad \Rightarrow \quad v_2 = \begin{bmatrix} 0 \ 1 \end{bmatrix} $$
因此,特征值分别为 4 和 2,对应的特征向量为 $\begin{bmatrix} 1 \ 0 \end{bmatrix}$ 和 $\begin{bmatrix} 0 \ 1 \end{bmatrix}$。
在 SVD 中的作用
在 SVD 中,特征值和特征向量的概念用于计算奇异值和奇异向量。SVD 的奇异值是通过对 $A^T A$ 或 $A A^T$ 的特征值取平方根得到的,特征向量则与奇异向量相关。
3. 对称矩阵(Symmetric Matrix)
定义
对称矩阵是一个方阵 $A$,满足其转置矩阵等于自身,即:
$$ A = A^T $$
这意味着矩阵 $A$ 的元素关于主对角线对称:$a_{ij} = a_{ji}$。
性质
- 对称矩阵的特征值都是实数。
- 对称矩阵的特征向量可以选择为正交的(即可以构成正交矩阵)。
- 对称矩阵可以通过特征值分解表示为 $A = Q \Lambda Q^T$,其中 $Q$ 是正交矩阵,$\Lambda$ 是特征值对角矩阵。
简单案例
一个简单的对称矩阵:
$$ A = \begin{bmatrix} 5 & 2 \ 2 & 3 \end{bmatrix} $$
验证其对称性:$A^T = \begin{bmatrix} 5 & 2 \ 2 & 3 \end{bmatrix} = A$,满足对称矩阵定义。
计算特征值:
- 特征方程:$\det(A - \lambda I) = \det\begin{bmatrix} 5 - \lambda & 2 \ 2 & 3 - \lambda \end{bmatrix} = (5 - \lambda)(3 - \lambda) - 4 = \lambda^2 - 8\lambda + 11 = 0$
- 解得 $\lambda = \frac{8 \pm \sqrt{64 - 44}}{2} = \frac{8 \pm \sqrt{20}}{2} = 4 \pm \sqrt{5}$,均为实数。
特征向量可以通过代入计算得到,且可以正交化。
在 SVD 中的作用
在 SVD 中,我们构造 $A^T A$ 和 $A A^T$,这两个矩阵都是对称矩阵,因此可以进行特征值分解,进而求解奇异值和奇异向量。
4. 单位矩阵与矩阵分解的基础
单位矩阵(Identity Matrix)
单位矩阵 $I$ 是一个对角线上全为 1,其余位置为 0 的方阵。例如,2×2 的单位矩阵为:
$$ I = \begin{bmatrix} 1 & 0 \ 0 & 1 \end{bmatrix} $$
单位矩阵在矩阵运算中相当于数字中的 1,任何矩阵乘以单位矩阵结果不变。
矩阵分解
矩阵分解是将一个矩阵表示为几个简单矩阵乘积的过程。常见的分解包括:
- 特征值分解(适用于对称矩阵):$A = Q \Lambda Q^T$。
- 奇异值分解(适用于任意矩阵):$A = U \Sigma V^T$。
矩阵分解在降维、数据压缩和特征提取中非常重要。
简单案例
对于对称矩阵 $A = \begin{bmatrix} 4 & 0 \ 0 & 2 \end{bmatrix}$,其特征值分解为:
$$ A = \begin{bmatrix} 1 & 0 \ 0 & 1 \end{bmatrix} \begin{bmatrix} 4 & 0 \ 0 & 2 \end{bmatrix} \begin{bmatrix} 1 & 0 \ 0 & 1 \end{bmatrix} $$
这表明 $A$ 已经被分解为特征向量矩阵和特征值对角矩阵的乘积形式。
在 SVD 中的作用
SVD 是一种更广义的矩阵分解方法,适用于非方阵,而特征值分解是 SVD 计算的基础步骤。
总结与联系
- 正交矩阵:列向量正交且单位化,在 SVD 中用于旋转或反射($U$ 和 $V$)。
- 特征值与特征向量:描述矩阵在某些方向上的缩放特性,是计算奇异值的基础。
- 对称矩阵:具有实特征值和正交特征向量,SVD 通过构造 $A^T A$ 和 $A A^T$ 利用其性质。
- 矩阵分解:将复杂矩阵分解为简单矩阵乘积,是降维和数据分析的核心工具。
奇异值分解(SVD)的输入和输出:
- 输入:一个任意的矩阵 $A$,尺寸为 $m \times n$(其中 $m$ 是行数,$n$ 是列数,可以是矩形矩阵,不必是方阵)。
奇异值分解(SVD)得到的三个矩阵 $U$、$\Sigma$ 和 $V^T$ 各有其特定的意义和用途,下面我简要说明它们的作用:
**$U$** (左奇异向量矩阵) :
- 是一个 $m \times m$ 的正交矩阵,列向量是矩阵 $A A^T$ 的特征向量。
- 作用:表示原始矩阵 $A$ 在行空间(样本空间)中的主方向或基向量。简单来说,$U$ 的列向量描述了数据在行维度上的“模式”或“结构”。
- 应用:在降维中,$U$ 的前几列可以用来投影数据到低维空间,保留主要信息(如在图像处理中提取主要特征)。
**$\Sigma$** (奇异值矩阵) :
- 是一个 $m \times n$ 的对角矩阵,对角线上的值是奇异值(singular values),按降序排列,非负。
- 作用:奇异值表示原始矩阵 $A$ 在每个主方向上的“重要性”或“能量”。较大的奇异值对应更重要的特征,较小的奇异值对应噪声或次要信息。
- 应用:通过选择前 $k$ 个较大的奇异值,可以实现降维,丢弃不重要的信息(如数据压缩、去噪)。
**$V^T$** (右奇异向量矩阵的转置) :
- 是 $V$ 的转置,$V$ 是一个 $n \times n$ 的正交矩阵,列向量是矩阵 $A^T A$ 的特征向量。
- 作用:表示原始矩阵 $A$ 在列空间(特征空间)中的主方向或基向量。简单来说,$V$ 的列向量描述了数据在列维度上的“模式”或“结构”。
- 应用:类似 $U$,$V$ 的前几列可以用来投影数据到低维空间,提取主要特征。
整体作用:
结合起来,$A = U \Sigma V^T$ 意味着原始矩阵 $A$ 可以被分解为一系列主方向($U$ 和 $V$)和对应的权重($\Sigma$)的组合。这种分解揭示了数据的内在结构。
主要应用:
- 降维:通过保留前 $k$ 个奇异值及其对应的 $U$ 和 $V$ 的列向量,可以近似重建 $A$,减少数据维度(如 PCA 的基础)。
- 数据压缩:如图像压缩,丢弃小的奇异值以减少存储空间。
- 去噪:小的奇异值往往对应噪声,丢弃它们可以提高数据质量。
- 推荐系统:如矩阵分解,用于预测用户评分矩阵中的缺失值。
简单来说,$U$、$\Sigma$ 和 $V^T$ 提供了数据的核心结构信息,帮助我们在保留主要信息的同时简化数据处理。
输出:SVD 将矩阵 $A$ 分解为三个矩阵的乘积形式,即 $A = U \Sigma V^T$,其中:
- $U$:一个 $m \times m$ 的正交矩阵,列向量是 $A A^T$ 的特征向量,称为左奇异向量矩阵。
- $\Sigma$:一个 $m \times n$ 的对角矩阵,对角线上的元素是非负的奇异值(singular values),通常按降序排列,表示 $A$ 的“重要性”或“能量”。
- $V^T$:一个 $n \times n$ 的正交矩阵的转置,$V$ 的列向量是 $A^T A$ 的特征向量,称为右奇异向量矩阵。
奇异值的应用
奇异值分解(SVD)后,原始矩阵 $A$ 被分解为 $A = U \Sigma V^T$,这种分解是等价的,意味着通过 $U$、$\Sigma$ 和 $V^T$ 的乘积可以完全重构原始矩阵 $A$,没有任何信息损失。
但在实际应用中,我们通常不需要保留所有的奇异值和对应的向量,而是可以通过筛选规则选择排序靠前的奇异值及其对应的向量来实现降维或数据压缩。以下是这个过程的核心思想:
奇异值的排序:
- 在 $\Sigma$ 矩阵中,奇异值(对角线上的值)是按降序排列的。靠前的奇异值通常较大,代表了数据中最重要的信息或主要变化方向;靠后的奇异值较小,代表次要信息或噪声。
- 奇异值的大小反映了对应向量对原始矩阵 $A$ 的贡献程度。
筛选规则:
我们可以根据需求选择保留前 $k$ 个奇异值($k$ 是一个小于原始矩阵秩的数),并丢弃剩余的较小奇异值。
常见的筛选规则包括:
- 固定数量:直接选择前 $k$ 个奇异值(例如,前 10 个)。
- 累计方差贡献率:计算奇异值的平方(代表方差),选择累计方差贡献率达到某个阈值(如 95%)的前 $k$ 个奇异值。
- 奇异值下降幅度:观察奇异值下降的“拐点”,在下降明显变缓的地方截断。
降维与近似:
- 保留前 $k$ 个奇异值后,我们只取 $U$ 矩阵的前 $k$ 列(记为 $U_k$,尺寸为 $m \times k$)、$\Sigma$ 矩阵的前 $k$ 个奇异值(记为 $\Sigma_k$,尺寸为 $k \times k$)、以及 $V^T$ 矩阵的前 $k$ 行(记为 $V_k^T$,尺寸为 $k \times n$)。
- 近似矩阵为 $A_k = U_k \Sigma_k V_k^T$,这个矩阵是原始矩阵 $A$ 的低秩近似,保留了主要信息,丢弃了次要信息或噪声。
- 这种方法在降维(如主成分分析 PCA)、图像压缩、推荐系统等领域非常常用。
对应的向量:
- $U$ 的列向量和 $V$ 的列向量分别对应左右奇异向量。保留前 $k$ 个奇异值时,$U_k$ 的列向量代表数据在行空间中的主要方向,$V_k$ 的列向量代表数据在列空间中的主要方向。
- 这些向量与奇异值一起,构成了数据的主要“模式”或“结构”。
总结:SVD 分解后原始矩阵是等价的,但通过筛选排序靠前的奇异值和对应的向量,我们可以实现降维,保留数据的主要信息,同时减少计算量和噪声影响。这种方法是许多降维算法(如 PCA)和数据处理技术的基础。
实际案例
输出解释:
- 原始矩阵 $A$ 被分解为 $U$、$\Sigma$(由
sigma表示)和 $V^T$。 - 通过 $U \cdot \Sigma \cdot V^T$ 的矩阵乘法,可以完全重构原始矩阵 $A$,几乎没有信息损失(可能有非常小的数值误差)。
矩阵降维案例
import numpy as np
# 创建一个矩阵 A (5x3)
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12],
[13, 14, 15]])
print("原始矩阵 A:")
print(A)
# 进行 SVD 分解
U, sigma, Vt = np.linalg.svd(A, full_matrices=False)
print("\n奇异值 sigma:")
print(sigma)
# 保留前 k=1 个奇异值进行降维
k = 1
U_k = U[:, :k] # 取 U 的前 k 列,因为要保持行数不变
sigma_k = sigma[:k] # 取前 k 个奇异值
Vt_k = Vt[:k, :] # 取 Vt 的前 k 行,因为要保持列数不变
# 近似重构矩阵 A,常用于信号or图像筛除噪声
A_approx = U_k @ np.diag(sigma_k) @ Vt_k
print("\n保留前", k, "个奇异值后的近似矩阵 A_approx:")
print(A_approx)
# 计算近似误差
error = np.linalg.norm(A - A_approx, 'fro') / np.linalg.norm(A, 'fro')
print("\n近似误差 (Frobenius 范数相对误差):", error)
可以看到,再保留了k=1个奇异值后,近似误差仅为 4.19%,表明这种降维方式非常有效,丢失的信息很少。
在机器学习中,如果对训练集进行 SVD 降维后训练模型,而测试集的特征数量与降维后的训练集不一致(测试集仍保持原始特征数量),该如何处理?
1. 问题分析
- 训练集降维:假设训练集有 1000 个样本,50 个特征,通过 SVD 降维后保留 $k=10$ 个特征,得到形状为
(1000, 10)的新数据。模型基于这 10 个特征进行训练。 - 测试集问题:测试集假设有 200 个样本,仍然是 50 个特征。如果直接输入测试集到模型中,特征数量不匹配(模型期望 10 个特征,测试集有 50 个),会导致错误。
- 核心问题:如何确保测试集也能被正确地降维到与训练集相同的 $k$ 个特征空间?
2. 解决方案:对测试集应用相同的变换
在机器学习中,降维(如 SVD、PCA 等)是一种数据预处理步骤。训练集和测试集必须经过相同的变换,以确保数据分布一致。具体到 SVD,步骤如下:
- 训练阶段:对训练集 $X_{train}$ 进行 SVD 分解,得到 $U$, $\Sigma$, 和 $V^T$,并保存 $V^T$ 矩阵(或其前 $k$ 行)用于降维变换。
- 测试阶段:使用从训练集得到的 $V^T$ 矩阵,将测试集 $X_{test}$ 投影到相同的低维空间,得到降维后的测试数据。
- 原因:$V^T$ 矩阵定义了从原始特征空间到低维特征空间的映射关系,测试集必须使用相同的映射以保持一致性。
数学上,假设训练集 SVD 分解为 $X_{train} = U \Sigma V^T$,我们保留前 $k$ 个奇异值对应的 $V_k^T$(形状为 $k \times 50$)。测试集降维公式为:
$$ X_{test_reduced} = X_{test} \cdot V_k^T.T $$
其中 $V_k^T.T$ 是 $V_k^T$ 的转置(形状为 $50 \times k$),$X_{test}$ 是形状为 (n_test, 50) 的测试集矩阵,降维后 $X_{test_reduced}$ 的形状为 (n_test, k)。
3. 为什么不能对测试集单独做 SVD?
- 如果对测试集单独进行 SVD,会得到不同的 $V^T$ 矩阵,导致测试集和训练集的低维空间不一致,模型无法正确处理测试数据。
- 训练集的 $V^T$ 矩阵代表了训练数据的特征映射规则,测试集必须遵循相同的规则,否则会引入数据泄漏或不一致性问题。
4. 代码示例:训练集和测试集的 SVD 降维
以下是一个完整的代码示例,展示如何对训练集进行 SVD 降维,训练模型,并对测试集应用相同的降维变换。
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# 设置随机种子以便结果可重复
np.random.seed(42)
# 模拟数据:1000 个样本,50 个特征
n_samples = 1000
n_features = 50
X = np.random.randn(n_samples, n_features) * 10 # 随机生成特征数据
y = (X[:, 0] + X[:, 1] > 0).astype(int) # 模拟二分类标签
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"训练集形状: {X_train.shape}")
print(f"测试集形状: {X_test.shape}")
# 对训练集进行 SVD 分解
U_train, sigma_train, Vt_train = np.linalg.svd(X_train, full_matrices=False)
print(f"Vt_train 矩阵形状: {Vt_train.shape}")
# 选择保留的奇异值数量 k
k = 10
Vt_k = Vt_train[:k, :] # 保留前 k 行,形状为 (k, 50)
print(f"保留 k={k} 后的 Vt_k 矩阵形状: {Vt_k.shape}")
# 降维训练集:X_train_reduced = X_train @ Vt_k.T
X_train_reduced = X_train @ Vt_k.T
print(f"降维后训练集形状: {X_train_reduced.shape}")
# 使用相同的 Vt_k 对测试集进行降维:X_test_reduced = X_test @ Vt_k.T
X_test_reduced = X_test @ Vt_k.T
print(f"降维后测试集形状: {X_test_reduced.shape}")
# 训练模型(以逻辑回归为例)
model = LogisticRegression(random_state=42)
model.fit(X_train_reduced, y_train)
# 预测并评估
y_pred = model.predict(X_test_reduced)
accuracy = accuracy_score(y_test, y_pred)
print(f"测试集准确率: {accuracy}")
# 计算训练集的近似误差(可选,仅用于评估降维效果)
X_train_approx = U_train[:, :k] @ np.diag(sigma_train[:k]) @ Vt_k
error = np.linalg.norm(X_train - X_train_approx, 'fro') / np.linalg.norm(X_train, 'fro')
print(f"训练集近似误差 (Frobenius 范数相对误差): {error}")
6. 实际操作中的注意事项
标准化数据:在进行 SVD 之前,通常需要对数据进行标准化(均值为 0,方差为 1),以避免某些特征的量纲差异对降维结果的影响。可以使用
sklearn.preprocessing.StandardScaler。from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)注意:
scaler 必须在训练集上fit,然后对测试集只用transform,以避免数据泄漏。选择合适的 $k$:可以通过累计方差贡献率(explained variance ratio)选择 $k$,通常选择解释 90%-95% 方差的 $k$ 值。代码中可以计算:
explained_variance_ratio = np.cumsum(sigma_train**2) / np.sum(sigma_train**2) print(f"前 {k} 个奇异值的累计方差贡献率: {explained_variance_ratio[k-1]}")使用 sklearn 的 TruncatedSVD:
sklearn 提供了TruncatedSVD类,专门用于高效降维,尤其适合大规模数据。它直接计算前 $k$ 个奇异值和向量,避免完整 SVD 的计算开销。from sklearn.decomposition import TruncatedSVD svd = TruncatedSVD(n_components=k, random_state=42) X_train_reduced = svd.fit_transform(X_train) X_test_reduced = svd.transform(X_test) print(f"累计方差贡献率: {sum(svd.explained_variance_ratio_)}")
Day20 奇异值分解
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法