如何使用通过 PCA 获得的特征向量来重新投影我的数据?

How to use eigenvectors obtained through PCA to reproject my data?

我正在对 100 张图像使用 PCA。我的训练数据是 442368x100 double 矩阵。 442368 是特征,100 是图像数量。这是我寻找特征向量的代码。

[ rows, cols] = size(training);
maxVec=rows;
maxVec=min(maxVec,rows);
train_mean=mean(training,2);
A=training-train_mean*ones(1,cols);
A=A'*A;
[evec,eval]=eig(A);
[eval ind]  =  sort(-1*diag(eval));
evec= evec(:, ind(1:100));

现在 evec 是一个 100x100 double 阶的特征向量矩阵,现在我已经对 100 个特征向量进行了排序。

问题:

现在,如果我想使用上面计算的特征向量转换我的测试数据,那么我该如何使用这些特征向量?我的测试数据是 442368x50 double 但我的特征向量矩阵是 100x100 double。内部矩阵尺寸不一致。如何找到我的测试数据和特征向量矩阵的点积?

你所做的本质上是 dimensionality reduction. You currently have the top 100 eigenvectors that determine the basis vectors that retain the largest variance in your data. What you want to do now is to project your test data onto these same basis vectors. BTW, you do have an error with your covariance matrix calculation. This is performed on a per feature basis but you are performing this on a per image basis.... so that's not correct. You have to swap the order of the transpose in your calculation. You also must divide by the total number of examples minus 1 to complete the calculation and produce an unbiased estimator:

A = (1/(cols-1))*(A*A.');

先转置 A 然后相乘假定每一列都是一个特征,但对您而言并非如此。如果你还记得降维,我们目前有一个特征向量矩阵,其中每一列都是一个特征向量。如果您想最终执行归约,只需将数据矩阵与特征向量矩阵相乘即可​​。请务必注意,此矩阵中特征向量的顺序是包含可由您的数据解释的最大方差的基向量首先出现。这就是为什么对特征值进行排序的原因,因为具有最大特征值的特征向量体现了这个属性。但是,此操作假定每个 都是一个特征,并且您的数据矩阵是这样的,每个 都是一个特征。如果您想对原始训练数据进行重建,则需要在执行此乘法之前转置减去均值的数据。但是,这将使每个示例连续。从您的代码中,每个 column 都是一个示例,因此您可以转置特征向量矩阵:

% Assuming you did (1/(cols-1))*(A*A.') to compute the eigenvectors
Atrain = training - train_mean*ones(1, cols);
Areconstruct = evec.' * Atrain;

Areconstruct 将包含重建数据,其中每一列都是对应的重新投影示例。我还需要存储均值减去特征矩阵,因为您的代码用协方差矩阵覆盖了它。如果你想在你的测试数据上执行这个重投影,你 必须 意味着减去从你的训练数据计算的特征,然后应用上面的乘法。假设您的数据存储在 test_data 中,只需执行以下操作:

cols_test = size(test_data, 2);
B = test_data - train_mean*ones(1, cols_test);
Breconstruct = evec.' * B;

Breconstruct 包含重新投影到基向量上的数据,现在将成为一个 100 x 50 矩阵,其中每一列都是来自测试数据的重新投影示例。


一句警告

此代码可能 运行 非常慢,或者最坏的情况下根本不会 运行,因为您的协方差矩阵非常大。强烈建议您在尝试降维之前尽可能减少特征总数 a priori。正如您在评论中所述,每个示例只是图像的展开版本作为长矢量,因此请尝试将图像的大小调整为易于管理的大小。此外,通常习惯在使用之前对调整大小的图像进行低通滤波(例如高斯模糊),因为它可以防止混叠。

此外,请查看我稍后在此 post 中关于使用奇异值分解的建议。它应该比使用协方差矩阵的特征向量更快。


你能让你的代码更有效率吗?

我会通过使用 bsxfun and also you can use sort with the descend flag 改进此代码,这样您就不必在排序之前将您的值乘以 -1 来按降序排列索引。 bsxfun 允许您有效地减去您的特征,而无需执行重复操作,即对您拥有的尽可能多的示例重复每个特征的平均值(即使用 ones(1, cols))。

具体来说:

[ rows, cols] = size(training);
maxVec=rows;
maxVec=min(maxVec,rows);
train_mean=mean(training,2);
A = bsxfun(@minus, training, train_mean); % Change
%A=training-train_mean*ones(1,cols); 
Acov = (1/(cols-1))*(A*A.'); % Change - correct formula
[evec,eval]=eig(Acov);
%[eval ind]  =  sort(-1*diag(eval));
[eval, ind]  =  sort(diag(eval), 'descend'); % Change
evec= evec(:, ind(1:100));

最后是你的测试数据:

B = bsxfun(@minus, test_data, train_mean);
Breconstruct = evec.' * B;

忠告 - 使用 SVD

众所周知,使用特征向量进行降维是不稳定的 - 特别是在计算高维数据(例如您拥有的数据)的特征向量时。建议您改用 Singular Value Decomposition (SVD) 框架来执行此操作。您可以查看此交叉验证 post 关于协方差矩阵的特征向量与使用 SVD 执行 PCA 之间的关系:

https://stats.stackexchange.com/questions/134282/relationship-between-svd-and-pca-how-to-use-svd-to-perform-pca

因此,在协方差矩阵上计算 SVD,V 的列是执行计算所需的特征向量。 SVD 的额外好处是特征向量 已经根据它们的方差排序 因此 V 的第一列将是指向方差最大方向的基向量.因此,您不需要像对特征向量那样进行任何排序。

因此,您可以将其与 SVD 一起使用:

Acov = (1/(cols-1))*(A*A.'); 
[U,S,V] = svd(Acov);
Areconstruct = V(:, 1:100).' * A;

对于您的测试数据:

B = bsxfun(@minus, test_data, train_mean);
Breconstruct = V(:, 1:100).' * B;

进一步阅读

你可以看看我的 post 关于使用协方差矩阵中的特征向量和特征值进行降维的方法,来自我的回答:

它还简要概述了为什么要执行此操作以执行 PCA 或降维。但是,我强烈建议您使用 SVD 来做您需要的事情。它比使用协方差矩阵的特征向量更快更稳定。