奇异值分解SVD

         本总结是是个人为防止遗忘而作,不得转载和商用。


关于奇异值分解的名字:

         第一次看“奇异值分解”时真是超不知所以。不过它的英文名字是Singular Value Decompostion。而Signular是“突出的、奇特的、非凡的”的意思,于是用“优值分解”的这个名字好像更贴切些,而且“优值分解”这个名字的第一印象就比“奇异值分解”更让人容易接受。


什么是奇异值分解:

         假设A是一个m*n的实矩阵,那么一定存在这样一个分解使得:

                   Am*n= Um*mΣm*nVTn*n

              其中,U和V都是单位正交方阵,Σ是一个只有45°对角线上存在非零值的矩阵。

         这时,称这样一个分解为奇异值分解

                   Σ对角线上的元素σi是矩阵A的奇异值

                   U的第i列称为A的关于σi的左奇异向量

                   V的第i列称为A的关于σi的右奇异向量

         看了上面的介绍是不是还不明所以,没关系,下面我会继续解释,总之知道这样一种分解是奇异值分解就是了。

                   PS:就好像对于一个数,我总能把它写成3个数相乘似得,对于一个矩阵,我总能通过某种方法把它分解成这样的形式,你别管我用的什么方法,但你总的承认我能把它分解对吧。


奇异值分解定义的解释:

         为了对奇异值分解更有概念,我们来对定义举个小例子。

         对于一个矩阵A

                  

         我总能通过某种方式将其分解成A = UΣVT的样子(你别管我怎么分解的),其中UΣV如下:

        

         且U和V是单位正交方阵,即:矩阵U和V满足式子:

                  UTU = I,VTV= I

         Σ是只有45°对角线上有非零元素的矩阵(注意是45°对角线)。

         这时,这样的分解就是奇异值分解

         Σ中45°对角线上的那三个非零元素就是矩阵A的奇异值


奇异值分解有什么作用:

         现在我们已经知道,通过奇异值分解可以把矩阵A分解成UΣV三个矩阵相乘的形式,但奇异值分解到底有什么用呢?

为了说明这个,我假设A是个m*n的矩阵,那经过奇异值分解后,U就是m*m的矩阵,Σ是m*n的矩阵,V是n*n的矩阵(为什么?因为根据定义U和V都是方阵,如果还看不懂,那你需要复习下矩阵的乘法了。)

         然后,把矩阵M的每一列用一个列向量ui表示,于是矩阵U我就可以写成

                  U = [u1, u2, …, ui,…, um]

         同理,把V的每一行用一个行向量vi表示后,矩阵V就可以写成

                  V = [v1, v2, …, vi,…, vn]

         而Σ因为只有对角线上有非零元素,所以我们用σi表示Σ上每一行的非零元素。

         这时,如果我们只取这三个矩阵的前k个元素,就有:

                  A = UΣV = u1σ1v1 + u2σ2v2 + … + ukσkvk

             这意味着什么?

         这意味着我们将m*n这样一个维度的矩阵A降成了k*k维!

         当然这样一来降维后的矩阵和原来的矩阵不同,即:数学结果不同。

不过在实际应用中,这个降维后的矩阵其效果是和原矩阵一样的!


例子:

         下面我写的SVD压缩图片的效果和代码(restore函数来自于皱博老师)

         首先是效果。

         原图:

         使用SVD分解压缩后后:

         上面四张图是分别取前1、10、40、80个特征向量的结果。

         可以看到,取前80个特征向量就已经可以把原图恢复的差不多了,而代码中经过mtr.shape = (649, 2886)转换之后可是有649个特征向量的。

         下面是代码,其中我的疑问也在里面,如果有谁知道答案的话,不知可否在评论里告知一下,不胜感激。

#-*-coding:utf-8-*-

# 关于 svd 压缩图片的问题

# 问题0:

#   在 restore 函数的

#      b = a.astype('uint8')

#   前加上如下3行可以解决本人的实验图片经svd 压缩并使用 restore 函数保存后图片太扁的问题

#      n = n / 3

#      a.shape = (m, n, 3)

#      a.transpose()

#   但即使是以参数的方式传入这个 3,但是不是还是太有针对性?

#

# 问题1:

#   上课时听老师讲 SVD 时说的的矩阵的2维的,而我使用

#      mtr = np.array(im)

#   将 im 转换成矩阵后,矩阵是3维的,矩阵的信息如下:

#      # Mtr   --  ndim:3, shape:(649, 962, 3), size:1873014

#   这是为什么?

#   是本来就是这样,需要我在转换成矩阵后在将其处理2维的吗?还是什么?

#

# 问题2:

#   在问题1的基础上,图片读取成矩阵后如何处理这个矩阵?

#   我这边如代码所示,在使用下面两行代码

#      mtr.shape = (649, 2886)

#      mtr.transpose()

#   处理图片,最后使用 defrestore 保存出来的图片会特别的扁。

#

# 问题3:

#   有没有什么方法可以

#      "读取图片 -> 将图片数据转换成矩阵 -> 使用svd -> 代入 def restore"

#   而不是像我写的

#      "读取图片 -> 将图片数据转换成矩阵 -> 将矩阵处理成秩为2的矩阵 -> 使用svd -> 代入 def restore"

#  

# 其他:我使用的图片在 http://pan.baidu.com/s/1i4GLeSH

 

import os

import sys

import Image

import numpy as np

 

BASIC_PATH = sys.path[0]

 

def restore(sigma, u, v, k):

    m= len(u)

    n= len(v[0])

    a= np.zeros((m, n))

   for k in range(k+1):

       for i in range(m):

           # a[0] = sigma 的第一个 * u 的第一列 * v 的第一行

           # a[1] = sigma 的第二个 * u 的第二列 * v 的第二行

           # 以此类推

           a[i] += sigma[k] * u[i][k] * v[k]

         #下面三行是我自己添加的,否则保存出来的图片会太扁

    n= n / 3

   a.shape = (m, n, 3)

   a.transpose()

    b= a.astype('uint8')

   Image.fromarray(b).save("svd_" + str(k) + ".jpg")

 

 

# 读取图片

im = Image.open("%s/1.jpg" %BASIC_PATH)

# 将图片信息转换成矩阵

mtr = np.array(im)

# Image -- format:JPEG, size:(962, 649), mode:RGB

print 'Image\t--\tformat:%s, size:%s,mode:%s' % (im.format, str(im.size), im.mode)

# Mtr  --  ndim:3, shape:(649, 962, 3),size:1873014

print 'Mtr\t-- \tndim:%s, shape:%s,size:%d' % (str(mtr.ndim), str(mtr.shape), mtr.size)

 

# 这里矩阵的秩是3,将其转成2

mtr.shape = (649, 2886)

mtr.transpose()

# svd

# 这里 U 和 VT 是秩为 2 的矩阵,sigma 矩阵的秩为 1

U, sigma, VT = np.linalg.svd(mtr,full_matrices=False)

# 取前 k 个特征向量

k = 100

# 保存图片

restore(sigma, U, VT, k)

im = Image.open("%s/svd_%s.jpg" %(BASIC_PATH, k))

im.show()

         

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值