1.为什么进行PCA?
我们处于数据爆炸的时代,许多数据的维度比较高,处理起来十分麻烦,处理时容易造成“维度灾难”。主成分分析旨在将数据进行预处理,方便后续的数据分析、研究、利用。现如今,PCA算法已经广泛应用于各个领域:图像处理、商品综合评价、物质成分分析等。在制作简易的人脸识别时,可以将训练集和测试集的主成分分别提取出来,在识别时计算两者主成分之间的欧氏距离,如果低于一定阈值,可以认为是同一个人。主成分较原来图像维度比较低,在进行后续欧氏距离计算时计算量会比较小。
2.PCA的主要思想
PCA主要是希望找到一个空间让原始数据投影,从而实现原始数据的降维,降维后的向量(主成分)能够表征原始数据的主要信息。对该空间有两个要求:一是可以尽可能保留最重要的成分,二是保留下来的各成分之间的联系要小。从数学和信息学角度而言所谓的保留主要成分就是指方差较大的数据,数据的方差越大,不确定性大,熵也越大,信息量也越大;各成分之间的联系要小是指成分之间的协方差要小,否则两个主成分之间所表征的信息就会高度相似,浪费空间。
(图2-1 PCA算法对投影空间的要求)
如何寻找到这一空间?从图1中可以观察到:假设一个维的样本数据为
第一个坐标轴的方向和原始数据中方差最大的方向一致;第二个是与第一个坐标轴正交的平面中数据方差最大的方向;第三个是前两个坐标轴正交的平面中数据方差最大的方向。以此类推,找到
个这样的坐标轴。当找到这样一个空间后发现,大量主要成分主要集中在前
个坐标轴中,而剩余的坐标轴所包含的数据所表示的信息量不大,没有保留的价值。因此,前
个坐标轴所张成的空间就是所要寻找的投影空间,也就是特征空间。
3.PCA数学推导
沿用上一节中的要求:方差要大,协方差要小。发现数据的协方差矩阵恰好能够包含这两个数据:对角线上的数据点是数据的方差,而其余数据则是协方差。如果需要寻找特征空间,只要对协方差矩阵进行特征分解即可,得到的特征向量矩阵,就是我们所需要的空间。对此,进行相关数学推导。
若训练集,含有
个样本,每个样本的维度为
,即
1.中心化
求每一组样本的平均值,各组样本再减去相应的平均值。中心化后有:
2.计算协方差矩阵
将 构成的协方差矩阵记为
,得到协方差矩阵
:
3.计算协方差矩阵的特征值以及特征向量矩阵
对协方差矩阵进行特征分解得到特征值矩阵
及其特征向量矩阵
:
4.特征值保留
对特征值排序,取前个特征值构成相对应的特征向量矩阵
:
5.空间映射
特征向量矩阵 中的每一个列向量张成的空间就是特征空间,将原始数据映射到该空间中实现降维得到降维后的数据
。
6.重建
利用特征向量进行重建得到
:
4.PCA实现(matlab)
实现流程图大致如下:
(图4-1 PCA算法实现的流程图)
代码实现借助ORL人脸库,每个图像都是,取人脸库的60%的图像作为训练集,对其进行主成分提取及重建。
代码实现图像的主成分提取:
1.预处理
clc;clear
sample_sum = zeros(112,92*400);
k = 1;
for i = 1:40
for j = 1:10
imageName=strcat('E:\pca\ORL\s',num2str(i),'\',num2str(j),'.bmp');
sample{k} = double(imread(imageName));
k = k + 1;
end
end
j = 1;
k = 1;
for j = 1:92:92*400
sample_sum(1:112,j:j + 91) = sample{k};
k = k + 1;
end
reshaped_samples = reshape(sample_sum, 112*92,400);
% 取60%作为训练数据
test_sample_index = [];
train_sample_index = [];
for i=0:39
%test_sample_index = [test_sample_index 10*i+1:10*i+4];
train_sample_index = [train_sample_index 10*i+5:10*(i+1)];
end
%test_sample = reshaped_samples(:, test_sample_index);
train_sample = reshaped_samples(:, train_sample_index);
waitfor(show_samples(train_sample))
2.中心化
% 每一行分别求均值,中心化
mean_sample = mean(train_sample, 2);
symbol_sample = (train_sample - mean_sample);
waitfor(show_samples(symbol_sample));
3.计算协方差矩阵
cov_matrix = symbol_sample * symbol_sample';
[eigen_vectors, dianogol_matrix] = eig(cov_matrix);
4.计算协方差矩阵的特征值及其特征向量,并对特征值进行从大到小的排序
% 获取特征值
eigen_values = diag(dianogol_matrix);
% 特征值排序
[sorted_eigen_values, index] = sort(eigen_values, 'descend');
% 排序后的特征值对应的特征向量
sorted_eigen_vectors = eigen_vectors(:, index);
% 所有特征脸
all_eigen_sample = sorted_eigen_vectors;
waitfor(show_samples(all_eigen_sample));
5.重建
single_sample = symbol_sample(:,1);
subplot(2, 4, 1);
show_sample(single_sample + mean_sample);
title('原图');
index = 2;
for i=30:30:210 %选取不同的特征值
% 取出相应数量特征脸
eigen_samples = all_eigen_sample(:,1:i);
% 重建人脸并显示
rebuild_samples = eigen_samples * (eigen_samples' * single_sample) + mean_sample;
subplot(2, 4, index);
index = index + 1;
fig = show_sample(rebuild_samples);
title(['特征维度i=',num2str(i)]);
if (i == 200)
waitfor(fig);
end
end
5.结果分析
上一节步骤4中得到的特征脸:
(图5-1 测试集中任取的8张特征脸)
步骤5结果:
(图5-2 特征维度为30,60,90,120,150,180,210的重建效果)
从上面重建图像不难看出特征维度越大,图像的重建效果越好。当特征维度为90时人脸大致结构已经明显,当特征维度取190时人脸细节已经完全体现。这一结果再次说明:图像数据冗余大。因此可以借助PCA算法进行图像压缩。
注:图2-1转载于Stack Overflow的一篇文章中的图片,具体链接弄丢了。