复现经典:《统计学习方法》第15章 奇异值分解

第15章 奇异值分解

本文是李航老师的《统计学习方法》一书的代码复现。作者:黄海广

备注:代码都可以在github中下载。我将陆续将代码发布在公众号“机器学习初学者”,可以在这个专辑在线阅读。

1.矩阵的奇异值分解是指将 实矩阵 表示为以下三个实矩阵乘积形式的运算

其中 阶正交矩阵, 阶正交矩阵, 矩形对角矩阵

其对角线元素非负,且满足

2.任意给定一个实矩阵,其奇异值分解一定存在,但并不唯一。

3.奇异值分解包括紧奇异值分解和截断奇异值分解。紧奇异值分解是与原始矩阵等秩的奇异值分解,截断奇异值分解是比原始矩阵低秩的奇异值分解。

4.奇异值分解有明确的几何解释。奇异值分解对应三个连续的线性变换:一个旋转变换,一个缩放变换和另一个旋转变换第一个和第三个旋转变换分别基于空间的标准正交基进行。

5.设矩阵 的奇异值分解为 ,则有

即对称矩阵 的特征分解可以由矩阵 的奇异值分解矩阵表示。

6.矩阵 的奇异值分解可以通过求矩阵 的特征值和特征向量得到: 的特征向量构成正交矩阵 的列;从 的特征值 的平方根得到奇异值 ,即

对其由大到小排列,作为对角线元素,构成对角矩阵 ;求正奇异值对应的左奇异向量,再求扩充的 的标准正交基,构成正交矩阵 的列。

7.矩阵 的弗罗贝尼乌斯范数定义为

在秩不超过 矩阵的集合中,存在矩阵 的弗罗贝尼乌斯范数意义下的最优近似矩阵 。秩为 的截断奇异值分解得到的矩阵 能够达到这个最优值。奇异值分解是弗罗贝尼乌斯范数意义下,也就是平方损失意义下的矩阵最优近似。

8.任意一个实矩阵 可以由其外积展开式表示

其中 矩阵,是列向量 和行向量 的外积, 为奇异值, 通过矩阵 的奇异值分解得到。

任意一个 x 矩阵,都可以表示为三个矩阵的乘积(因子分解)形式,分别是 正交矩阵,由降序排列的非负的对角线元素组成的 x 矩形对角矩阵,和 正交矩阵,称为该矩阵的奇异值分解。矩阵的奇异值分解一定存在,但不唯一。

奇异值分解可以看作是矩阵数据压缩的一种方法,即用因子分解的方式近似地表示原始矩阵,这种近似是在平方损失意义下的最优近似。

矩阵的奇异值分解是指,将一个非零的 x 实矩阵 表示为一下三个实矩阵乘积形式的运算:
,
其中 阶正交矩阵, 阶正交矩阵, 是由降序排列的非负的对角线元素组成的 x 矩形对角矩阵。称为 的奇异值分解。 的列向量称为左奇异向量, 的列向量称为右奇异向量。

奇异值分解不要求矩阵 是方阵,事实上矩阵的奇异值分解可以看作方阵的对角化的推广。

紧奇奇异值分解是与原始矩阵等秩的奇异值分解, 截断奇异值分解是比原始矩阵低秩的奇异值分解。


# 实现奇异值分解, 输入一个numpy矩阵,输出 U, sigma, V
# https://zhuanlan.zhihu.com/p/54693391

import numpy as np


#基于矩阵分解的结果,复原矩阵
def rebuildMatrix(U, sigma, V):
    a = np.dot(U, sigma)
    a = np.dot(a, np.transpose(V))
    return a


#基于特征值的大小,对特征值以及特征向量进行排序。倒序排列
def sortByEigenValue(Eigenvalues, EigenVectors):
    index = np.argsort(-1 * Eigenvalues)
    Eigenvalues = Eigenvalues[index]
    EigenVectors = EigenVectors[:, index]
    return Eigenvalues, EigenVectors


#对一个矩阵进行奇异值分解
def SVD(matrixA, NumOfLeft=None):
    #NumOfLeft是要保留的奇异值的个数,也就是中间那个方阵的宽度
    #首先求transpose(A)*A
    matrixAT_matrixA = np.dot(np.transpose(matrixA), matrixA)
    #然后求右奇异向量
    lambda_V, X_V = np.linalg.eig(matrixAT_matrixA)
    lambda_V, X_V = sortByEigenValue(lambda_V, X_V)
    #求奇异值
    sigmas = lambda_V
    sigmas = list(map(lambda x: np.sqrt(x)
                      if x > 0 else 0, sigmas))  #python里很小的数有时候是负数
    sigmas = np.array(sigmas)
    sigmasMatrix = np.diag(sigmas)
    if NumOfLeft == None:
        rankOfSigmasMatrix = len(list(filter(lambda x: x > 0,
                                             sigmas)))  #大于0的特征值的个数
    else:
        rankOfSigmasMatrix = NumOfLeft
    sigmasMatrix = sigmasMatrix[0:rankOfSigmasMatrix, :]  #特征值为0的奇异值就不要了

    #计算右奇异向量
    X_U = np.zeros(
        (matrixA.shape[0], rankOfSigmasMatrix))  #初始化一个右奇异向量矩阵,这里直接进行裁剪
    for i in range(rankOfSigmasMatrix):
        X_U[:, i] = np.transpose(np.dot(matrixA, X_V[:, i]) / sigmas[i])

    #对右奇异向量和奇异值矩阵进行裁剪
    X_V = X_V[:, 0:NumOfLeft]
    sigmasMatrix = sigmasMatrix[0:rankOfSigmasMatrix, 0:rankOfSigmasMatrix]
    #print(rebuildMatrix(X_U, sigmasMatrix, X_V))

    return X_U, sigmasMatrix, X_V
A = np.array([[1, 1, 1, 2, 2], [0, 0, 0, 3, 3], [0, 0, 0, 1, 1], [1, 1, 1, 0, 0],
              [2, 2, 2, 0, 0], [5, 5, 5, 0, 0], [1, 1, 1, 0, 0]])

A
array([[1, 1, 1, 2, 2],
       [0, 0, 0, 3, 3],
       [0, 0, 0, 1, 1],
       [1, 1, 1, 0, 0],
       [2, 2, 2, 0, 0],
       [5, 5, 5, 0, 0],
       [1, 1, 1, 0, 0]])
X_U, sigmasMatrix, X_V = SVD(A, NumOfLeft=3)
X_U
array([[ 1.96602638e-01, -5.12980706e-01, -6.20066911e-09],
       [ 3.08997616e-02, -8.04794293e-01,  1.69140901e-09],
       [ 1.02999205e-02, -2.68264764e-01,  5.63803005e-10],
       [ 1.76002797e-01,  2.35488225e-02, -7.63159275e-09],
       [ 3.52005594e-01,  4.70976451e-02, -1.52631855e-08],
       [ 8.80013984e-01,  1.17744113e-01, -3.81579637e-08],
       [ 1.76002797e-01,  2.35488225e-02, -7.63159275e-09]])
sigmasMatrix
array([[9.81586105e+00, 0.00000000e+00, 0.00000000e+00],
       [0.00000000e+00, 5.25821946e+00, 0.00000000e+00],
       [0.00000000e+00, 0.00000000e+00, 1.16381789e-07]])
X_V
array([[ 5.75872999e-01,  4.12749590e-02,  8.16496581e-01],
       [ 5.75872999e-01,  4.12749590e-02, -4.08248290e-01],
       [ 5.75872999e-01,  4.12749590e-02, -4.08248290e-01],
       [ 5.05512944e-02, -7.05297502e-01,  3.28082013e-17],
       [ 5.05512944e-02, -7.05297502e-01,  3.28082013e-17]])
# rebuild from U, sigma, V

rebuildMatrix(X_U, sigmasMatrix, X_V)
array([[ 1.00000000e+00,  1.00000000e+00,  1.00000000e+00,
         2.00000000e+00,  2.00000000e+00],
       [ 5.39915464e-17,  7.72260438e-16, -7.54662738e-16,
         3.00000000e+00,  3.00000000e+00],
       [ 9.57429619e-18,  2.48997260e-16, -2.59977132e-16,
         1.00000000e+00,  1.00000000e+00],
       [ 1.00000000e+00,  1.00000000e+00,  1.00000000e+00,
         1.25546281e-17,  1.25546281e-17],
       [ 2.00000000e+00,  2.00000000e+00,  2.00000000e+00,
         2.51092563e-17,  2.51092563e-17],
       [ 5.00000000e+00,  5.00000000e+00,  5.00000000e+00,
         9.74347659e-18,  9.74347659e-18],
       [ 1.00000000e+00,  1.00000000e+00,  1.00000000e+00,
         1.38777878e-17,  1.38777878e-17]])

same as A.

from PIL import Image
import requests
from io import BytesIO

url = 'https://images.mulberry.com/i/mulberrygroup/RL5792_000N651_L/small-hampstead-deep-amber-small-classic-grain-ayers/small-hampstead-deep-amber-small-classic-grain-ayers?v=3&w=304'
response = requests.get(url)
img = Image.open(BytesIO(response.content))
img


本章代码来源:https://github.com/hktxt/Learn-Statistical-Learning-Method

下载地址

https://github.com/fengdu78/lihang-code

参考资料:

[1] 《统计学习方法》: https://baike.baidu.com/item/统计学习方法/10430179

[2] 黄海广: https://github.com/fengdu78

[3]  github: https://github.com/fengdu78/lihang-code

[4]  wzyonggege: https://github.com/wzyonggege/statistical-learning-method

[5]  WenDesi: https://github.com/WenDesi/lihang_book_algorithm

[6]  火烫火烫的: https://blog.csdn.net/tudaodiaozhale

[7]  hktxt: https://github.com/hktxt/Learn-Statistical-Learning-Method

人工智能常识和干货,适合收藏

《统计学习方法》(李航)读书笔记(完结)

良心推荐:机器学习入门资料汇总及学习建议

网红少年编程书,AI自学不再难

【B站免费教程】2W 收藏!火爆 B 站的计算机科学速成教程发布,全中文版

良心推荐:机器学习入门资料汇总及学习建议(2018版)

机器学习必备宝典-《统计学习方法》的python代码实现、电子书及课件

软件下载和Python,AI,资料

【送书PDF】Python编程从入门到实践

Python从入门到精通,深度学习与机器学习资料大礼包!

【免费】某机构最新3980元机器学习/大数据课程高速下载,限量200份

长按扫码撩海归

   觉得不错, 请随意转发,麻烦点个在看!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值