在很多情况下,数据的绝大部分信息往往集中在很小一部分数据上,我们知道线性代数中有很多矩阵的分解技术可以将矩阵表示成易于处理或是表达简化的形式。最常见的一就种是SVD(Singular Value Decomposition)算法。
SVD将数据分解成三个矩阵U,S,VT,这里得到的S是一个对角阵,其中对角元素为奇异值,它代表着矩阵的重要特征,从左上角到右下角重要程度递减。因为奇异值往往对应着矩阵中隐含的重要信息,而且奇异值大小与重要性正相关。
优点:简化数据,优化数据的表达形式。
缺点:难于计算。
关于奇异值分解的定义和相关推导,推荐参考这篇文章,介绍的非常清晰易懂:机器学习中的数学(5)-强大的矩阵奇异值分解(SVD)及其应用
故公式什么的这里就不列出了,理解了理论后,我们来小小测试一下,以体会其强大之处。
这里使用的是matlab函数svd():[U,S,V]=svd(A);
SVD的matlab测试代码如下:
clear,clc;
close all;
img = double(imread('room1.tif')); %[256,256]
figure(1);
subplot(331);imshow(img,[]);title('original');
[m,n] = size(img);
%返回与img同大小的对角矩阵S,两个酉矩阵U和V,且满足img=U*S*V'
[U,S,V] = svd(img);
%若img大小为m×n,则U为m×m矩阵,V为n×n矩阵.S为m×n矩阵,奇异值在S的对角线上
decomp = U(:,:)*S(:,1)*V(:,1)';
subplot(332);imshow(decomp,[]);title('svd-前1个特征');
decomp = U(:,:)*S(:,1:5)*V(:,1:5)';
subplot(333);imshow(decomp,[]);title('svd-前5个特征');
decomp = U(:,:)*S(:,1:10)*V(:,1:10)';
subplot(335);imshow(decomp,[]);title('svd-前10个特征');
decomp = U(:,:)*S(:,1:50)*V(:,1:50)';
subplot(336);imshow(decomp,[]);title('svd-前50个特征');
decomp = U(:,:)*S(:,1:80)*V(:,1:80)';
subplot(338);imshow(decomp,[]);title('svd-前80个特征')
decomp = U(:,:)*S(:,1:150)*V(:,1:150)';
subplot(339);imshow(decomp,[]);title('svd-前150个特征');
输出结果:图像大小为256x256,奇异值有256个,结果可见前50个特征就基本涵盖了原图所有信息。
这里使用的是numpy库的函数linalg.svd()
SVD的python测试代码如下:
#!usr/bin/python
# -*- code:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def svd_decompose(img, s_num):
u, s, vt = np.linalg.svd(img)
h, w = img.shape[:2]
s1 = np.diag(s[:s_num],0) #用s_num个奇异值生成新对角矩阵
u1 = np.zeros((h,s_num), float)
vt1 = np.zeros((s_num,w), float)
u1[:,:] = u[:,:s_num]
vt1[:,:] = vt[:s_num,:]
svd_img = u1.dot(s1).dot(vt1)
return svd_img
def main():
img = Image.open('room.jpg') #(256,256)
img = np.array(img)
svd_1 = svd_decompose(img, 1)
svd_5 = svd_decompose(img, 5)
svd_10 = svd_decompose(img, 10)
svd_20 = svd_decompose(img, 20)
svd_50 = svd_decompose(img, 50)
svd_100 = svd_decompose(img, 100)
plt.figure(1);
plt.subplot(331);plt.imshow(img, cmap='gray');plt.title('original');plt.xticks([]);plt.yticks([]);
plt.subplot(332);plt.imshow(svd_1, cmap='gray');plt.title('1 Singular Value');plt.xticks([]);plt.yticks([]);
plt.subplot(333);plt.imshow(svd_5, cmap='gray');plt.title('5 Singular Values');plt.xticks([]);plt.yticks([]);
plt.subplot(335);plt.imshow(svd_10, cmap='gray');plt.title('10 Singular Values');plt.xticks([]);plt.yticks([]);
plt.subplot(336);plt.imshow(svd_20, cmap='gray');plt.title('20 Singular Values');plt.xticks([]);plt.yticks([]);
plt.subplot(338);plt.imshow(svd_50, cmap='gray');plt.title('50 Singular Values');plt.xticks([]);plt.yticks([]);
plt.subplot(339);plt.imshow(svd_100, cmap='gray');plt.title('100 Singular Values');plt.xticks([]);plt.yticks([]);
plt.show()
if __name__ == '__main__':
main()
输出结果:同样,结果可见前50个特征就基本涵盖了原图所有信息。
图像压缩(image compression):较少的奇异值就可以表达出图像中大部分信息,舍弃掉一部分奇异值来实现压缩。
图像降噪(image denoise):噪声一般存在于图像高频部分,也表现在奇异值小的部分,故可以借助SVD实现去噪。
音频滤波(filtering):Andrew Ng的机器学习课程上有个svd将混杂声音分离的例子,其实和噪声滤波类似。
求任意矩阵的伪逆(pseudo-inverse):由于奇异矩阵或非方阵矩阵不可求逆,在特殊情况下需要广义求逆时可用svd方法。
模式识别(pattern recognition):特征为矩阵,数据量较大时,可以用svd提取主要的成分。
潜在语义索引(Latent Semantic Indexing):NLP中,文本分类的关键是计算相关性,这里关联矩阵A=USV’,分解的三个矩阵有很清楚的物理含义,可以同时得到每类文章和每类关键词的相关性。