Matlab - 如何在大数据集上计算PCA

5
我想对一个庞大的点数据集进行PCA分析。更具体地说,我的dataPoints大小为[329150 132],其中328150是数据点的数量,132是特征数量。我想提取特征向量及其对应的特征值,以便进行PCA重建。但是,当我使用princomp函数(即[eigenVectors projectedData eigenValues] = princomp(dataPoints);)时,出现以下错误: Possible Duplicate:
MATLAB is running out of memory but it should not be
>> [eigenVectors projectedData eigenValues] = princomp(pointsData);
Error using svd
Out of memory. Type HELP MEMORY for your options.

Error in princomp (line 86)
[U,sigma,coeff] = svd(x0,econFlag); % put in 1/sqrt(n-1) later

然而,如果我使用较小的数据集,我就没有问题。

我该如何在Matlab上对整个数据集执行PCA?有人遇到过这个问题吗?

编辑

我已经修改了princomp函数,尝试使用svds替代svd,但是,我仍然得到几乎相同的错误。我将错误放在下面:

Error using horzcat
Out of memory. Type HELP MEMORY for your options.

Error in svds (line 65)
B = [sparse(m,m) A; A' sparse(n,n)];

Error in princomp (line 86)
[U,sigma,coeff] = svds(x0,econFlag); % put in 1/sqrt(n-1) later

你的进展如何?我想知道这些答案是否有助于解决你的问题? - petrichor
4个回答

5

基于特征值分解的解决方案

您可以像@david所说的那样,首先在X'X上计算PCA。具体来说,请参见以下脚本:

sz = [329150 132];
X = rand(sz);

[V D] = eig(X.' * X);

实际上,V保存了右奇异向量,并且如果将数据向量放在行中,则保存了主向量。特征值D是每个方向上的方差。奇异向量(标准差)计算为方差的平方根:
S = sqrt(D);

然后,使用公式X = USV'计算左奇异向量U。请注意,如果您的数据向量在列中,则U指代主成分。
U = X*V*S^(-1);

让我们重构原始数据矩阵并查看L2重构误差:
X2 = U*S*V';
L2ReconstructionError = norm(X(:)-X2(:))

它几乎是零:

L2ReconstructionError =
  6.5143e-012

如果您的数据向量在列中,并且希望将数据转换为特征空间系数,则应执行 U.'*X
这段代码片段在我的64位桌面上大约需要3秒钟。
基于随机PCA的解决方案
或者,您可以使用基于随机PCA的更快的近似方法。请参见 Cross Validated 中我的答案。您可以直接计算fsvd并获取UV,而不是使用eig
如果数据大小太大,您可以采用随机PCA。但是,我认为先前的方法已足够处理您给出的大小。

为了澄清,应该是“奇异值(singular values)”,它们是标准差吗? - Shadow

1

我猜你有一个巨大的数据集。你不需要所有的svd系数。在这种情况下,使用svds而不是svd

直接从Matlab帮助中获取:

 s = svds(A,k) computes the k largest singular values and associated singular vectors of matrix A.

从您的问题中,我了解到您不直接调用svd。但是您可以看一下princomp(它是可编辑的!)并更改调用它的行。

0

你可能需要在计算中计算一个n乘n的矩阵,也就是说:

329150 * 329150 * 8btyes ~ 866GB`

内存错误的原因是空间不足。似乎有一种高效的方法可以使用princomp(X, 'econ')来计算pca,我建议你尝试一下。

更多信息请参见stackoverflowmathworks


"329150" 是数据点的数量。我有 "1321" 个特征。所以基本上我要计算一个 "132乘以132" 的矩阵。 - Simon
使用132 x 132矩阵不会导致内存不足。请参考这个这个这个来计算PCA所需的内存。您可以尝试我的建议或对数据进行子采样。 - none

0

手动计算X'X(132x132),并对其进行奇异值分解。或者找到NIPALS脚本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接