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

Raf*_*Mir 4 matlab image eigenvector pca dimensionality-reduction

我在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));
Run Code Online (Sandbox Code Playgroud)

现在evec是一个100x100倍的特征向量矩阵,现在我有100个特征向量排序.

问题:

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

ray*_*ica 8

你在做什么基本上是减少维数.您目前拥有前100个特征向量,用于确定保留数据中最大差异的基础向量.您现在要做的是将测试数据投影到这些相同的基础向量上.顺便说一句,您的协方差矩阵计算确实存在错误.这是基于每个功能执行的,但您是在每个图像的基础上执行此操作....所以这是不正确的.您必须在计算中交换转置的顺序.您还必须除以示例总数减1才能完成计算并生成无偏估计:

A = (1/(cols-1))*(A*A.');
Run Code Online (Sandbox Code Playgroud)

A先转置然后乘法假设每列都是一个特征,但事实并非如此.如果你从维数减少中回忆起来,我们目前有一个特征向量矩阵,其中每列是一个特征向量.如果你想最终执行缩减,它只是数据矩阵的乘法,即用特征向量矩阵减去平均值.重要的是要注意,该矩阵中的特征向量的顺序使得包含可由您的数据解释的最大方差的基矢量首先出现.这就是为什么对特征值进行排序的原因,因为具有最大特征值的特征向量体现了这个特性.但是,此操作假定每都是一个要素,并且您的数据矩阵使得每一都是一个要素.如果要对原始训练数据执行重建,则需要在进行此乘法之前转置平均减去的数据.但是,这将使每个示例连续.从您的代码中,每都是一个示例,因此您可以转换特征向量矩阵:

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

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

cols_test = size(test_data, 2);
B = test_data - train_mean*ones(1, cols_test);
Breconstruct = evec.' * B;
Run Code Online (Sandbox Code Playgroud)

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


一句警告

由于您的协方差矩阵的大小非常大,因此此代码可能会运行得很慢或最差情况根本不会运行.您减少总数的特点这是非常可取的先验努力降维之前,尽可能多地.正如您在评论中所述,每个示例都只是图像的展开版本作为长向量,因此请尝试将图像调整为可管理的大小.另外,通常习惯于在使用之前对经过调整大小的图像进行低通滤波(例如高斯模糊),因为它可以防止混叠.

另外,请查看本文后面有关使用奇异值分解的建议.它应该比使用协方差矩阵的特征向量更快.


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

我会通过使用改进的代码bsxfun,你也可以使用sortdescend标志,所以你不必-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));
Run Code Online (Sandbox Code Playgroud)

最后为您的测试数据:

B = bsxfun(@minus, test_data, train_mean);
Breconstruct = evec.' * B;
Run Code Online (Sandbox Code Playgroud)

建议 - 使用SVD

已知使用特征向量进行降维是不稳定的 - 特别是在计算高维数据的特征向量时,例如你所拥有的.建议您使用奇异值分解(SVD)框架来代替.您可以在协方差矩阵的特征向量之间的关系上查看此Cross Validated帖子,并使用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;
Run Code Online (Sandbox Code Playgroud)

对于您的测试数据:

B = bsxfun(@minus, test_data, train_mean);
Breconstruct = V(:, 1:100).' * B;
Run Code Online (Sandbox Code Playgroud)

进一步阅读

您可以使用来自我的答案的协方差矩阵中的特征向量和特征值来查看我关于降维的文章: 在数据分析中选择协方差矩阵中的最大特征值和特征向量意味着什么?

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

  • 惊人的帖子+1 (2认同)