了解 MATLAB 中的 PCA
Understanding PCA in MATLAB
下面两个函数有什么区别?
prepTransform.m
function [mu trmx] = prepTransform(tvec, comp_count)
% Computes transformation matrix to PCA space
% tvec - training set (one row represents one sample)
% comp_count - count of principal components in the final space
% mu - mean value of the training set
% trmx - transformation matrix to comp_count-dimensional PCA space
% this is memory-hungry version
% commented out is the version proper for Win32 environment
tic;
mu = mean(tvec);
cmx = cov(tvec);
%cmx = zeros(size(tvec,2));
%f1 = zeros(size(tvec,1), 1);
%f2 = zeros(size(tvec,1), 1);
%for i=1:size(tvec,2)
% f1(:,1) = tvec(:,i) - repmat(mu(i), size(tvec,1), 1);
% cmx(i, i) = f1' * f1;
% for j=i+1:size(tvec,2)
% f2(:,1) = tvec(:,j) - repmat(mu(j), size(tvec,1), 1);
% cmx(i, j) = f1' * f2;
% cmx(j, i) = cmx(i, j);
% end
%end
%cmx = cmx / (size(tvec,1)-1);
toc
[evec eval] = eig(cmx);
eval = sum(eval);
[eval evid] = sort(eval, 'descend');
evec = evec(:, evid(1:size(eval,2)));
% save 'nist_mu.mat' mu
% save 'nist_cov.mat' evec
trmx = evec(:, 1:comp_count);
pcaTransform.m
function [pcaSet] = pcaTransform(tvec, mu, trmx)
% tvec - matrix containing vectors to be transformed
% mu - mean value of the training set
% trmx - pca transformation matrix
% pcaSet - output set transforrmed to PCA space
pcaSet = tvec - repmat(mu, size(tvec,1), 1);
%pcaSet = zeros(size(tvec));
%for i=1:size(tvec,1)
% pcaSet(i,:) = tvec(i,:) - mu;
%end
pcaSet = pcaSet * trmx;
哪个在做PCA?
如果一个人在做 PCA,另一个人在做什么?
第一个函数 prepTransform
实际上是对您的训练数据执行 PCA,您在其中确定新轴以将数据表示到较低维度 space。它所做的是找到数据的协方差矩阵的特征向量,然后对特征向量进行排序,使得具有最大特征值的特征向量出现在特征向量矩阵的第一列 evec
和具有最小特征值的特征向量出现在最后一列。此函数的重要之处在于,您可以通过保留 evec
的前 N
列来定义要将数据减少到多少维度,这将允许您将数据减少到 N
维度。丢弃其他列并仅保留第一个 N
是代码中设置为 trmx
的内容。变量 N
由 prepTransform
函数中的 prep_count
变量定义。
第二个函数 pcaTransform
最终将定义在与训练数据相同的域中但不一定是训练数据本身(如果您愿意也可以)的数据转换到较低维度 space 由协方差矩阵的特征向量定义。要最终执行降维,或众所周知的 dimensionality reduction,您只需将训练数据从其均值中减去每个特征,然后将训练数据乘以矩阵 trmx
。请注意,prepTransform
输出向量 mu
中每个特征的平均值很重要,以便在您最终调用 pcaTransform
时减去数据。
如何使用这些功能
要有效地使用这些函数,首先要确定 trmx
矩阵,其中包含数据的 主要成分,方法是首先定义要减少的维数数据以及存储在 mu
:
中的每个特征的平均值
N = 2; % Reduce down to two dimensions for example
[mu, trmx] = prepTransform(tvec, N);
接下来,您最终可以对定义在与 tvec
相同的域(如果您愿意,甚至可以是 tvec
,但不一定如此)的数据执行降维,方法是:
pcaSet = pcaTransform(tvec, mu, trmx);
就词汇而言,pcaSet
包含数据的 主要分数 ,这是用于将数据转换为低维 space.
如果我能推荐一些东西...
已知通过特征向量方法寻找 PCA 是不稳定的。我强烈建议您在协方差矩阵上使用 Singular Value Decomposition via svd
,其中结果的 V
矩阵已经为您提供了与主成分相对应的特征向量:
mu = mean(tvec, 1);
[~,~,V] = svd(cov(tvec));
然后通过取每个特征的平均减去数据并乘以 V
矩阵来执行转换,一旦您子集化并获取 V
的前 N
列:
N = 2;
X = bsxfun(@minus, tvec, mu);
pcaSet = X*V(:, 1:N);
X
是平均减去数据,它执行与 pcaSet = tvec - repmat(mu, size(tvec,1), 1);
相同的操作,但您没有明确地在每个训练示例上复制平均向量,而是让 bsxfun
这样做为你内部。但是,利用 MATLAB R2016b,无需显式调用 bsxfun
:
即可完成此重复
X = tvec - mu;
进一步阅读
如果您完全想理解所编写的代码及其背后的理论,我推荐以下两本 Stack Overflow post我写的关于该主题的文章:
第一个 post 介绍了您提供的代码,它使用特征向量方法执行 PCA。第二个 post 涉及您如何在答案末尾使用 SVD 来做到这一点。我在这里写的这个答案是上面两个 post 的混合。
下面两个函数有什么区别?
prepTransform.m
function [mu trmx] = prepTransform(tvec, comp_count)
% Computes transformation matrix to PCA space
% tvec - training set (one row represents one sample)
% comp_count - count of principal components in the final space
% mu - mean value of the training set
% trmx - transformation matrix to comp_count-dimensional PCA space
% this is memory-hungry version
% commented out is the version proper for Win32 environment
tic;
mu = mean(tvec);
cmx = cov(tvec);
%cmx = zeros(size(tvec,2));
%f1 = zeros(size(tvec,1), 1);
%f2 = zeros(size(tvec,1), 1);
%for i=1:size(tvec,2)
% f1(:,1) = tvec(:,i) - repmat(mu(i), size(tvec,1), 1);
% cmx(i, i) = f1' * f1;
% for j=i+1:size(tvec,2)
% f2(:,1) = tvec(:,j) - repmat(mu(j), size(tvec,1), 1);
% cmx(i, j) = f1' * f2;
% cmx(j, i) = cmx(i, j);
% end
%end
%cmx = cmx / (size(tvec,1)-1);
toc
[evec eval] = eig(cmx);
eval = sum(eval);
[eval evid] = sort(eval, 'descend');
evec = evec(:, evid(1:size(eval,2)));
% save 'nist_mu.mat' mu
% save 'nist_cov.mat' evec
trmx = evec(:, 1:comp_count);
pcaTransform.m
function [pcaSet] = pcaTransform(tvec, mu, trmx)
% tvec - matrix containing vectors to be transformed
% mu - mean value of the training set
% trmx - pca transformation matrix
% pcaSet - output set transforrmed to PCA space
pcaSet = tvec - repmat(mu, size(tvec,1), 1);
%pcaSet = zeros(size(tvec));
%for i=1:size(tvec,1)
% pcaSet(i,:) = tvec(i,:) - mu;
%end
pcaSet = pcaSet * trmx;
哪个在做PCA?
如果一个人在做 PCA,另一个人在做什么?
第一个函数 prepTransform
实际上是对您的训练数据执行 PCA,您在其中确定新轴以将数据表示到较低维度 space。它所做的是找到数据的协方差矩阵的特征向量,然后对特征向量进行排序,使得具有最大特征值的特征向量出现在特征向量矩阵的第一列 evec
和具有最小特征值的特征向量出现在最后一列。此函数的重要之处在于,您可以通过保留 evec
的前 N
列来定义要将数据减少到多少维度,这将允许您将数据减少到 N
维度。丢弃其他列并仅保留第一个 N
是代码中设置为 trmx
的内容。变量 N
由 prepTransform
函数中的 prep_count
变量定义。
第二个函数 pcaTransform
最终将定义在与训练数据相同的域中但不一定是训练数据本身(如果您愿意也可以)的数据转换到较低维度 space 由协方差矩阵的特征向量定义。要最终执行降维,或众所周知的 dimensionality reduction,您只需将训练数据从其均值中减去每个特征,然后将训练数据乘以矩阵 trmx
。请注意,prepTransform
输出向量 mu
中每个特征的平均值很重要,以便在您最终调用 pcaTransform
时减去数据。
如何使用这些功能
要有效地使用这些函数,首先要确定 trmx
矩阵,其中包含数据的 主要成分,方法是首先定义要减少的维数数据以及存储在 mu
:
N = 2; % Reduce down to two dimensions for example
[mu, trmx] = prepTransform(tvec, N);
接下来,您最终可以对定义在与 tvec
相同的域(如果您愿意,甚至可以是 tvec
,但不一定如此)的数据执行降维,方法是:
pcaSet = pcaTransform(tvec, mu, trmx);
就词汇而言,pcaSet
包含数据的 主要分数 ,这是用于将数据转换为低维 space.
如果我能推荐一些东西...
已知通过特征向量方法寻找 PCA 是不稳定的。我强烈建议您在协方差矩阵上使用 Singular Value Decomposition via svd
,其中结果的 V
矩阵已经为您提供了与主成分相对应的特征向量:
mu = mean(tvec, 1);
[~,~,V] = svd(cov(tvec));
然后通过取每个特征的平均减去数据并乘以 V
矩阵来执行转换,一旦您子集化并获取 V
的前 N
列:
N = 2;
X = bsxfun(@minus, tvec, mu);
pcaSet = X*V(:, 1:N);
X
是平均减去数据,它执行与 pcaSet = tvec - repmat(mu, size(tvec,1), 1);
相同的操作,但您没有明确地在每个训练示例上复制平均向量,而是让 bsxfun
这样做为你内部。但是,利用 MATLAB R2016b,无需显式调用 bsxfun
:
X = tvec - mu;
进一步阅读
如果您完全想理解所编写的代码及其背后的理论,我推荐以下两本 Stack Overflow post我写的关于该主题的文章:
第一个 post 介绍了您提供的代码,它使用特征向量方法执行 PCA。第二个 post 涉及您如何在答案末尾使用 SVD 来做到这一点。我在这里写的这个答案是上面两个 post 的混合。