关于PCA原理可以直接参考下面的文章
深入理解PCA
PCA是经常用来减少数据集的维数,同时保留数据集中对方差贡献最大的特征来达到简化数据集的目的。
PCA的原理就是将原来的样本数据投影到一个新的空间中,相当于我们在矩阵分析里面学习的将一组矩阵映射到另外的坐标系下。通过一个转换坐标,也可以理解成把一组坐标转换到另外一组坐标系下,但是在新的坐标系下,表示原来的原本不需要那么多的变量,只需要原来样本的最大的一个线性无关组的特征值对应的空间的坐标即可。
PCA算法核心思想就是将 n 维特征映射到 k 维上(k < n),这 k 维是全新的正交特征。我们将这 k 维成为主元,是重新构造出来的 k 维特征,而不是简单地从 n 维特征中取出其余 n-k 维特征。
PCA实现的步骤
(1)把原始数据中每个样本用一个向量表示,然后把所有样本组合起来构成一个矩阵。为了避免样本的单位的影响,样本集需要标准化(一般都是去均值化)。
(2)求该矩阵的协方差矩阵。
(3)求步骤2中得到的协方差矩阵的特征值和特征向量。
(4)将求出的特征向量按照特征值的大小进行组合形成一个映射矩阵,并根据指定的PCA保留的特征个数取出映射矩阵的前n行或者前n列作为最终的映射矩阵。
(5)用步骤4的映射矩阵对原始数据进行映射,达到数据降维的目的。
function [Y,V,E,D] = newpca(X)
%其中X为输入数据,X的每一列是一个输入样本。返回值Y是对X进行PCA分析后的投影矩阵。V是与X有关的协方差矩阵特征向量的白化矩阵,E是对应的特征向量(列)构成的矩阵,D是对应的特征值构成的对角矩阵(特征值处于对角线上)。返回值中的白化矩阵,特征向量和特征值都是按照对应特征值大小进行排序后了的。
% do PCA on image patches
%
% INPUT variables:
% X matrix with image patches as columns
%
% OUTPUT variables:
% Y the project matrix of the input data X without whiting
% V whitening matrix
% E principal component transformation (orthogonal)
% D variances of the principal components
%去除直流成分
X = X-ones(size(X,1),1)*mean(X);
% Calculate the eigenvalues and eigenvectors of the new covariance matrix.
covarianceMatrix = X*X'/size(X,2); %求出其协方差矩阵
%E是特征向量构成,它的每一列是特征向量,D是特征值构成的对角矩阵
%这些特征值和特征向量都没有经过排序
[E, D] = eig(covarianceMatrix);
% Sort the eigenvalues and recompute matrices
% 因为sort函数是升序排列,而需要的是降序排列,所以先取负号,diag(a)是取出a的对角元素构成
% 一个列向量,这里的dummy是降序排列后的向量,order是其排列顺序
[dummy,order] = sort(diag(-D));
E = E(:,order);%将特征向量按照特征值大小进行降序排列,每一列是一个特征向量
Y = E'*X;
d = diag(D); %d是一个列向量
%dsqrtinv是列向量,特征值开根号后取倒,仍然是与特征值有关的列向量
%其实就是求开根号后的逆矩阵
dsqrtinv = real(d.^(-0.5));
Dsqrtinv = diag(dsqrtinv(order));%是一个对角矩阵,矩阵中的元素时按降序排列好了的特征值(经过取根号倒后)
D = diag(d(order));%D是一个对角矩阵,其对角元素由特征值从大到小构成
V = Dsqrtinv*E';%特征值矩阵乘以特征向量矩阵
function [lowData,reconMat] = PCA(data,K)
[row , col] = size(data);
meanValue = mean(data);
%varData = var(data,1,1);
normData = data - repmat(meanValue,[row,1]);
covMat = cov(normData(:,1),normData(:,2));%求取协方差矩阵
[eigVect,eigVal] = eig(covMat);%求取特征值和特征向量
[sortMat, sortIX] = sort(eigVal,'descend');
[B,IX] = sort(sortMat(1,:),'descend');
len = min(K,length(IX));
eigVect(:,IX(1:1:len));
lowData = normData * eigVect(:,IX(1:1:len));
reconMat = (lowData * eigVect(:,IX(1:1:len))') + repmat(meanValue,[row,1]); % 将降维后的数据转换到新空间 end
下面给出PCA的Matlab实现部分:Matlab自带的函数
Matlab中已经包含了实现了的PCA算法,可以通过princomp函数调用。其形式为:
[COEFF,SCORE, latent]=princomp(X);
X:为要输入的n维原始数据。带入这个matlab自带函数,将会生成新的n维加工后的数据(即SCORE)。此数据与之前的n维原始数据一一对应。
COEFF为主成分分量,即变换空间中的那些基向量,是系数矩阵。通过COEFF可以知道x是怎样转换成SCORE的。
在n行p列的数据集X上做主成分分析。返回主成分系数。X的每行表示一个样本的观测值,每一列表示特征变量。COEFF是一个p行p列的矩阵,是X矩阵所对应的协方差阵V的所有特征向量组成的矩阵,即变换矩阵或称投影矩阵,COEFF每列对应一个特征值的特征向量,列的排列顺序是按特征值的大小递减排序。
SCORE为主成分,即X的低维表示。生成的n维加工后的数据存在SCORE里。它是对原始数据进行的分析,进而在新的坐标系下获得的数据。他将这n维数据按贡献率由大到小排列。(即在改变坐标系的情况下,又对n维数据排序)
latent为一个包含样本协方差矩阵的本征值的向量。是一维列向量,每一个数据是对应SCORE里相应维的贡献率,因为数据有n维所以列向量有n个数据。由大到小排列(因为SCORE也是按贡献率由大到小排列)。
princomp这个matlab自带的函数,在降维之前就将每一个样本减去了一个所有样本的平均值。princomp这里使用一行表示一个样本,每行包括这个样本的所有的特征值。
其实我们要的是由函数[COEFF,SCORE, latent] = princomp(X)它所产生的pc和latent。由latent可以算出降维后的空间所能表示原空间的程度,只要这个累积的值大于95%就行了
cumsum(latent)./sum(latent)
举例说明:
load hald; %载入matlab内部数据
[COEFF,SCORE,latent,tsquare] = princomp(ingredients); %调用pca分析函数
cumsum(latent)./sum(latent)
ans =
0.8660
0.9789
0.9996
1.0000
由以上ans值可以看出前两个主成分就能表示原空间的97.89%,所以取COEFF中的前两列可做主成分变换矩阵tranMatrix = COEFF(:,1:2)。则从原来的4维空间降到2维空间。
对任意一个原空间样本,例如a=(7 ,26 ,6 ,60)变到低维空间的表达式为
a1 = a*tranMatrix。(当然你也可以取pc中的前三列,由原来的4维空间变到3维空间)
biplot(pc(:,1:2),’Scores’,score(:,1:2),’VarLabels’,…
{‘X1’ ‘X2’ ‘X3’ ‘X4’})
测试样本降维
如果你需要对测试样本降维,一般情况下,使用matlab自带的方式,肯定需要对测试样本减去一个训练样本均值,因为你在给训练样本降维的时候减去了均值,所以测试样本也要减去均值,然后乘以coeff这个矩阵,就获得了测试样本降维后的数据。使用训练样本得到的转换矩阵,保证训练样本和测试样本转换到相同的样本空间中。比如说你的测试样本是1*1000000,那么乘上一个1000000*29的降维矩阵,就获得了1*29的降维后的测试样本的降维数据。
princomp(x)使用的行表示一个样本,每行的所有的列数据都是这个样本的特征值。降维以后比如是30*29,那么每一行就是降维以后的数据。每个样本有29个特征值。
%X为训练集,Xtest为测试集
[COEFF,SCORE, latent]=princomp(X);
SelectNum=cumsum(latent)./sum(latent)
%选择由latent可以算出降维后的空间所能表示原空间的程度,只要这个累积的值大于95%的数目ForwardNum,就选择前ForwardNum个主成分作为变换矩阵。
%做主成分变换矩阵
%
tranMatrix = COEFF(:,1:ForwardNum)
[row , col] = size(X);
meanValue = mean(X);
normData = Xtest - repmat(meanValue,[row,1]);
NewData = normData *tranMatrix;
%NewData就是Xtest经过PCA降维后的数据。