我在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倍的特征向量矩阵,现在我已经排序了100个特征向量。
问题:
现在,如果我想使用上面计算的特征向量转换我的测试数据,那么我该如何使用这些特征向量?我的测试数据是442368x50 double
,但我的特征向量矩阵是100x100 double
。内部矩阵尺寸不一致。如何找到测试数据和特征向量矩阵的点积?
答案 0 :(得分:8)
你在做什么基本上是dimensionality reduction。您目前拥有前100个特征向量,用于确定保留数据中最大差异的基础向量。您现在要做的是将测试数据投影到这些相同的基础向量上。顺便说一句,您的协方差矩阵计算确实存在错误。这是在每个功能的基础上执行的,但您是在每个图片的基础上执行此操作....这样做不正确。您必须在计算中交换转置的顺序。您还必须除以示例总数减1才能完成计算并produce an unbiased estimator:
A = (1/(cols-1))*(A*A.');
首先转置A
然后乘以假定每列都是一个要素,但事实并非如此。如果你从维数减少中回忆起来,我们目前有一个特征向量矩阵,其中每列是一个特征向量。如果你想最终执行缩减,它只是数据矩阵的乘法,即用特征向量矩阵减去平均值。重要的是要注意,该矩阵中的特征向量的顺序使得包含可由您的数据解释的最大方差的基矢量首先出现。这就是为什么对特征值进行排序的原因,因为具有最大特征值的特征向量体现了这个特性。但是,此操作假定每个列都是一个要素,而您的数据矩阵是每个行都是一个要素。如果要对原始训练数据执行重建,则在进行此乘法之前,您需要转换平均减去的数据。但是,这将使每个示例连续。从您的代码中,每个列都是一个示例,因此您可以转换特征向量矩阵:
% 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
矩阵,其中每列是来自测试数据的重新投影示例。
由于您的协方差矩阵的大小非常大,因此此代码可能会运行速度非常慢或最差情况根本不运行。在尝试降低维数之前,强烈建议您尽可能减少先验的要素总数。正如您在评论中所述,每个示例都只是图像的展开版本作为长向量,因此请尝试将图像调整为可管理的大小。另外,通常习惯于在使用之前对经过调整大小的图像进行低通滤波(例如高斯模糊),因为它可以防止混叠。
另外,请查看我在本文中稍后使用奇异值分解的建议。它应该比使用协方差矩阵的特征向量更快。
我会使用bsxfun
来改进此代码,您也可以使用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;
使用特征向量进行降维已知是不稳定的 - 特别是在计算高维数据的特征向量时,例如你所拥有的。建议您使用Singular Value Decomposition(SVD)框架来代替。您可以在协方差矩阵的特征向量之间的关系上查看此Cross Validated帖子,并使用SVD执行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;
您可以使用我的答案中的协方差矩阵中的特征向量和特征值来查看我关于维数减少的帖子:What does selecting the largest eigenvalues and eigenvectors in the covariance matrix mean in data analysis?
它还简要概述了为执行PCA或减少维数而执行此操作的原因。但是,我强烈建议您使用SVD来做您需要的事情。它比使用协方差矩阵的特征向量更快更稳定。