降维方法——SVD奇异值分解

奇异值分解(SVD)是一种矩阵分解的方法,
假设有矩阵 A A m m n n 列,那么通过SVD,我们可以得到如下式子:

Am×n=Um×mΣm×nVTn×n A m × n = U m × m Σ m × n V n × n T

其中 U U 定义为 A A 的左奇异向量, V V 定义为右奇异向量, Σ Σ 对角线上的值为 A A 的奇异值。
这里 U U 可以看成 m m 列的列向量组成的 m×m m × m 的正交矩阵; V V 可以看成 n n 行的行向量组成的 n×n n × n 的正交矩阵;
所以要求矩阵A的奇异值分解值主要有一下四个部分。
- 分别计算正交矩阵 AAT A A T ATA A T A
- U U 中的列由 AAT A A T 的单位特征向量组成。
- V V 中的列由 ATA A T A 的单位特征向量组成。
- Σ Σ 对角线上的值由 ATA A T A 的特征值的平方根得出。

SVD的应用可以应用在很多场景,如在对数据处理时可以通过SVD选取重要的维度即 Σ Σ 中的特征值(其实按照从大到小的顺序排列),也可以对图像进行做特征提取处理,同时也可以应用于基于协同过滤的推荐中,也可以对数据进行压缩处理。

这里我们举例,SVD对图像中基本的特征提取应用。

#!/usr/bin/python
# -*- coding:utf-8 -*-

import  numpy as np
import  os
from  PIL import  Image
import  matplotlib.pyplot as plt
import  matplotlib as mpl
from pprint import  pprint


def restorel(sigma, u, v, K):
    m = len(u)
    n = len(v[0])
    a = np.zeros((m,n))
    for k in range(K):
        print("==============",u.shape)
        uk = u[:,k].reshape(m,1)
        vk = v[k].reshape(1,n)
        print("=======================")
        print(sigma[k].shape)
        a += sigma[k]*np.dot(uk,vk)
    print("a:",a.shape)
    print("**********************")
    print(a)
    a[a < 0] = 0
    a[a > 255] = 255
    return np.rint(a).astype('uint8')



if __name__ == "__main__":
    A = Image.open("A.png",'r')
    print(A)
    output_path = r'.\Pic'
    if not os.path.exists(output_path):
        os.mkdir(output_path)
    a = np.array(A)
    # print(a.shape)
    K = 50
    u_r, sigma_r, v_r = np.linalg.svd(a[:,:,0])
    u_g, sigma_g, v_g = np.linalg.svd(a[:,:,1])
    u_b, sigma_b, v_b = np.linalg.svd(a[:,:,2])
    # print("====================")
    # print(u_r.shape)
    # print(sigma_r.shape)
    # print(v_r.shape)
    plt.figure(figsize=(10,10),facecolor='w')
    mpl.rcParams['font.sans-serif'] = [u'simHei']
    mpl.rcParams['axes.unicode_minus'] = False
    for k in range(1,K+1):
        print(k)
        R = restorel(sigma_r, u_r, v_r, k)
        G = restorel(sigma_g, u_g, v_g, k)
        B = restorel(sigma_b, u_b, v_b, k)
        I = np.stack((R,G,B),axis=2)
        Image.fromarray(I).save("%s\\svd_%d.png"%(output_path,k))
        if k <= 12:
            plt.subplot(3, 4, k)
            plt.imshow(I)
            plt.axis('off')
            plt.title(u'奇异值个数:%d' % k)
    plt.suptitle(u'SVD与图像分解',fontsize = 20)
    plt.tight_layout(0.3, rect=(0,0,1,0.92))
    plt.show()

你可能感兴趣的:(machine,learning,python)