主成分分析 PCA算法

   夹角余弦是用原始数据定义的. 如果改用与样本平均值的比较值, 就是所谓的相似系数rkl (有的文献中也称为相关系数).
    rkl构成的矩阵为相似矩阵,多用于Q型分析.式中求和对特征进行(列标处的圆点表示该平均值是在行标指定的行上对所有列求出的平均值)
    距离:相似性还可以用模式空间中的“距离”来量度, 这显然是由地理学上的距离概念转化而来. 这种“距离”的定义很多,如Minkoski距离、Haming距离、Tanimoto距离等多种定义,这里不再赘述.
    模式识别方法简介:模式识别方法很多, 可以从不同的角度划分成不同的类别. 若按是否需要训练集来划分, 可以分为监督模式识别与无监督模式识别两大类.
    监督模式识别需要有一训练集, 例如,对于两类的情况,在训练集中,有一些样本属于A类,另外一些样本属于B类,将此信息输入计算机,经过训练之后,计算机可以对未知样本进行分类.监督模式识别包括线性判别、逐步判别分析、KNN、SIMCA等方法.
无监督模式识别则不需要输入分类信息, 例如,聚类分析等方法就是如此.
    人工神经网络可以是监督或无监督的.
    监督模式识别方法:一般步骤是:
    1.用一组已知类别的样本作为训练集,对计算机进行训练而得到判别模型;
    2.用另一组已知类别的样本即测试集来测试所得数学模型的识别(recognition)率. 测试集的分类对于研究者是已知的, 却不输入计算机.
    3.若识别率符合要求,就可以对预测集进行预测.无论对于研究者和计算机来说,预测集的活性都是未知的,预测结果正确与否需要由实验去检验.
    监督模式识别方法之一:主成分分析(PCA)
    主成份分析是一种简化数据结构、突出主要矛盾的多元统计方法.它利用某些数学方法将原有特征组合成相互正交的新特征——主成份,以突出反映事物的规律性. 它既是一种模式识别方法,也是一种数据预处理手段, 用主成份作为新特征进行模式识别,有时分类结果会更好.
    下面介绍其基本步骤:
    (1)写出原始数据矩阵X:

 
   

    (2)对X作标准化变换,构成标准化数据矩阵Z :

 

 

 

    (3)求矩阵Z的协方差矩阵Σ. 其矩阵元为

 

 

 

    (4)解矩阵Σ 的特征方程|Σ –λI |=0, 求得所有n个特征值及对应的n个特征向量(这与求解HMO久期方程作法相同).n是特征数目.将非零特征值由大到小依次排列,特征向量也相应排列.
    (5)从这n个特征值中选出前r个特征值(rn,只要这r个特征值之和占到n个特征值总和的85%以上即可),并选出r个对应的特征向量作为列向量, 构成nr列的系数矩阵D.
    (6)对标准化数据矩阵Z作变换:P m´ r =Zm´ n Dn´ r,则P 矩阵的每一行对应一个样本(共m 个),每一列对应一个主成份(共 r 个). 即:对于每一个样本,以一个特征向量作为线性组合系数, 将标准变量组合起来,就得到一个主成份,r个特征向量产生 r 个主成份.
    主成份是相互正交的一组新特征, 用它代替原来的特征, 既能减少特征的数目, 提高样本-特征比,又不会损失必要的信息,因为每一个主成份都包含着原有特征的信息.于是,原始的特征变量数目就可以多取一些,只要样本-主成份比大于3即可. 从这个意义上讲,PCA可以作为数据预处理的一种手段.

 

    如前所述,在二维和三维空间中,人的眼睛是最好的模式识别器, 但在高维空间中却不是这样. 于是就必须先压缩空间维数再显示. 这种压缩也叫做“空间约化”. 样本在高维空间中有一种分布模式,例如,各样本之间有确定的"距离" .把高维空间约化成低维空间后,不可能期望原来的分布模式一成不变,只能期望畸变尽可能小一些. 空间约化有不同的方法. 若约化后的空间是原有空间坐标的非线性组合,则称约化过程为"映射"; 若约化后的空间是原有空间坐标的线性组合,约化过程就称为“投影”, 也有的文献将"投影"称为"线性映射".

 

图10-10 荧光粉线性映射分类图

 
 

    PCA具有线性映射显示功能. 以某两个主成份构成二维坐标平面, 可将所有样本显示在该平面上进行分类.
    线性映射实例: 陈念贻等对Keise Optonix公司申请的德国专利系列中的46种稀土硼酸盐绿色荧光粉, 以Tb、Ce含量,原子序与离子半径比, 平均电负性作为特征参数,研究其与荧光粉亮度的关系,得到分类图.
    根据显示的优化方向,可以设计出专利范围以外的新配方,有些已被实验证实.
    

clc;
clear all
Class_Num=20;%样本及测试的种类为20类,每类中有10张图片
Train_Num=6;%现拿出每类中6张作为训练样本
Total=Class_Num*Train_Num;
n=1;
for i=1:20
    for j=1:6
        A=imread(strcat('F:\timchen\s',num2str(i),'\',num2str(j),'.pgm'));
       % imshow(A)
       A=im2double(A);%这个函数不简单啊,把整数全部搞成小于1的数啊
       Train_DATA(:,n)=A(:);
       n=n+1;
    end
end
%%以上获得了训练数据
Mean=mean(Train_DATA(2));%求行的均值,这样得出的结果是一个向量
Train_DATA=Train_DATA-Mean;%%这里的训练数据已经减掉均值了
R=Train_DATA'*Train_DATA;%注意这里的行数远远大于列数哦,所以考虑组成维数小的方阵,且是协方差矩阵
%%接下来需要求的协方差矩阵的特征值和特征向量,且需要对其进行排序,因为我们要对其进行降维,这里取50维
[V,D]=eig(R);
[a,b]=sort(diag(D));
n=1;
for i=71:120
    temp1(:,n)=V(:,b(i));%降维的特征向量
    temp2(n,n)=a(b(i));%降维后的特征值
    n=n+1;
end
%%以上获得了协方差矩阵的降维特征值和特征向量,接下来做svd定理
%%正交归一化后的特征脸空间
W=Train_DATA*temp1*(temp2)^-0.5;
KLTrain_DATA=W'*Train_DATA;%%将训练的数据投影到特征脸空间

%%%%%%%%%%%%%以下进行LDA%%%%%%%%%%%
%%需要求出类内散度矩阵和类间散度矩阵,由此可以求出投影的向量
Mean1=mean(KLTrain_DATA,2);%求出投影到特征脸空间的数据的行均值
pp=zeros(50,20);
%%以下程序时求出每一类的均值
for i=1:20
    for j=1:Train_Num
        pp(:,i)=pp(:,i)+KLTrain_DATA(:,((i-1)*Train_Num+j));
    end
end
ClassMean=pp/6;
%%计算类间散度矩阵SB
SB=zeros(50,50);
for m=1:20
    SB=SB+(ClassMean(:,m)-Mean1)*(ClassMean(:,m)-Mean1)'*Train_Num;
end
%%计算类内散步矩阵SW
qq=zeros(50,50);
SW=zeros(50,50);
for a=1:20
    for b=1:Train_Num
        qq=qq+(KLTrain_DATA(:,((a-1)*Train_Num+b))-ClassMean(:,a))*(KLTrain_DATA(:,((a-1)*Train_Num+b))-ClassMean(:,a))';
    end
    SW=SW+qq;
end

M=inv(SW)*SB;
[v,d]=eig(M);

%%取19个特征向量,在50个特征向量中取最大的 特征值对应的19个特征向量
num=19;
w=[];
for i=1:num
    w=[w,v(:,i)];
end

KLTrain_DATA=KLTrain_DATA-Mean1*ones(1,120);
Final_KLTrain_DATA=w'*KLTrain_DATA;

%%识别阶段
testface=imread('F:\timchen\s4\8.pgm');
testface=imresize(testface,[112 92],'bicubic');
testface=im2double(testface);
test1=testface(:);
test1=test1-Mean;
KLtestface=W'*test1;
KLtestface=KLtestface-Mean1;
Final_KLtestface=w'*KLtestface;


min_dist=1e+30;
     for i=1:120
         train=Final_KLTrain_DATA(:,i);
          dist=sqrt(dot(Final_KLtestface-train,Final_KLtestface-train));
          if min_dist>dist
              min_dist=dist;
              No=i;
         end
     end
class=ceil(No/6);
fprintf('\n');
fprintf('此人在本库中,号码:%d\n', class);
%%%%%%%%%%%%%%%%%%%%%%%%显示原人脸和待测人脸%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% imsize=size(A);
% Image_row_NUM=imsize(1);
% Image_col_NUM=imsize(2);
% huifu=reshape(allsamples(:,class*6),Image_row_NUM,Image_col_NUM);
% huifu=im2uint8(huifu);
% testface=im2uint8(testface);
% subplot(1,2,1);imshow(huifu);title('库中人脸');
% subplot(1,2,2);imshow(testface);title('待测人脸');



对同一个体进行多项观察时,必定涉及多个随机变量X1X2Xp,它们都是的相关性,一时难以综合。这时就需要借助主成分分析 (principal componentanalysis)来概括诸多信息的主要方面。我们希望有一个或几个较好的综合指标来概括信息,而且希望综合指标互相独立地各代表某一方面的性质。

任何一个度量指标的好坏除了可靠、真实之外,还必须能充分反映个体间的变异。如果有一项指标,不同个体的取值都大同小异,那么该指标不能用来区分不同的个体。由这一点来看,一项指标在个体间的变异越大越好。因此我们把“变异大”作为“好”的标准来寻求综合指标。

 

1.主成分的一般定义 

设有随机变量X1X2Xp其样本均数记为 ,样本标准差记为S1S2Sp。首先作标准化变换

 

我们有如下的定义:

   (1)C1=a11x1+a12x2++a1pxp,且使Var(C1)最大,则称C1为第一主成分;

   (2)C2=a21x1+a22x2+…+a2pxp(a21a22a2p)垂直于(a11a12a1p),且使Var(C2)最大,则称C2为第二主成分;

   (3)类似地,可有第三、四、五主成分,至多有p个。

   

2.      主成分的性质   

  主成分C1C2Cp具有如下几个性质:

   (1)主成分间互不相关,即对任意ijCiCj的相关系数

Corr(CiCj)=0          i¹ j                       

   (2)组合系数(ai1ai2aip)构成的向量为单位向量,

                              

   (3)各主成分的方差是依次递减的,

Var(C1)Var(C2)Var(Cp)  

   (4)总方差不增不减

Var(C1)+Var(C2)+ …+Var(Cp)

                   =Var(x1)+Var(x2)+… +Var(xp)

=p

这一性质说明,主成分是原变量的线性组合,是对原变量信息的一种改组,主成分不增加总信息量,也不减少总信息量。

(5)主成分和原变量的相关系数 Corr(Cixj)=aij=aij

    (6)X1X2Xp的相关矩阵为R, (ai1ai2aip)则是相关矩阵R的第i个特征向量(eigenvector)。而且,特征值li就是第i主成分的方差,

Var(Ci)=li                                  

 

其中li为相关矩阵R的第i个特征值(eigenvalue)

l1l2≥…≥lp0

 

3.      主成分的数目的选取 

前已指出,设有p个随机变量,便有p个主成分。由于总方差不增不减,C1C2等前几个综合变量的方差较大,CpCp-1等后几个综合变量的方差较小,严格说来,只有前几个综合变量才称得上主()成份,后几个综合变量实为“次”()成份。实践中总是保留前几个,忽略后几个。

保留多少个主成分取决于保留部分的累积方差在方差总和中所占百分比(即累计贡献率),它标志着前几个主成分概括信息之多寡。实践中,粗略规定一个百分比便可决定保留几个主成分;如果多留一个主成分,累积方差增加无几,便不再多留。

 

 

4.主成分回归

   主成分分析本身往往并不是目的,而是达到目的的一种手段。因此,它多用在大型研究项目的某个中间环节。例如,把它用在多重回归中,便产生了主成分回归。另外,它还可以用于聚类、判别分析等。本节主要介绍主成分回归。

   在多重回归曾指出,当自变量间高度相关时,某些回归参数的估计值极不稳定,甚至出现有悖常理、难以解释的情形。这时,可先采用主成分分析产生若干主成分,它们必定会将相关性较强的变量综合在同一个主成分中,而不同的主成分又是互相独立的。只要多保留几个主成分,原变量的信息不致过多损失。然后,以这些主成分为自变量进行多重回归就不会再出现共线性的困扰。如果原有p个自变量X1X2Xp,那么,采用全部p个主成分所作回归完全等价于直接对原变量的回归;采用一部分主成分所作回归虽不完全等价于对原变量的回归,但往往能摆脱某些虚假信息,而出现较合理的结果。

以上思路也适用于判别分析,当自变量高度相关时,直接作判别分析同样有多重共线性问题,可先计算自变量的主成分,然后通过主成分估计判别函数。

 

主成分分析 ( Principal Component Analysis , PCA )是一种掌握事物主要矛盾的统计分析方法,它可以从多元事物中解析出主要影响因素,揭示事物的本质,简化复杂的问题。计算主成分的目的是将高维数据投影到较低维空间。给定n 个变量的 m 个观察值,形成一个 n ′ m 的数据矩阵, n通常比较大。对于一个由多个变量描述的复杂事物,人们难以认识,那么是否可以抓住事物主要方面进行重点分析呢?如果事物的主要方面刚好体现在几个主要变量上,我们只需要将这几个变量分离出来,进行详细分析。但是,在一般情况下,并不能直接找出这样的关键变量。这时我们可以用原有变量的线性组合来表示事物的主要方面,PCA 就是这样一种分析方法。

    PCA的目标是寻找 r ( r<n)个新变量,使它们反映事物的主要特征,压缩原有数据矩阵的规模。每个新变量是原有变量的线性组合,体现原有变量的综合效果,具有一定的实际含义。这r 个新变量称为“主成分”,它们可以在很大程度上反映原来 n个变量的影响,并且这些新变量是互不相关的,也是正交的。通过主成分分析,压缩数据空间,将多元数据的特征在低维空间里直观地表示出来。例如,将多个时间点、多个实验条件下的基因表达谱数据(N 维)表示为 3 维空间中的一个点,即将数据的维数从 降到 。

    在进行基因表达数据分析时,一个重要问题是确定每个实验数据是否是独立的,如果每次实验数据之间不是独立的,则会影响基因表达数据分析结果的准确性。对于利用基因芯片所检测到的基因表达数据,如果用PCA方法进行分析,可以将各个基因作为变量,也可以将实验条件作为变量。当将基因作为变量时,通过分析确定一组“主要基因元素”,它们能够很好地说明基因的特征,解释实验现象;当将实验条件作为变量时,通过分析确定一组“主要实验因素”,它们能够很好地刻画实验条件的特征,解释基因的行为。下面着重考虑以实验条件作为变量的PCA 分析方法。假设将数据的维数从 R N 降到 R 3 ,具体的 PCA 分析步骤如下:

(1) 第一步计算矩阵 X 的样本的协方差矩阵 S :

(2) 第二步计算协方差矩阵S的本征向量 e1,e2,…,eN的本征值, i = 1,2,…,N 。本征值按大到小排序: ;

(3)第三步投影数据到本征矢张成的空间之中,这些本征矢相应的本征值为。现在数据可以在三维空间中展示为云状的点集。

    对于PCA ,确定新变量的个数 r 是一个两难的问题。我们的目标是减小 r ,如果 r小,则数据的维数低,便于分析,同时也降低了噪声,但可能丢失一些有用的信息。究竟如何确定 r呢?这需要进一步分析每个主元素对信息的贡献。

    令 代表第 i 个特征值,定义第 i 个主元素的贡献率为:

                                     (8-45)

前 r 个主成分的累计贡献率为:

                                (8-46)

贡献率表示所定义的主成分在整个数据分析中承担的主要意义占多大的比重,当取前 r个主成分来代替原来全部变量时,累计贡献率的大小反应了这种取代的可靠性,累计贡献率越大,可靠性越大;反之,则可靠性越小。一般要求累计贡献率达到70% 以上。

    经过PCA分析,一个多变量的复杂问题被简化为低维空间的简单问题。可以利用这种简化方法进行作图,形象地表示和分析复杂问题。在分析基因表达数据时,可以针对基因作图,也可以针对实验条件作图。前者称为Q 分析,后者称为 R 分析。

    表8.1 是对酵母 6000 多个基因在 7 个时间点表达数据的 PCA分析结果,每列数据代表主元素的系数。从表中可以看出,前两个主元素反应了 90% 以上( 76.9%+13.5%)的变化,而前三个主元素反应了 95% 以上的变化,因此取前两个主元素即可。 图 8.6 是对 7 个特征值的图示。

 

    图8.7 是前三个主元素系数变化图。第 1 个主元素代表各个基因表达加权平均,除第 1 个时间点外,其它所有系数都为正值( 见图8.7(a) )。如果某个基因对应此主元素的值为较大的正数,则基因表达上调,如果此主元素的值为较大的负数,则基因表达下调。第 2个主元素表示在时间序贯中基因表达的变化,除第 1 个时间点外,其它系数逐个增大( 见图 8.7(b))。如果某个基因的表达量随时间不断增加,则此主元素的值为正;如果表达量随时间不断减小,则此主元素的值为负。第 3个主元素系数变化曲线为抛物线形( 见图 8.7(c) )。



 1.eigenface_example.m(主程序)

<span style="font-size:14px;"> 

% load function files from subfolders aswell
addpath (genpath ('.'));

% load data
[X y width height names] = read_images('E:/faces_rec/orl_faces');

% compute a model
eigenface = eigenfaces(X,y,100)

% plot the first (atmost) 16 eigenfaces
figure;
title('Eigenfaces (AT&T Facedatabase)');
hold on;
for i=1:min(16, size(eigenface.W,2))
    subplot(4,4,i);
    eigenface.W(:,i)
    comp = cvtGray(eigenface.W(:,i), width, height)
    imshow(comp);
    colormap(jet(256));
    title(sprintf('Eigenface #%i', i));
end

%% 2D plot of projection (first three classes, add those you want)
figure; hold on;
for i = findclasses(eigenface.y, [1,2,3])
 % LineSpec: red dots 'r.'
 plot3(eigenface.P(1,i), eigenface.P(2,i), eigenface.P(3,i),'r.'), view(45,-45);
 text(eigenface.P(1,i), eigenface.P(2,i),eigenface.P(3,i), num2str(eigenface.y(i)));
end

pause;

以下为各部分子程序:

function model = eigenfaces(X, y, num_components)
 %% Performs a PCA on X and stores num_components principal components.
 %%
 %% Args:
 %%   X [dim x num_data] input data
 %%   y [1 x num_data] classes
 %%  num_components [int] components to keep
 %%
 %% Out:
 %%  model [struct] learned model
 %%   .name [char] name
 %%   .mu [dim x 1] sample mean of X
 %%   .num_components [int] number of components in this model
 %%   .W [dim x num_components] components identified by PCA
 %%   .P [num_components x num_data] projection of X
 %%
 %% Example:
 %%  m_eigenface = eigenfaces(X, y, 100)
 if(nargin < 3)
  num_components=size(X,2)-1;
 end
 
 % perform pca
 Pca = pca(X,y,num_components);
 
  % build model
  model.name = 'eigenfaces';
 model.W = Pca.W;
 model.num_components = num_components;
 model.mu = Pca.mu;
 % project data
 model.P = model.W'*(X - repmat(Pca.mu, 1, size(X,2)));
 % store classes
 model.y = y;
end

 

function G = cvtGray(I, width, height)
 %% Returns a greyscaled representation G of I.
 %%
 %% Args:
 %%  I: Array with width*height elements.
 %%  width: Width of G.
 %%  height: Height of G
 %%
 %% Returns:
 %%  Greyscaled (intensity 0-255) and reshaped image I.
 %%
 %% Example:
 %%  cvtGray(I, 200, 100)
 %%
 G = reshape(normalize(I, 0, 255), height, width);
 G = uint8(G);
end

 

function N = normalize(I, l, h)
 minI = min(I);
 maxI = max(I);
 %% Normalize to [0...1].
 N = I - minI;
 N = N ./ (maxI - minI);
 %% Scale to [low...high].
 N = N .* (h-l);
 N = N + l;
end

 

function [X y width height names] = read_images(path)
 %% Read images from a given path and return the Imagematrix X.
 %%
 %% Returns:
 %%  X [numDim x numSamples] Array with images given in columns -- [X1,X2,...,Xn]
 %%  y [1 x numSamples] Classes corresponding to images of X. -- [y1,y2,...,yn]
 %%  width [int] width of the images
 %%  height [int] height of the images
 %%  names [cell array] folder name of each class, so names{1} is the name of class 1
 %%
 %% Example:
 %%  [X y width height names] = read_images("./data/yalefaces")
 %%
 folder = list_files(path);
 X = [];
 y = [];
 names = {};
 n = 1;
 for i=1:length(folder)
  subject = folder{i};
  images = list_files([path, filesep, subject]);%filesep 表示Directory separator for current platform,images
  if(length(images) == 0)
   continue; %% dismiss files or empty folder
  end
  
  added = 0;
  names{n} = subject;
  %% build image matrix and class vector
  for j=1:length(images)
   %% absolute path
   filename = [path, filesep, subject, filesep, images{j}];

   %% Octave crashes on reading non image files (uncomment this to be a bit more robust)
   %extension = strsplit(images{j}, "."){end};
   %if(~any(strcmpi(extension, {"bmp", "gif", "jpg", "jpeg", "png", "tiff"})))
   % continue;
   %endif
     
   % Quite a pythonic way to handle failure.... May blow you up just like the above.
   try
    T = double(imread(filename));
   catch
    lerr = lasterror;
    fprintf(1,'Cannot read image %s', filename)
   end
   
   [height width channels] = size(T);
     
   % greyscale the image if we have 3 channels
   if(channels == 3)
    T = (T(:,:,1) + T(:,:,2) + T(:,:,3)) / 3;
   end
     
   %% finally try to append data
   try
    X = [X, reshape(T,width*height,1)];
    y = [y, n]
    added = added + 1;
   catch
    lerr = lasterror;
    fprintf(1,'Image cannot be added to the Array. Wrong image size?\n')
   end
  end
  % only increment class if images were actually added!
  if ~(added == 0)
   n = n + 1;
  end
 end
end

 

function L = list_files(path)
 %% List all files in a folder and return it as a cell array.
 %%
 %% Args:
 %%  path: Path to list files from.
 %%
 %% Returns:
 %%  L: Cell array with files in this folder.
 %%
 %% Example:
 %%  L = list_files("./data/yalefaces")
    %%返回的结果 Columns 1 through 14

%     'README'    'at.txt'    's1'    's10'    's11'    's12'    's13'    's14'    's15'    's16'    's17'    's18'    's19'    's2'

%     's20'    's21'    's22'    's23'    's24'    's25'    's26'    's27'    's28'    's29'    's3'    's30'    's31'    's32'    's33'

%     's34'    's35'    's36'    's37'    's38'    's39'    's4'    's40'    's5'    's6'    's7'    's8'    's9'
 L = dir(path);
 L = L(3:length(L));
 L = struct2cell(L);
 L = L(1,:);
end

 

function idx = findclasses(y, list_of_classes)
 min_class = min(y);
 max_class = max(y);
  idx = [];
 for i = list_of_classes
  if((i >= min_class) || (i <= max_class))
   idx = [idx, find(y == i)];
  end
 end
end

 

function model = pca(X, y, num_components)
 %% Performs a PCA on X and stores num_components principal components.
 %%
 %% Args:
 %%   X [dim x num_data] Input
 %%   y [1 x num_data] Classes
 %%  num_components [int] Number of components to use.
 %%
 %% Out:
 %%  model [struct] learned model
 %%   .name [char] name of this model
 %%   .W [dim x num_components] components identified by PCA
 %%   .num_components [int] mumber of components used in this model.
 %%   .mu [dim x 1] sample mean of X
 %%
 %% Example:
 %%  pca(X, y, struct('num_components',100))
 %%
 if(nargin < 3)
  num_components=size(X,2)-1;
 end
 % center data
  mu = mean(X,2);
  X = X - repmat(mu, 1, size(X,2));
  % svd on centered data == pca
  [E,D,V] = svd(X ,'econ');
 
  % build model
  model.name = 'pca';
 model.W = E(:,1:num_components);
 model.num_components = num_components;
 model.mu = mu;
end</span>






你可能感兴趣的:(主成分分析 PCA算法)