1、问题描述

        通常情况下,特征是相关的。例如,考虑我们想要使用图像中每个像素的红色、绿色和蓝色分量来对图像进行分类(例如检测狗与猫)的情况。对红光最敏感的图像传感器也会捕获一些蓝光和绿光。

        在这里我们生成随机数据并绘制 3D 数据,然后执行主成分分析以对数据进行去相关处理,并降低特征空间的维度。

        请注意,matlab 具有执行 PCA 的优化函数:princomp()。 但是,在我们的脚本中,我们通过计算特征向量手动执行PCA,用于演示目的。

2、创建随机数据

       我们创建334个随机数据点。

clear all;
close all;
 
% 创建随机点
s = [2 2 2];  % 偏斜因子
x = randn(334,1);
y1 = normrnd(s(1).*x,1)+3;
y2 = normrnd(s(2).*x,1)+2;
y3 = normrnd(s(3).*x,1)+1;
data = [y1 y2 y3];

3、可视化3D数据

        我们首先绘制原始数据点,然后计算特征向量和特征值,之后进行特征向量的绘制。

%%%%%%%%%%%%% 绘制原始数据 %%%%%%%%%%%
% 获取数据均值的坐标
avg = mean(data);
X0=avg(1);
Y0=avg(2);
Z0=avg(3);
 
% 绘制原始数据
scatter3(data(:,1), data(:,2), data(:,3), 5, data(:,3), 'filled');
colormap(gray);
 
% 计算特征向量和特征值
covariance = cov(data);
[eigenvec, eigenval ] = eig(covariance);
 
% 获取最大特征向量的索引
largest_eigenvec = eigenvec(:, 3);
largest_eigenval = eigenval(3,3);
medium_eigenvec = eigenvec(:, 2);
medium_eigenval = eigenval(2,2);
smallest_eigenvec = eigenvec(:, 1);
smallest_eigenval = eigenval(1,1);
 
% 绘制特征向量
hold on;
quiver3(X0, Y0, Z0, largest_eigenvec(1)*sqrt(largest_eigenval), largest_eigenvec(2)*sqrt(largest_eigenval), largest_eigenvec(3)*sqrt(largest_eigenval), '-m', 'LineWidth',3);
quiver3(X0, Y0, Z0, medium_eigenvec(1)*sqrt(medium_eigenval), medium_eigenvec(2)*sqrt(medium_eigenval), medium_eigenvec(3)*sqrt(medium_eigenval), '-g', 'LineWidth',3);
quiver3(X0, Y0, Z0, smallest_eigenvec(1)*sqrt(smallest_eigenval), smallest_eigenvec(2)*sqrt(smallest_eigenval), smallest_eigenvec(3)*sqrt(smallest_eigenval), '-r', 'LineWidth',3);
hold on;
 
% 设置轴标签
hXLabel = xlabel('x');
hYLabel = ylabel('y');
hZLabel = zlabel('z');
%Xlim([-10,10]);
%Ylim([-10,10]);
%Zlim([-10,10]);
title('原始3D数据');

可视化结果,我们可以看到原始数据和特征向量

4、绘制去相关数据

        这里我们对数据进行集中、规范化,去相关,然后重新绘制。

%%%%%%%%%%%%% 集中数据 %%%%%%%%%%%
data = data-repmat(avg, size(data, 1), 1);
%%%%%%%%%%%%% 规范化数据 %%%%%%%%%%%
stdev = sqrt(diag(covariance));
data = data./repmat(stdev', size(data, 1), 1);
%%%%%%%%%%%%% 去相关数据 %%%%%%%%%%%
decorrelateddata = (data*eigenvec);
% 绘制去相关数据
figure;
scatter3(decorrelateddata(:,1), decorrelateddata(:,2), decorrelateddata(:,3), 5, decorrelateddata(:,3), 'filled');
colormap(gray);
 
% 绘制特征向量 (现在是轴 (0,0,1), (0,1,0), (1,0,0)
% 居中数据的平均值为 (0,0,0)
hold on;
quiver3(0, 0, 0, 0, 0, 1*sqrt(largest_eigenval), '-m', 'LineWidth',3);
quiver3(0, 0, 0, 0, 1*sqrt(medium_eigenval), 0, '-g', 'LineWidth',3);
quiver3(0, 0, 0, 1*sqrt(smallest_eigenval), 0, 0, '-r', 'LineWidth',3);
hold on;
 
% Set the axis labels
hXLabel = xlabel('x');
hYLabel = ylabel('y');
hZLabel = zlabel('z');
%Xlim([-5,5]);
%Ylim([-5,5]);
%Zlim([-5,5]);
title('去相关的3D数据');

 可视化的去相关数据 

5、将数据降维到2D

        在这里我们只取前两个主成分,然后可视化。

%%%%%%%%%%%%% 将数据投影到2个最大的特征向量上 %%%%%%%%%%%
eigenvec_2d=eigenvec(:,2:3);
data_2d = data*eigenvec_2d;
% Plot the 2D data
figure;
scatter(data_2d(:,1), data_2d(:,2), 5, data(:,3), 'filled');
colormap(gray);
 
% Plot the eigenvectors
hold on;
quiver(0, 0, 0*sqrt(largest_eigenval), 1*sqrt(largest_eigenval), '-m', 'LineWidth',3);
quiver(0, 0, 1*sqrt(medium_eigenval), 0*sqrt(medium_eigenval), '-g', 'LineWidth',3);
hold on;
 
% Set the axis labels
hXLabel = xlabel('x');
hYLabel = ylabel('y');
%Xlim([-5,5]);
%Ylim([-5,5]);
title('Projected 2D data');
grid on;

可视化效果如下 

 6、将数据降维到1D

        这里我们就只保留最大的,第一个特征向量

%%%%%%%%%%%%% 将数据投影到最大的特征向量上 %%%%%%%%%%%
eigenvec_1d=eigenvec(:,3);
data_1d = data*eigenvec_1d;
% Plot the 1D data
figure;
scatter(repmat(0, size(data_1d,1), 1), data_1d, 5, data(:,3), 'filled');
colormap(gray);
 
% Plot the eigenvector
hold on;
quiver(0, 0, 0*sqrt(largest_eigenval), 1*sqrt(largest_eigenval), '-m', 'LineWidth',3);
hold on;
 
% Set the axis labels
hXLabel = xlabel('x');
hYLabel = ylabel('y');
%Xlim([-5,5]);
%Ylim([-5,5]);
title('Projected 1D data');
grid on;

可视化效果如下