PCA 流程如下:
1、去均值 2、計算協方差矩陣 3、計算協方差特徵值和特徵向量 4、降序排列特徵值選取較大的特徵值,選擇相應的特徵值和特徵向量
以下按照步驟編寫matlab代碼。
1.去均值
Matlab函數mean可得:如下
Mean_Image=mean(Train_SET,2);
Train_SET=Train_SET-Mean_Image*ones(1,Train_NUM);
2.計算協方差矩陣
協方差定義:
具體求解:
*注意分母爲(n-1)而不是n,因爲這樣定義的協方差方差是總體方差的無偏估計(具體可見:
http://en.wikipedia.org/wiki/Unbiased_estimator#Sample_variancehttp://www.zhihu.com/question/20099757)
協方差矩陣如下:
其元素aij表示變量i,j之間的協方差cov(i,j);
(關於協方差矩陣的含義,可見blog:http://blog.csdn.net/ice110956/article/details/14250745)
計算方法:
A.
其中Xj爲去中心化之後的特徵向量。
去中心化後,可表示爲如下:
求和之後,可以得到協方差矩陣。
B.
同理,上面的向量相加我們可以直接用矩陣相乘的形式得到。
設X爲去中心後的特徵矩陣,那麼
C.
直接用matlab自帶的協方差的函數cov()計算,不過注意cov按行計算,實際運用時要轉置。
我們使用矩陣形式,得到如下代碼:
R=Train_SET*Train_SET'/(Train_NUM-1);
3.計算特徵值與特徵向量
根據PCA的原理,我們需要尋找使協方差矩陣對角化的變換矩陣
(可見blog:http://blog.csdn.net/ice110956/article/details/14250745)。
一個方陣可以寫成如下形式:
其中Q爲其特徵向量組成的矩陣,爲其特徵值組成的對角矩陣,轉化一下式子,得到:
於是,我們現在只要得到協方差矩陣的歸一化特徵向量,組成轉化矩陣Q即可。
使用matlab自帶的函數eig(),
代碼:
[V,S]=eig(R);
**小樣本問題:
上面的代碼存在一個問題,就是常見的小樣本問題。樣本維數>>樣本個數,這樣得到的協方差矩陣很大,直接求解時間複雜度過高。於是我們通過另一種方式來求解。
SVD(奇異值分解):
A.奇異值
設A爲m*n階實矩陣,則存在m階正交陣U和n階正交陣V,使得
A = U*S*V’
其中S=diag(σi,σ2,……,σr),σi>0 (i=1,…,r),r=rank(A)。
其中:
對任意矩陣A,它的奇異值就是AA'或A'A的非零特徵值的開方(它們有相同的非零特徵值),這些特徵值都是正數。
U 爲AA'單位特徵向量矩陣。
V爲A’A單位特徵向量矩陣。
B.奇異值與特徵值的聯繫
奇異值有類似於特徵值的性質,當矩陣爲共軛對稱矩陣時,特徵值=奇異值。不過一般情況是不相同的。
如果把矩陣看做一個線性變換,那麼特徵值表徵了其特徵向量方向的能量大小。根據定義我們可以看出,奇異值也有類似的性質
C.奇異值分解與PCA的關係
通過變換,我們可以得到:
也就是,已知A,V,我們可以求得U。
如上,如果AA’維數過大,計算機不好求解其特徵向量U,那麼我們可以轉而求A’*A的特徵向量V。
求解PCA的過程中,對於小樣本問題,樣本維數M>>樣本個數N,那麼X*X’得到的協方差矩陣爲M*M,不好特徵分解。如果我們根據SVD的原理,解X’*X(N*N)的特徵向量,最後再變化,也能達到同樣的目的。
(SVD具體可見:
http://www.cnblogs.com/LeftNotEasy/archive/2011/01/19/svd-and-applications.html
http://szshdy.blog.163.com/blog/static/1322012512010511156587/)
通過奇異值分解,得到協方差矩陣特徵向量,代碼如下:
R=Train_SET'*Train_SET/(Train_NUM-1);
[V,S]=Find_K_Max_Eigen(R,Eigen_NUM);
disc_value=S;
disc_set=zeros(NN,Eigen_NUM);
Train_SET=Train_SET/sqrt(Train_NUM-1);
for k=1:Eigen_NUM
disc_set(:,k)=(1/sqrt(disc_value(k)))*Train_SET*V(:,k);
end
4.完整代碼
最終,整合上述的代碼,得到如下完整的PCA代碼:
function [disc_set,disc_value,Mean_Image]=Eigenface_f(Train_SET,Eigen_NUM)
[NN,Train_NUM]=size(Train_SET);
if NN<=Train_NUM
Mean_Image=mean(Train_SET,2);
Train_SET=Train_SET-Mean_Image*ones(1,Train_NUM);
R=Train_SET*Train_SET'/(Train_NUM-1);
[V,S]=Find_K_Max_Eigen(R,Eigen_NUM);
disc_value=S;
disc_set=V;
else % 小樣本問題,svd
Mean_Image=mean(Train_SET,2);
Train_SET=Train_SET-Mean_Image*ones(1,Train_NUM);
R=Train_SET'*Train_SET/(Train_NUM-1);
[V,S]=Find_K_Max_Eigen(R,Eigen_NUM);
disc_value=S;
disc_set=zeros(NN,Eigen_NUM);
Train_SET=Train_SET/sqrt(Train_NUM-1);
for k=1:Eigen_NUM
disc_set(:,k)=(1/sqrt(disc_value(k)))*Train_SET*V(:,k);
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [Eigen_Vector,Eigen_Value]=Find_K_Max_Eigen(Matrix,Eigen_NUM)
[NN,NN]=size(Matrix);
[V,S]=eig(Matrix); %Note this is equivalent to; [V,S]=eig(St,SL); also equivalent to [V,S]=eig(Sn,St); %
S=diag(S);
[S,index]=sort(S);
Eigen_Vector=zeros(NN,Eigen_NUM);
Eigen_Value=zeros(1,Eigen_NUM);
p=NN;
for t=1:Eigen_NUM
Eigen_Vector(:,t)=V(:,index(p));
Eigen_Value(t)=S(p);
p=p-1;
end