利用PCA,SVD原理实现对图片的特征提取(矩阵降维)
简述SVD和PCA
PCA
PCA是通过计算原始数据的协方差矩阵来将原始的数据构造成方阵;随后选择其中贡献率(方差、熵、特征值)较大,以此来提取一个矩阵的主要特征,并以此来实现降维;
SVD
SVD是通过将构造原始数据
A
A
A,通过
A
T
⋅
A
A^T·A
AT⋅A来构造方阵;
随后在其中选择贡献率(方差、熵、奇异值)较大的变量来对原矩阵进行分解,以此来提取数据矩阵的主要特征;
区别
- 将实际数据转换为方阵的方式不同;PCA是利用去中心化后的原始数据的协方差矩阵来将原始的数据构造成方阵;SVD是通过将构造原始数据 A A A,通过 A T ⋅ A A^T·A AT⋅A来构造方阵;
- 通常情况下SVD的奇异值下降的很快,很多时候10%或者1%就能占全部奇异值的99%以上,既也就是SVD有更好的降维效果;
- 由于 1 n ⋅ X T ⋅ X = 1 n U S V T V S U T = U S 2 n U T . \cfrac{1}{n} \cdot X^T·X = \cfrac{1}{n}USV^T VSU^T =U \cfrac{S^2}{n} U^T . n1⋅XT⋅X=n1USVTVSUT=UnS2UT.故SVD可以获取另一个方向上的主成分,而PCA只获取单方向上的主成分;
- 通常SVD比PCA更加稳定;因为在计算 X T X X^T X XTX时部分过小的数据会因为计算而丢失,从而使结果相比PCA更加稳定;
具体实现步骤(算法简述)
PCA
-
对原始数据进行去中心化,即: V = ( x 11 − u 1 ⋅ ⋅ ⋅ x n 1 − u n ⋮ ⋱ ⋮ x m 1 − u 1 ⋅ ⋅ ⋅ x m n − u n ) , 其 中 u i = 1 m ∑ 1 ≤ j ≤ m x i j V = \begin{pmatrix} x_{11}-u_{1} & \cdot\cdot\cdot &x_{n1}-u_{n} \\ \vdots & \ddots & \vdots\\ x_{m1}-u_{1} & \cdot\cdot\cdot &x_{mn}-u_{n} \end{pmatrix} ,其中 u_i = \cfrac{1}{m}\sum_{\mathclap{1\le j\le m}} x_{ij} V=⎝⎜⎛x11−u1⋮xm1−u1⋅⋅⋅⋱⋅⋅⋅xn1−un⋮xmn−un⎠⎟⎞,其中ui=m11≤j≤m∑xij
-
计算样本的协方差矩阵:
C = ( c o v ( x 1 , x 1 ) ⋅ ⋅ ⋅ c o v ( x 1 , x n ) ⋮ ⋱ ⋮ c o v ( x n , x 1 ) ⋅ ⋅ ⋅ c o v ( x n , x n ) ) C = \begin{pmatrix} cov(x_1,x_1)& \cdot\cdot\cdot &cov(x_1,x_n) \\ \vdots & \ddots & \vdots\\ cov(x_n,x_1) & \cdot\cdot\cdot &cov(x_n,x_n) \end{pmatrix} C=⎝⎜⎛cov(x1,x1)⋮cov(xn,x1)⋅⋅⋅⋱⋅⋅⋅cov(x1,xn)⋮cov(xn,xn)⎠⎟⎞
简 易 公 式 : C = 1 m ⋅ X T ⋅ X 简易公式:C = \cfrac{1}{m} \cdot X^T·X 简易公式:C=m1⋅XT⋅X -
计算新矩阵C的特征值和特征向量,并对其从大到小进行排序;
-
选取其中较大的t个特征值对应的特征向量构造新的矩阵:
V = ( c 11 ⋅ ⋅ ⋅ c 1 t ⋮ ⋱ ⋮ c m 1 ⋅ ⋅ ⋅ c m t ) V = \begin{pmatrix} c_{11} & \cdot\cdot\cdot &c_{1t} \\ \vdots & \ddots & \vdots\\ c_{m1} & \cdot\cdot\cdot &c_{mt} \end{pmatrix} V=⎝⎜⎛c11⋮cm1⋅⋅⋅⋱⋅⋅⋅c1t⋮cmt⎠⎟⎞ -
将数据投放到新的数据空间中: L = X ⋅ V L=X·V L=X⋅V
-
可以将降维后的数据还原,以此来检测损失率: D = L ⋅ V T + U D=L·V^T+U D=L⋅VT+U
SVD
-
将原始数据转化为方阵: D = X ⋅ X T D=X·X^T D=X⋅XT
-
计算新矩阵 D D D的特征值和特征向量,并对其从大到小进行排序得到特征值对角阵 E E E和特征向量阵;
-
选取其中较大的t个特征值对应的特征向量构造矩阵 V V V特征值构成对角阵 S S S:
V = ( d 11 ⋅ ⋅ ⋅ d 1 t ⋮ ⋱ ⋮ d m 1 ⋅ ⋅ ⋅ d m t ) V = \begin{pmatrix} d_{11} & \cdot\cdot\cdot &d_{1t} \\ \vdots & \ddots & \vdots\\ d_{m1} & \cdot\cdot\cdot &d_{mt} \end{pmatrix} V=⎝⎜⎛d11⋮dm1⋅⋅⋅⋱⋅⋅⋅d1t⋮dmt⎠⎟⎞
S = ( e 11 ⋅ ⋅ ⋅ 0 ⋮ ⋱ ⋮ 0 ⋅ ⋅ ⋅ e m t ) S = \begin{pmatrix} e_{11} & \cdot\cdot\cdot &0 \\ \vdots & \ddots & \vdots\\ 0 & \cdot\cdot\cdot &e_{mt} \end{pmatrix} S=⎝⎜⎛e11⋮0⋅⋅⋅⋱⋅⋅⋅0⋮emt⎠⎟⎞ -
逆向推导,利用 D = U ⋅ S ⋅ V T D=U·S·V^T D=U⋅S⋅VT推导出: U = D ⋅ V ⋅ S − 1 U=D·V·S^{-1} U=D⋅V⋅S−1
-
可以将降维后的数据还原,以此来检测损失率: N = U ⋅ S ⋅ V − 1 N=U·S·V^{-1} N=U⋅S⋅V−1
程序源码:
以matlab语言为例实现对图片的降维存储
注意: 该程序中是直接选择保留90%的特征,实际情况可以根据需要调整;
clear
clc
disp('利用svd和pca对图像进行降维存储')
disp('原始数据为1080*1920')
%对原始数据进行预处理
data = imread('Example.jpeg');
subplot(2,2,1)
imshow(data)
title('原始图像')
%图像灰度化
data =rgb2gray(data);
data = im2double(data);
%原始图像展示
subplot(2,2,2)
imshow(data)
title('原始图像灰度图')
%=========================================================================
%进行svd分解
[V,D] = eig(data'*data);
[S,D_index] = sort(diag(sqrt(D)),'descend');
S = diag(S);
V=V(:, D_index);
U = data * V * S^-1;
%获得对应的usv
cul = 0;
S_sum = sum(sum(S));
for i = 1:length(S)
cul = cul + S(i,i)/S_sum;
if cul > 0.9
break
end
end
disp(['提取累积贡献率大于90%的奇异值的个数为 ' num2str(i)])
%展示结果
V = V';
%生成新的数据
majorData = U(:,1:i) * S(1:i,1:i) * V(1:i,:);
subplot(2,2,3)
imshow(majorData)
title('svd提取主要特征之后的图像')
%=========================================================================
%进行PCA分解
d_mean = mean(data);
d_mean(length(data(:,1)),length(d_mean)) = 0;
for j = 1:length(d_mean)
d_mean(:,j) = d_mean(1,j);
end
data_mean = data-d_mean;
temp = cov(data_mean);
[V,D] = eig(temp);
[S,D_index] = sort(diag(sqrt(D)),'descend');
S = diag(S);
V=V(:, D_index);
cul = 0;
S_sum = sum(sum(S));
for i = 1:length(S)
cul = cul + S(i,i)/S_sum;
if cul > 0.9
break
end
end
disp(['提取累积贡献率大于90%的奇异值的个数为 ' num2str(i)])
V = V(:,1:i);
%展示结果
finData =data_mean * V;
%生成新的数据
majorData = finData*V'+ d_mean;
subplot(2,2,4)
imshow(majorData)
title('PCA提取主要特征之后的图像')