http://blog.csdn.net/watkinsong/article/details/8234766
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算法流程再过一遍。。否则别人再怎么说也没用。。。