夹角余弦是用原始数据定义的. 如果改用与样本平均值的比较值, 就是所谓的相似系数rkl (有的文献中也称为相关系数). |
|
(2)对X作标准化变换,构成标准化数据矩阵Z : |
|
|
|
(3)求矩阵Z的协方差矩阵Σ. 其矩阵元为 |
|
|
|
(4)解矩阵Σ 的特征方程|Σ –λI |=0, 求得所有n个特征值及对应的n个特征向量(这与求解HMO久期方程作法相同).n是特征数目.将非零特征值由大到小依次排列,特征向量也相应排列. |
|
如前所述,在二维和三维空间中,人的眼睛是最好的模式识别器, 但在高维空间中却不是这样. 于是就必须先压缩空间维数再显示. 这种压缩也叫做“空间约化”. 样本在高维空间中有一种分布模式,例如,各样本之间有确定的"距离" .把高维空间约化成低维空间后,不可能期望原来的分布模式一成不变,只能期望畸变尽可能小一些. 空间约化有不同的方法. 若约化后的空间是原有空间坐标的非线性组合,则称约化过程为"映射"; 若约化后的空间是原有空间坐标的线性组合,约化过程就称为“投影”, 也有的文献将"投影"称为"线性映射".
图10-10 荧光粉线性映射分类图 |
|
PCA具有线性映射显示功能. 以某两个主成份构成二维坐标平面, 可将所有样本显示在该平面上进行分类. |
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('待测人脸');
对同一个体进行多项观察时,必定涉及多个随机变量X1,X2,…,Xp,它们都是的相关性,一时难以综合。这时就需要借助主成分分析 (principal componentanalysis)来概括诸多信息的主要方面。我们希望有一个或几个较好的综合指标来概括信息,而且希望综合指标互相独立地各代表某一方面的性质。
任何一个度量指标的好坏除了可靠、真实之外,还必须能充分反映个体间的变异。如果有一项指标,不同个体的取值都大同小异,那么该指标不能用来区分不同的个体。由这一点来看,一项指标在个体间的变异越大越好。因此我们把“变异大”作为“好”的标准来寻求综合指标。
1.主成分的一般定义
设有随机变量X1,X2,…,Xp,其样本均数记为, ,…,,样本标准差记为S1,S2,…,Sp。首先作标准化变换
我们有如下的定义:
(1)若C1=a11x1+a12x2+…+a1pxp,,且使Var(C1)最大,则称C1为第一主成分;
(2)若C2=a21x1+a22x2+…+a2pxp,,(a21,a22,…,a2p)垂直于(a11,a12,…,a1p),且使Var(C2)最大,则称C2为第二主成分;
(3)类似地,可有第三、四、五…主成分,至多有p个。
2. 主成分的性质
主成分C1,C2,…,Cp具有如下几个性质:
(1)主成分间互不相关,即对任意i和j,Ci和Cj的相关系数
Corr(Ci,Cj)=0 i¹ j
(2)组合系数(ai1,ai2,…,aip)构成的向量为单位向量,
(3)各主成分的方差是依次递减的,即
Var(C1)≥Var(C2)≥…≥Var(Cp)
(4)总方差不增不减,即
Var(C1)+Var(C2)+ …+Var(Cp)
=Var(x1)+Var(x2)+… +Var(xp)
=p
这一性质说明,主成分是原变量的线性组合,是对原变量信息的一种改组,主成分不增加总信息量,也不减少总信息量。
(5)主成分和原变量的相关系数 Corr(Ci,xj)=aij=aij
(6)令X1,X2,…,Xp的相关矩阵为R, (ai1,ai2,…,aip)则是相关矩阵R的第i个特征向量(eigenvector)。而且,特征值li就是第i主成分的方差,即
Var(Ci)=li
其中li为相关矩阵R的第i个特征值(eigenvalue)
l1≥l2≥…≥lp≥0
3. 主成分的数目的选取
前已指出,设有p个随机变量,便有p个主成分。由于总方差不增不减,C1,C2等前几个综合变量的方差较大,而Cp,Cp-1等后几个综合变量的方差较小,严格说来,只有前几个综合变量才称得上主(要)成份,后几个综合变量实为“次”(要)成份。实践中总是保留前几个,忽略后几个。
保留多少个主成分取决于保留部分的累积方差在方差总和中所占百分比(即累计贡献率),它标志着前几个主成分概括信息之多寡。实践中,粗略规定一个百分比便可决定保留几个主成分;如果多留一个主成分,累积方差增加无几,便不再多留。
4.主成分回归
主成分分析本身往往并不是目的,而是达到目的的一种手段。因此,它多用在大型研究项目的某个中间环节。例如,把它用在多重回归中,便产生了主成分回归。另外,它还可以用于聚类、判别分析等。本节主要介绍主成分回归。
在多重回归曾指出,当自变量间高度相关时,某些回归参数的估计值极不稳定,甚至出现有悖常理、难以解释的情形。这时,可先采用主成分分析产生若干主成分,它们必定会将相关性较强的变量综合在同一个主成分中,而不同的主成分又是互相独立的。只要多保留几个主成分,原变量的信息不致过多损失。然后,以这些主成分为自变量进行多重回归就不会再出现共线性的困扰。如果原有p个自变量X1,X2,…,Xp,那么,采用全部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>