私は巨大な疎行列にPCAを適用しようとしています。次のリンクでは、sklearnのrandomizedPCAが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
PCAの性質上、入力がスパース行列であっても、出力はそうではありません。簡単な例で確認できます:
>>> 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
)に近いが、not0
。
つまり、PCAの場合、入力がスパース行列であっても、出力はそうではありません。したがって、マトリックスから100,000,000(1e8
)コンポーネントを抽出しようとすると、最終的に1e8 x n_features
(この例では1e8 x 1617899
)の密なマトリックスになります。 tメモリに保持されます。
私は専門家の統計学者ではありませんが、scikit-learnの実装の問題ではなく、sparse PCAの数学的定義にすぎないため(sparse SVDによる)、現在、scikit-learnを使用したこの問題に対する対処法はないと考えています。結果は密になります。
うまくいくかもしれない唯一の回避策は、少量のコンポーネントから始めて、メモリに保持できるデータと説明されるデータの割合(これは次のように計算します):
>>> clf.explained_variance_ratio_.sum()
PCA(X)はSVD(X-mean(X))です。 Xが疎行列であっても、X-mean(X)は常に密行列です。したがって、スパース行列のランダム化されたSVDのように、ランダム化されたSVD(TruncatedSVD)は効率的ではありません。ただし、評価の遅れ
遅延(X-平均(X))
疎行列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