PCA的一些基本資料
最近因為最人臉表情識別,提取的gabor特征太多了,所以需要用PCA進行對提取的特征進行降維。
本來最早的時候我沒有打算對提取的gabor特征進行降維,但是如果一個圖像時64*64,那么使用五個尺度八個方向的gabor濾波器進行濾波,這樣提取的特征足足有64*64*5*8這么多,如果圖像稍微大一點,比如128*128的圖像,那么直接提取的特征就會幾十萬,所以不降維的話直接用SVM訓練分類器是非常困難的。
所以在這段時間我就學習了一下PCA降維的基本原理和使用方法,網上給出的資料都比較亂,而且很不清楚,經過這幾天的學習和測試,終於把調理弄清楚了,給大家分享一下,下面只是我對於PCA的個人理解,肯定有不對的地方,還請各位大牛多多指教。
下面先給出一下PCA的資料地址,都是我收集的:
http://hi.baidu.com/yicomrdztxbeiwd/item/913f28c05cf7ebc4994aa06f
http://blog.sciencenet.cn/blog-265205-544681.html
http://blog.csdn.net/mpbchina/article/details/7384425
http://blog.sina.com.cn/s/blog_6833a4df0100pvk7.html
http://stackoverflow.com/questions/4991343/matlab-principal-component-analysis-eigenvalues-order
http://stackoverflow.com/questions/10400230/what-is-score-in-princomp
http://www.mathworks.com/matlabcentral/newsreader/view_thread/152608
http://stats.stackexchange.com/questions/27572/matlab-princomp-latent
http://www.nlpca.org/pca-principal-component-analysis-matlab.html
http://www.matlabsky.com/thread-11751-1-1.html
http://stackoverflow.com/questions/10818718/principal-component-analysis
http://www.mathworks.cn/cn/help/stats/princomp.html
http://www.mathworks.cn/cn/help/stats/pca.html#bti6n7k-2
http://lovelittlebean.blog.163.com/blog/static/116582186201181213911729/
http://www.ilovematlab.cn/thread-54493-1-1.html
http://www.ilovematlab.cn/forum.php?mod=viewthread&tid=146626
http://www.ilovematlab.cn/forum.php?mod=viewthread&tid=204069
http://www.ilovematlab.cn/forum.php?mod=viewthread&tid=54600
http://search.discuz.qq.com/s/aa8585553/princomp+%E9%99%8D%E7%BB%B4.html
http://www.ilovematlab.cn/thread-68796-1-1.html
http://www.ilovematlab.cn/thread-209229-1-1.html
http://www.ilovematlab.cn/thread-209229-1-1.html
http://blog.sina.com.cn/s/blog_61c0518f0100f4mi.html
http://blog.csdn.net/haitao111313/article/details/7875392
http://media.cs.tsinghua.edu.cn/~ahz/digitalimageprocess/chapter11/chapt11_ahz.htm
http://hi.baidu.com/845777018/item/7438e555df1138404fff2011
http://en.wikipedia.org/wiki/Principal_component_analysis
http://baike.baidu.com/view/852194.htm
http://wenku.baidu.com/view/bd9284fcfab069dc51220107.html
http://wenku.baidu.com/view/c0bde56da98271fe910ef9b8.html
http://wenku.baidu.com/view/9f69930790c69ec3d5bb75d3.html
http://www.ilovematlab.cn/thread-54600-1-1.html
http://www.cnblogs.com/sunwufan/archive/2011/08/31/2159952.html
http://zhidao.baidu.com/question/416895922.html
上面的網址都是一些pca原理啊,實現什么的介紹。
具體的PCA的算法的理論基礎呢,我這里就不詳細說了,因為我也沒有看具體詳細,所以如果想要徹底的弄明白PCA的工作原來,還是請到wiki上看吧,寫的非常清晰,我因為臨時用一下,就寫個大致的原理就可以了。
PCA原理:
PCA的原理就是將原來的樣本數據投影到一個新的空間中,相當於我們在矩陣分析里面學習的將一組矩陣映射到另外的坐標系下。通過一個轉換坐標,也可以理解成把一組坐標轉換到另外一組坐標系下,但是在新的坐標系下,表示原來的原本不需要那么多的變量,只需要原來樣本的最大的一個線性無關組的特征值對應的空間的坐標即可。
比如,原來的樣本是30*1000000的維數,就是說我們有30個樣本,每個樣本有1000000個特征點,這個特征點太多了,我們需要對這些樣本的特征點進行降維。那么在降維的時候會計算一個原來樣本矩陣的協方差矩陣,這里就是1000000*1000000,當然,這個矩陣太大了,計算的時候有其他的方式進行處理,這里只是講解基本的原理,然后通過這個1000000*1000000的協方差矩陣計算它的特征值和特征向量,最后獲得具有最大特征值的特征向量構成轉換矩陣。比如我們的前29個特征值已經能夠占到所有特征值的99%以上,那么我們只需要提取前29個特征值對應的特征向量即可。這樣就構成了一個1000000*29的轉換矩陣,然后用原來的樣本乘以這個轉換矩陣,就可以得到原來的樣本數據在新的特征空間的對應的坐標。30*1000000 * 1000000*29 = 30 *29, 這樣原來的訓練樣本每個樣本的特征值的個數就降到了29個。
一般來說,PCA降維后的每個樣本的特征的維數,不會超過訓練樣本的個數,因為超出的特征是沒有意義的。
下面是百度百科中對pca降維的一段解釋,還是挺清晰的:
“對於一個訓練集,100個對象模板,特征是10維,那么它可以建立一個100*10的矩陣,作為樣本。求這個樣本的協方差矩陣,得到一個10*10的協方差矩陣,然后求出這個協方差矩陣的特征值和特征向量,應該有10個特征值和特征向量,我們根據特征值的大小,取前四個特征值所對應的特征向量,構成一個10*4的矩陣,這個矩陣就是我們要求的特征矩陣,100*10的樣本矩陣乘以這個10*4的特征矩陣,就得到了一個100*4的新的降維之后的樣本矩陣,每個特征的維數下降了。
當給定一個測試的特征集之后,比如1*10維的特征,乘以上面得到的10*4的特征矩陣,便可以得到一個1*4的特征,用這個特征去分類。”
我對 PCA的一些了解
我的pca迷惑
迷惑一
迷惑三
pca的實現(matlab)
1. matlab自帶的實現方式
not necessarily zero, i.e., when N <= P, only the first N-1, and the
corresponding columns of COEFF and SCORE. This can be significantly
faster when P >> N.
cumsum(latent)./sum(latent),通過這樣計算特征值的累計貢獻率,一般來說都選擇前95%的特征值對應的特征向量,還是原來的矩陣30*1000000,如果你計算得到前25個特征值的累計貢獻率已經超過99.9%,那么就完全可以只要降維后的數據的前25列。
2. 一個自實現的pca降維方式
- %訓練
- %Lx=X'*X
- clear;
- clc;
- train_path='..\Data\TrainingSet\';
- phi=zeros(64*64,20);
- for i=1:20
- path=strcat(train_path,num2str(i),'.bmp');
- Image=imread(path);
- Image=imresize(Image,[64,64]);
- phi(:,i)=double(reshape(Image,1,[])');
- end;
- %mean
- mean_phi=mean(phi,2);
- mean_face=reshape(mean_phi,64,64);
- Image_mean=mat2gray(mean_face);
- imwrite(Image_mean,'meanface.bmp','bmp');
- %demean
- for i=1:19
- X(:,i)=phi(:,i)-mean_phi;
- end
- Lx=X'*X;
- tic;
- [eigenvector,eigenvalue]=eigs(Lx,19);
- toc;
- %normalization
- for i=1:19
- %K-L變換
- UL(:,i)=X*eigenvector(:,i)/sqrt(eigenvalue(i,i));
- end
- %display Eigenface
- for i=1:19
- Eigenface=reshape(UL(:,i),[64,64]);
- figure(i);
- imshow(mat2gray(Eigenface));
- end
得到的均值圖像mean_face:
前19個最大主元對應的“特征臉”:
測試:
測試用樣本:
- %使用測試樣本進行測試
- clc;
- test_path='..\Data\TestingSet\';
- error=zeros([1,4]);
- for i=1:4
- path=strcat(test_path,num2str(i),'.bmp');
- Image=imread(path);
- Image=double(imresize(Image,[64,64]));
- phi_test=zeros(64*64,1);
- phi_test(:,1)=double(reshape(Image,1,[])');
- X_test=phi_test-mean_phi;
- Y_test=UL'*X_test;
- X_test_re=UL*Y_test;
- Face_re=X_test_re+mean_phi;
- calculate error rate
- e=Face_re-phi_test;
- %%display figure
- Face_re_2=reshape(Face_re(:,1),[64,64]);
- figure(i);
- imshow(mat2gray(Image));
- title('Original');
- figure(10+i);
- imshow(mat2gray(Face_re_2));
- title('Reconstruct');
- error(1,i)=norm(e);
- %dispaly error rate
- error_rate=error(1,i);
- display(error_rate);
- end
四副測試樣本的重建誤差分別為:
1.4195e+003
1.9564e+003
4.7337e+003
7.0103e+003
可見測試樣本為人臉的樣本的重建誤差顯然小於非人臉的重建誤差。
通過 princomp降維后的數據進行重建
- clear;
- clc;
- train_path='E:\TrainingSet\angry\positive\';
- images = dir('E:\TrainingSet\angry\positive\*.bmp');
- phi=zeros(30,64*64);
- % 加載樣本圖像到 30*(64*64)的矩陣中,每一行代表一幅圖像
- for i=1:30
- path=strcat(train_path,images(i).name);
- Image=imread(path);
- Image=imresize(Image,[64,64]);
- phi(i,:)=double(reshape(Image,1,[]));
- end;
- % 計算平均臉,並保存用以查看
- mean_phi=mean(phi,1);
- mean_face=reshape(mean_phi,64,64);
- Image_mean=mat2gray(mean_face);
- imwrite(Image_mean,'meanface2.bmp','bmp');
- % 使用matlab自帶的pca進行降維
- [coeff, score, latent, TSQUARED] = princomp(phi,'econ');
- %display Eigenface
- for i=1:29
- Eigenface=reshape(coeff(:,i),[64,64]);
- figure(i);
- imshow(mat2gray(Eigenface));
- end
- % 進行測試
- %使用測試樣本進行測試
- clc;
- test_path='E:\BIT\code\FER\meanface.bmp';
- error=zeros([1,4]);
- Image=imread(test_path);
- Image=double(imresize(Image,[64,64]));
- phi_test=zeros(1,64*64);
- phi_test(1,:)=double(reshape(Image,1,[])); % 讀入的測試圖像保存為一行,行向量
- X_test=phi_test-mean_phi; % 檢測訓練樣本的平均臉
- Y_test=X_test*coeff; % 進行降維<span style="background-color: rgb(248, 248, 248);"></span>
- X_test_re=Y_test*coeff'; % 重構
- Face_re=X_test_re+mean_phi;
- %calculate error rate
- e=Face_re-phi_test;
- %%display figure
- Face_re_2=reshape(Face_re(1,:),[64,64]);
- figure(i);
- imshow(mat2gray(Image));
- title('Original');
- figure(10+i);
- imshow(mat2gray(Face_re_2));
- title('Reconstruct');
- error(1,i)=norm(e);
- %dispaly error rate
- error_rate=error(1,i);
- display(error_rate);
關於網絡上的一些解釋個人理解(僅供大家參考理解)
1.
最近看了些主成分分析,混跡Matlab論壇,翻了n多帖子,對princomp函數有了些了解。
在此只講一些個人理解,並沒有用術語,只求通俗。
貢獻率:每一維數據對於區分整個數據的貢獻,貢獻率最大的顯然是主成分,第二大的是次主成分......
[coef,score,latent,t2] = princomp(x);(個人觀點):
x:為要輸入的n維原始數據。帶入這個matlab自帶函數,將會生成新的n維加工后的數據(即score)。此數據與之前的n維原始數據一一對應。
score:生成的n維加工后的數據存在score里。它是對原始數據進行的分析,進而在新的坐標系下獲得的數據。他將這n維數據按貢獻率由大到小排列。(即在改變坐標系的情況下,又對n維數據排序)
latent:是一維列向量,每一個數據是對應score里相應維的貢獻率,因為數據有n維所以列向量有n個數據。由大到小排列(因為score也是按貢獻率由大到小排列)。
coef:是系數矩陣。通過cofe可以知道x是怎樣轉換成score的。
則模型為從原始數據出發:
score= bsxfun(@minus,x,mean(x,1))*coef;(作用:可以把測試數據通過此方法轉變為新的坐標系)
逆變換:
x= bsxfun(@plus,score*inv(coef),mean(x,1))
例子:

%% %清屏 clear %% %初始化數據 a=[-14.8271317103068,-3.00108550936016,1.52090778549498,3.95534842970601;-16.2288612441648,-2.80187433749996,-0.410815700402130,1.47546694457079;-15.1242838039605,-2.59871263957451,-0.359965674446737,1.34583763509479;-15.7031424565913,-2.53005662064257,0.255003254103276,-0.179334985754377;-17.7892158910100,-3.32842422986555,0.255791146332054,1.65118282449042;-17.8126324036279,-4.09719527953407,-0.879821957489877,-0.196675865428539;-14.9958877514765,-3.90753364293621,-0.418298866141441,-0.278063876667954;-15.5246706309866,-2.08905845264568,-1.16425848541704,-1.16976057326753;]; x=a; %% %調用princomp函數 [coef,score,latent,t2] = princomp(x); score %測試score是否和score_test一樣 score_test=bsxfun(@minus,x,mean(x,1))*coef; score_test latent=100*latent/sum(latent)%將latent總和統一為100,便於觀察貢獻率 pareto(latent);%調用matla畫圖
上圖是通過自帶函數繪制,當貢獻率累加至95%,以后的維數會不在顯示,最多只顯示10維。
下面用自己編寫的表示:
之前的錯誤認識:
1.認為主成分分析中latent顯示的貢獻值是原始數據的,其實是加工后的數據的。解釋:對原始數據既然選擇PCA方法,那么計算機認為原始數據每維之間可能存在關聯,你想去掉關聯、降低維數。所以采用這種方法的。所以計算機並不關心原始數據的貢獻值,因為你不會去用了,用的是加工后的數據(這也是為什么當把輸入數據每一維的順序改變后,score、latent不受影響的原因)。
2.認為PCA分析后自動降維,不對。PCA后會有貢獻值,是輸入者根據自己想要的貢獻值進行維數的改變,進而生成數據。(一般大家會取貢獻值在85%以上,要求高一點95%)。
3.PCA分析,只根據輸入數據的特征進行主成分分析,與輸出有多少類型,每個數據對應哪個類型無關。如果樣本已經分好類型,那PCA后勢必對結果的准確性有一定影響,我認為對於此類數據的PCA,就是在降維與准確性間找一個平衡點的問題,讓數據即不會維數多而使運算復雜,又有較高的分辨率。
2。
[coef,score,latent,t2] = princomp(X);
則那些參數的底層算法大體過程如下:
x0 = bsxfun(@minus,X,mean(X,1)); %x0為將X去均值后的數據。
[coef,ignore] = eig(x0'*x0); 這就是coef的由來。 【當然最終的還有排序什么亂七八糟的。。】
scroe = x0*coef % 這就是score的由來,就是一個簡單的線性變換,將原來的X的坐標轉換到主成分空間中的坐標。僅此而已
則模型為從原始數據出發:
score = bsxfun(@minus,X,mean(X,1))*coef;
逆變換:
X = bsxfun(@plus,score*inv(coef),mean(X,1))
以上這些你可以自己驗證,看是否正確。
關於你的第三問。對於每一個主成分,就看coef的相應的列就能知道原始的變量那個對該主成分貢獻大了啊。。
上面是沒有預處理的。如果加了可逆的預處理。則原始數據亦可從預處理后的數據表示出。進而 bla bla....
===============這回夠通俗易懂吧。。O(∩_∩)O
PS:pca算法流程,你熟悉嗎?只要知道那個算法過程。這些都不難理解啊。。
建議您看看書把pca算法流程再過一遍。。否則別人再怎么說也沒用。。。