使用sklearn对大型稀疏矩阵执行PCA

25

我正在尝试在巨大的稀疏矩阵上应用PCA,在下面的链接中指出,sklearn的随机PCA可以处理scipy稀疏格式的稀疏矩阵。 对非常大的稀疏矩阵应用PCA

但是,我总是遇到错误。有人能指出我做错了什么吗。

输入矩阵'X_train'包含float64数字:

>>>type(X_train)
<class 'scipy.sparse.csr.csr_matrix'>
>>>X_train.shape
(2365436, 1617899)
>>>X_train.ndim 
2
>>>X_train[0]     
<1x1617899 sparse matrix of type '<type 'numpy.float64'>'
    with 81 stored elements in Compressed Sparse Row format>

我正在尝试做:

>>>from sklearn.decomposition import RandomizedPCA
>>>pca = RandomizedPCA()
>>>pca.fit(X_train)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/RT11/.pyenv/versions/2.7.9/lib/python2.7/site-packages/sklearn/decomposition/pca.py", line 567, in fit
    self._fit(check_array(X))
  File "/home/RT11/.pyenv/versions/2.7.9/lib/python2.7/site-packages/sklearn/utils/validation.py", line 334, in check_array
    copy, force_all_finite)
  File "/home/RT11/.pyenv/versions/2.7.9/lib/python2.7/site-packages/sklearn/utils/validation.py", line 239, in _ensure_sparse_format
    raise TypeError('A sparse matrix was passed, but dense '
TypeError: A sparse matrix was passed, but dense data is required. Use X.toarray() to convert to a dense numpy array.

如果我尝试转换为稠密矩阵,我认为内存会不够用。

>>> pca.fit(X_train.toarray())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/RT11/.pyenv/versions/2.7.9/lib/python2.7/site-packages/scipy/sparse/compressed.py", line 949, in toarray
    return self.tocoo(copy=False).toarray(order=order, out=out)
  File "/home/RT11/.pyenv/versions/2.7.9/lib/python2.7/site-packages/scipy/sparse/coo.py", line 274, in toarray
    B = self._process_toarray_args(order, out)
  File "/home/RT11/.pyenv/versions/2.7.9/lib/python2.7/site-packages/scipy/sparse/base.py", line 800, in _process_toarray_args
    return np.zeros(self.shape, dtype=self.dtype, order=order)
MemoryError

你在你链接的问题中看到这个答案了吗?https://dev59.com/_mgv5IYBdhLWcg3wSewf#10721425 - cel
1
是的,但我想知道是否有一种方法可以在巨大的稀疏矩阵上应用PCA(如果可能的话,使用Python和sklearn)。 - khassan
如果我设置小的n_components,例如100,TruncatedSVD可以工作,但如果我将其设置为1,000,000,则会失败。 - khassan
事实上,即使为TruncatedSVD设置n_components = 3000也会出现MemoryError。 - khassan
@cel 如果可能的话,构建整个矩阵的PCA,然后选择覆盖99%或99.99%方差的特征向量将是非常好的。 - khassan
显示剩余2条评论
2个回答

22

由于主成分分析的性质,即使输入是稀疏矩阵,输出也不是稀疏的。您可以通过一个快速的示例进行检查:

>>> from sklearn.decomposition import TruncatedSVD
>>> from scipy import sparse as sp

创建一个随机稀疏矩阵,其中0.01%的数据为非零值。

>>> X = sp.rand(1000, 1000, density=0.0001)

应用PCA进行处理:

>>> clf = TruncatedSVD(100)
>>> Xpca = clf.fit_transform(X)

现在,检查结果:

>>> type(X)
scipy.sparse.coo.coo_matrix
>>> type(Xpca)
numpy.ndarray
>>> print np.count_nonzero(Xpca), Xpca.size
95000, 100000

这表明95000个条目为非零,但是,

>>> np.isclose(Xpca, 0, atol=1e-15).sum(), Xpca.size
99481, 100000

有99481个元素接近于0(<1e-15),但不是0。

简单来说,对于PCA,即使输入是一个稀疏矩阵,输出也不是。因此,如果你尝试从你的矩阵中提取100,000,000(1e8)个组件,你最终会得到一个1e8 x n_features(在你的例子中为1e8 x 1617899)的密集矩阵,这显然是无法保存在内存中的。

我不是一个专业的统计学家,但我相信目前使用scikit-learn没有解决这个问题的方法,因为这不是scikit-learn实现的问题,而是他们的稀疏PCA的数学定义(通过稀疏SVD)使结果变成了密集型。

唯一可能适用于您的解决方法是从少量组件开始,并增加直到找到可以保留在内存中的数据和解释数据百分比之间的平衡点(可以如下计算):

>>> clf.explained_variance_ratio_.sum()

我明白了,我已经成功将特征数量从160万减少到500(刚好能够适应内存)。看起来,除非你有非常大的RAM,否则无法在巨大的矩阵上执行SVD。 - khassan
目前使用sklearn,我们可以执行 pca = PCA(0.99),其中0.99是总的“explained_variance_ratio_”。 - Ali Pardhan

7
PCA(X)是SVD(X-mean(X))。
即使X是一个稀疏矩阵,X-mean(X)始终是一个密集矩阵。因此,截断的随机SVD并不像对于稀疏矩阵的随机SVD那样高效。
然而,延迟评估可以避免将稀疏矩阵X扩展为密集矩阵X-mean(X)。延迟评估使得使用随机SVD能够高效地进行稀疏矩阵的PCA。
这个机制已经在我的软件包中实现: https://github.com/niitsuma/delayedsparse/ 你可以查看使用这个机制的PCA代码: https://github.com/niitsuma/delayedsparse/blob/master/delayedsparse/pca.py 与现有方法的性能比较表明,这种机制极大地减少了所需的内存大小: https://github.com/niitsuma/delayedsparse/blob/master/demo-pca.sh

这项技术的更详细说明可以在我的专利中找到: https://patentscope2.wipo.int/search/ja/detail.jsf?docId=JP225380312


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