数值分析:矩阵奇异值分解

1. 奇异值分解(SVD)

(1)奇异值分解

已知矩阵\(\bm{A} \in \R^{m \times n}\), 其奇异值分解为:

\[\bm{A} = \bm{U}\bm{S}\bm{V}^T \]

其中\(\bm{U} \in \R^{m \times m}\)\(\bm{V} \in \R^{n \times n}\)是正交矩阵,\(\bm{S} \in \R^{m \times n}\)是对角线矩阵。\(\bm{S}\)的对角线元素\(\bm{s}_1, \bm{s}_2,..., \bm{s}_{\min(m,n)}\)是矩阵的奇异值。

(2) 奇异值分解的求解

而求矩阵的奇异值的算法非常简单,对于实数域下的矩阵\(A\),我们只需要求\(A^TA\)的特征值和特征向量。其特征向量归一化后即右奇异向量\(\bm{v}_1,\bm{v}_2,...,\bm{v}_n\),其特征值开根号即对应的奇异值\(\bm{s}_1, \bm{s}_2,..., \bm{s}_{\min(m,n)}\)。 然后由等式

\[\bm{A}\bm{v}_1=s_1\bm{u}_1, \\ \bm{A}\bm{v}_2=s_2\bm{u}_2, \\ ..., \\ A\bm{v}_{\min(m,n)} = \bm{s}_{\min(m,n)}\bm{u}_{\min(m,n)}\]

依次计算出相应的\(\bm{u}_i\)向量的值。
至于特征值的计算,采用 QR 算法,此处不予介绍,这里可以直接调用 np.linalg.eig()函数实现。以下给出奇异值计算代码实例(此处仅为知识演示,具体的工业级别的奇异值计算算法要复杂得多,参考 Golub 与 Van Loan《矩阵计算》)

import numpy as np
def svd(A):
    eigen_values, eigen_vectors = np.linalg.eig(A.T.dot(A))
    singular_values = np.sqrt(eigen_values)
    #这里奇异值要从大到小排序,特征向量也要随之从大到小排
    val_vec = [] #存储奇异值-特征向量对
    for i in range(len(eigen_values)):
        val_vec.append((singular_values[i], eigen_vectors[:, i]))
    val_vec.sort(key = lambda x:-x[0])
    singular_values = [ pair[0] for pair in val_vec]
    eigen_vectors = [ pair[1] for pair in val_vec]

    # 在计算左奇异向量之前,先要对右奇异向量也就是特征向量组成的基正交化
    # 不过linalg.eig返回的是已经正交化的,这一步可省略

    # 由等式Avi = siui(vi是右奇异向量, ui是左奇异向量)
    # 依次计算左奇异向量
    U = np.zeros((A.shape[0], A.shape[1]))
    for i in range(A.shape[1]):
        u = A.dot(eigen_vectors[i])/singular_values[i]
        U[:, i] = u
    # 给U加上标准正交基去构造R3的基
    for i in range(A.shape[1], A.shape[0]):
        basis = np.zeros((A.shape[0], 1))
        basis[i] = 1
        U = np.concatenate([U, basis], axis=1)
    eigen_vectors = [vec.reshape(-1, 1) for vec in eigen_vectors]
    eigen_vectors = np.concatenate(eigen_vectors, axis=1)
    return U, singular_values, eigen_vectors

if __name__ == '__main__':
    # 例一:普通矩阵
    A = np.array(
        [
            [0, 1],
            [0, -1]
        ]
    )
    # 例二:对称矩阵
    # A = np.array(
    #     [
    #         [0, 1],
    #         [1, 3/2]
    #     ]
    # )
    U, S, V = svd(A)
    print("我们实现的算法结果:")
    print(U, "\n", S, "\n", V)
    print("\n")
    print("调用库函数的计算结果:")
    # 调用api核对
    U2, S2, V2 = np.linalg.svd(A)
    print(U2, "\n", S2, "\n", V2)

对普通矩阵\(\left(\begin{matrix}0 & 1 \\0 & -1\end{matrix}\right)\)运行该算法的结果为:

我们实现的算法结果:
[[ 0.70710678  0.70710678]
 [-0.70710678 -0.70710678]] 
 [1.4142135623730951, 0.0] 
 [[0. 1.]
 [1. 0.]]


调用库函数的计算结果:
[[
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
矩阵奇异值分解是一种重要的矩阵分解方法,被广泛应用于信号处理、数据挖掘、机器学习等领域。虽然矩阵奇异值分解具有很多优点,但是也存在一些缺点,主要包括以下几个方面: 1. 计算复杂度高:矩阵奇异值分解的计算复杂度通常比较高,特别是对于大型矩阵、高维数据等场景,计算时间和资源消耗都会比较大,需要使用高性能的计算机和算法。 2. 精度损失问题:矩阵奇异值分解过程中可能存在精度损失问题。由于计算机的精度是有限的,在计算奇异值分解时可能会出现数值误差,从而影响计算结果的精度。 3. 不适用于稀疏矩阵矩阵奇异值分解通常不适用于稀疏矩阵。对于稀疏矩阵进行奇异值分解需要先进行矩阵填充等预处理操作,这会增加计算复杂度和精度损失的风险。 4. 隐含因素的解释问题:矩阵奇异值分解通常是一种无监督的方法,难以对奇异向量的意义进行解释。在实际应用中,需要对模型的结果进行解释和理解,但由于矩阵奇异值分解本身的特点,很难对模型的内部机制进行详细的分析和解释。 5. 过拟合问题:矩阵奇异值分解通常是一种无约束模型,容易产生过拟合问题,特别是在数据量较小、噪声较大、模型复杂度较高等情况下容易出现过拟合现象,需要采取适当的正则化方法进行调整。 总的来说,矩阵奇异值分解在实际应用中存在一些缺点,需要根据具体场景和需求进行选择和调整,以获得更好的计算效果和应用效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值