当前位置: 代码迷 >> 综合 >> 04-0002 PCA算法
  详细解决方案

04-0002 PCA算法

热度:57   发布时间:2023-11-24 02:01:48.0

PCA算法

  • 1.PCA算法简介
  • 2.PCA个人理解
  • 3.PCA算法推导
    • 3.1逆向推导
    • 3.2正向思维
  • 4.PCA算法流程
  • 5.PCA算法代码
  • 6.PCA算法数据
  • 7.PCA算法应用
    • 7.1PCA数据降维
    • 7.2PCA图像压缩
      • 7.2.1理解
      • 7.2.2代码

1.PCA算法简介

!!!插入代码的时候不要空行!!!

主成分分析(Principal Component Analysis,PCA), 是一种统计方法。通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。

在实际课题中,为了全面分析问题,往往提出很多与此有关的变量(或因素),因为每个变量都在不同程度上反映这个课题的某些信息。

主成分分析首先是由K.皮尔森(Karl Pearson)对非随机变量引入的,尔后H.霍特林将此方法推广到随机向量的情形。信息的大小通常用离差平方和或方差来衡量。

以上信息来自于百度,直接搬过来的,目的是为了有一个比较官方的解释,让整个文章看起来哄哄的~

2.PCA个人理解

!!!插入代码的时候不要空行!!!

此处是个人的理解:
关于PCA,是一种数据降维的方法,不如说是一种数据处理的方法,或者说是一种数据处理的思想,或者说是一个数据空间转换的函数···
一般而言,处理数据的时候,通常是一个m*n的矩阵,其中m是行,是样本的个数,n是列,是数据的维数,也就是说在当前的这个空间,每一个样本(每一条数据)中包含n个值,相当于一个n维坐标系,通过一个(x1,x2,···,xn)的坐标来表示一条数据。[这是对于原始数据的理解]
跳转一下,解释另一个东西。设想,在一个三维的直角坐标系里面有一个从原点出发的向量A。对于A,有着如下描述:A向量与x-y平面的夹角特别特别 特别 小。
上面这句话什么意思?就是说A向量在x轴y轴的分量都是不可以忽略的,在z轴的分量很小很小,以至于可以忽略不计。直观的说,我身为三维空间中的生物(我也不知道自己是几维的 ),直接观察到的A向量,与从z轴方向观察到的A向量很像,他们具有极高的拟合度。
显然,这个时候为了方便与我们处理数据,就会很自然的想到,舍弃z轴,因为那个轴上的分量很小,很不重要。此时,就能够用一个二维的坐标去表示一个三维的数据。
再想,倘若是A向量与z轴的夹角很小。也就是说在x轴y轴上的投影很小,那我们就可以直接把另外两轴丢弃,然后把z轴作为直角坐标轴,就可以近似的表示A向量。
也可以扩展一下想,倘若是更高维度的生物来看待这个问题,他们就能够从四维五维或者是更高维度,来观察这些数据。
所以,倘若我们的数据是可以在某未知维度的直角坐标系下表示出来,对于每一个样本,我们就知道它在哪个轴上的分量比较小,哪个轴可以去掉。
最终我们的目的:让这些数据可以表示出来,绘制在图中,一维的图,二维的图,或者是三维的图。我们可以画的也就这三个维度,物质决定意识,没有达到更高的维度很难画出高维度的图,所以对于这个有着n个维度的数据集,我们只能忽略掉很多维度(轴),取其中我们可以绘制的几个维度来对数据进行分析处理。
此时,舍弃维度的过程也就是降维。
预先假设了这种理想化的数据,称其为理想数据,理想数据是容易处理的,每个轴之间都互相不会干扰,相关性为零。
而原来的数据称其为原始数据,轴与轴之间存在一定的相关性,会互相影响,这种数据是不容易处理的。
协方差用来表示相关性,协方差矩阵是每两个维度之间相关性构成的矩阵。
所以说,理想数据就是最终的目的,而原始的数据是出发点,此时的数据处理转化成了寻找理想数据与原始数据之间关系的一个问题。也就是找到是的处理后的数据的协方差矩阵只有对角线上有值(只有自身跟自身有相关性),其他位置都是零(该维度与其他的维度之间没有相关性,不相关)。
好,这样的思路我很满意~

3.PCA算法推导

!!!插入代码的时候不要空行!!!

3.1逆向推导

设原始数据矩阵X的协方差矩阵为C,P是一组基按行组成的矩阵,设Y=PX,则Y为X对P做基变换后的数据。设Y的协方差矩阵为D,则可以进行如下推导:
在这里插入图片描述

观察式子右侧的结果,容易联想的是矩阵对角化的过程,但是也有一些不同,对角化的时候,C的左侧是转置,所以这个时候要试图寻找这个P与C对角化时ETE^TET之间有什么关系。

矩阵对角化时有如下的公式:
在这里插入图片描述

通过正交矩阵转置与逆相等的概念等,可以推知:
在这里插入图片描述

这样就能够解释,为什么我们要求原始数据协方差矩阵的特征值与特征向量,为什么我们可以直接拿着原始数据协方差矩阵的特征向量去乘原始数据,就能够得到理想数据。

3.2正向思维

关于这样讲解PCA的链接有好多,可以去度娘直接搜索。这种思路的目的是为了使得数据在某一个轴上的投影方差最大,问题的目的是求方差最大时数据之间的关系,手段是拉格朗日常数法(通过求偏导求解最值的一种方法)。
不求甚解,知道运算过程之后,总是会知道这样算是为什么,能够很容易的看懂推导的过程。上面你想思维也只是一部分,最后理想数据等于什么,两种方法得到的结果是一样的。

4.PCA算法流程

!!!插入代码的时候不要空行!!!

  1. 对原始数据A进行标准化(归一化)处理,得到矩阵B。[A、B都是m*n的]
  2. 求矩阵B的协方差矩阵Cov。[Cov是n*n的]
  3. 求协方差矩阵Cov的特征值e,特征向量v。[e是n1的,v是nn的]
  4. 将e排序,按照排好序的e,对v进行排序。[没有改变维度]
  5. 用归一化矩阵B乘上特征向量矩阵v,得到新的数据矩阵New。[New是mn的,mnnn得到m*n的矩阵]
  6. 取New的前n列进行绘制图表。[一般是取前两列或者三列,再多画不来]

说明一下即可,主要是算法过程中数据矩阵形式的变化,这也是代码实现时候的一大困扰。

5.PCA算法代码

!!!插入代码的时候不要空行!!!

clc;
oridata=load('iris.csv');
data=oridata(:,2:5);
coldata=oridata(:,1);
zdata=zscore(data);%数据标准化
data_cov=cov(zdata);%协方差矩阵
[data_v,data_d]=eig(data_cov);%特征值特征向量
d=diag(data_d);
eig1=sort(d,'descend');%按照特征值进行排序
v=fliplr(data_v);%根据排序后的特征值,得到一个特征向量的排序
new=zdata*v(:,1:2);%选取第一主成分以及第二主成分分别作为x,y轴
newdata=[coldata,new];
[a b]=size(newdata)
figure()
for i=1:ahold onif newdata(i,1)==0plot(newdata(i,2),newdata(i,3),'r.','markersize',15);elseif newdata(i,1)==1plot(newdata(i,2),newdata(i,3),'go','markersize',5);elseif newdata(i,1)==2plot(newdata(i,2),newdata(i,3),'b*','markersize',5);end
end

把下面数据保存成MATLAB可读取的文件,把上述代码保存为,m的文件,拿到MATLAB里直接运行即可。最后绘制的时候,一个点一个点的绘制,判断是第几类数据。

6.PCA算法数据

算法数据如下:
有150条,4个维度,第一列表示类别,不算在其中。
!!!插入代码的时候不要空行!!!

0 2 14 33
1 24 56 31
1 23 51 31
0 2 10 36
1 20 52 30
1 19 51 27
2 13 45 28
2 16 47 33
1 17 45 25
2 14 47 32
0 2 16 31
1 19 50 25
0 1 14 36
0 2 13 32
2 12 40 26
1 18 49 27
2 10 33 23
0 2 16 38
0 2 16 30
1 21 56 28
0 4 19 38
0 2 14 30
2 10 41 27
2 15 45 29
0 2 14 36
1 19 51 27
0 4 15 34
1 18 55 31
2 10 33 24
0 2 14 42
1 15 50 22
2 14 39 27
0 2 14 29
2 12 39 27
1 23 57 32
2 15 42 30
1 20 49 28
1 18 58 25
2 13 44 23
2 15 49 25
2 11 30 25
1 21 54 31
1 25 61 36
2 13 36 29
1 21 55 30
0 1 14 30
0 3 17 38
2 14 44 30
0 4 15 37
2 17 50 30
1 22 56 28
1 15 51 28
2 15 45 22
2 14 46 30
2 11 39 25
1 23 59 32
1 23 54 34
1 25 57 33
0 2 13 35
2 15 45 32
1 18 51 30
1 23 53 32
2 15 45 30
1 21 57 33
0 2 13 30
0 2 16 32
1 18 60 32
1 18 49 30
0 2 12 32
0 1 11 30
2 14 44 31
0 2 14 35
0 4 16 34
2 10 35 26
1 23 61 30
2 13 42 26
0 1 15 41
1 18 48 30
2 13 42 27
0 2 15 31
0 4 17 39
2 16 45 34
2 10 35 20
0 2 13 32
2 13 54 29
0 2 15 34
2 10 50 22
0 1 15 31
0 2 15 37
2 12 47 28
2 13 41 28
0 4 13 39
1 20 51 32
2 15 49 31
2 13 40 25
0 3 13 23
0 3 15 38
2 14 48 28
0 2 15 35
1 25 60 33
2 15 46 28
0 3 14 34
2 18 48 32
2 16 51 27
1 18 55 30
0 5 17 33
1 22 67 38
1 21 66 30
1 13 52 30
2 13 40 28
2 11 38 24
0 2 14 34
1 20 64 38
0 6 16 35
1 20 67 28
2 12 44 26
0 3 14 30
0 2 19 34
1 14 56 26
0 2 12 40
1 18 48 28
2 15 45 30
0 2 14 32
0 4 15 44
1 24 56 34
1 16 58 30
1 21 59 30
1 18 56 29
2 12 42 30
1 23 69 26
2 13 56 29
0 2 15 34
2 10 37 24
0 2 15 31
1 19 61 28
0 3 13 35
1 18 63 29
2 15 47 31
2 13 41 30
2 13 43 29
1 22 58 30
0 3 14 35
2 14 47 29
1 19 53 27
0 2 16 34
1 20 50 25
2 13 40 23
0 2 17 34
1 24 51 28
0 2 15 37

7.PCA算法应用

!!!插入代码的时候不要空行!!!

7.1PCA数据降维

上述即是数据降维PCA方法。

7.2PCA图像压缩

7.2.1理解

对于此处图像压缩的理解不是很深刻,自我感觉是将图片800800的,缩小成400400的进行保存,然后再将400400的图像打开,保存为800800的。这样做会变模糊,但是依旧能够从图片中获得主要信息。
图片压缩就是,利用PCA的方法提取出来图片中中的主成分(一个方块),然后再用这些方块去还原图片,主成分提取的多,图片丢失的信息就少,反正就会很模糊。

我记得有一个狗狗的表情包,有人把它分成好些小片,然后取一部分进行拼接,就可以得到好几个像素风格的相似表情包,当时只是觉得很搞笑,现在看来,那种思想就是PCA。

7.2.2代码

clc;
% 输入
In=imread('C:\Users\31386\Desktop\timg.jpg');
imR=In(:,:,1);
imG=In(:,:,2);
imB=In(:,:,3);
% In=rgb2gray(In);
% In=In(179:690,179:690);% 输入参数
num_val = 10;                                 %取前num_val个特征值
size_block = 32;                                       %取size_block*size_block块%调用函数
[outR]=PCA(imR,num_val,size_block);
[outG]=PCA(imG,num_val,size_block);
[outB]=PCA(imB,num_val,size_block);
Out(:,:,1)=outR(:,:);
Out(:,:,2)=outG(:,:);
Out(:,:,3)=outB(:,:);% 显示图像
imshow(In),title('原图')
figure,imshow(Out),title('压缩后的图像')
% figure,imshow(Out2),title('差值的图像')
% figure,imshow(Out3),title('补充的图像')
imwrite(Out,'压缩后的图像.jpg')%函数定义
% 将原图像矩阵分割成n*n的块,再转化为列矩阵,构成最终矩阵reIn
function [Out]=PCA(In,num_val,size_block)In = im2double(In);
[row rol] = size(In);
m = 0;
Data = zeros(size_block*size_block,(row/size_block)*(rol/size_block));              % 数据矩阵
for i = 1:size_block:rowfor j = 1:size_block:rolm = m+1;block = In(i:i+size_block-1,j:j+size_block-1);Data(:,m) = block(:);end
end% PCA处理
Data1 = Data - ones(size(Data,1),1)*mean(Data);             % 标准化处理
c = cov(Data1');                                     % 求矩阵协方差矩阵
[vec,val] = eig(c);                                      % 求特征值和特征向量% 按特征值降序排列
val = diag(val);                                        % 从对角线拿出特征值
[val t] = sort(val,'descend');                             % 特征值降序排列
vec = vec(:,t);                                        % 特征向量也对应改变顺序% 重构图像
vec_new = vec(:,1:num_val);                                    % 取前k个特征向量%计算所取特征值贡献率rata = val./sum(val);rata_sum = sum(rata(1:num_val));fprintf('选取%g个特征值的贡献率为:%g \n',num_val,rata_sum);   y = vec_new'* Data;                                      % 映射 由公式:y=w'*x
Data2 = vec_new * y;                                    % 重构图像
Data2 = Data2 + ones(size(vec_new, 1), 1) * mean(Data);     % 加均值
m = 0;for i = 1:size_block:rowfor j = 1:size_block:rolm = m + 1;block1 = reshape(Data2(:, m), size_block, size_block);        % 列向量块转化为方块Out(i:i+size_block-1, j:j+size_block-1) = block1; end
end
end

插入代码的时候里面不能有空行,插入完可以在其中输入空行。我昨天已经写过一遍,5000多字,最后一位插入代码的时候,有空行,什么都没了。

改变自己菜的本质,从现在开始。虽然路途坎坷,但一直坚持便可。