J'essaie d'appliquer PCA sur une énorme matrice clairsemée, dans le lien suivant, il est dit que le PCA randomisé de sklearn peut gérer une matrice clairsemée de format scipy clairsemé. Appliquer l'APC sur une très grande matrice clairsemée
Cependant, je reçois toujours une erreur. Quelqu'un peut-il indiquer ce que je fais mal?.
La matrice d'entrée 'X_train' contient des nombres dans 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>
J'essaie de faire:
>>>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.
si j'essaie de convertir en matrice dense, je pense que je suis à court de mémoire.
>>> 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
En raison de la nature de l'ACP, même si l'entrée est une matrice clairsemée, la sortie ne l'est pas. Vous pouvez le vérifier avec un exemple rapide:
>>> from sklearn.decomposition import TruncatedSVD
>>> from scipy import sparse as sp
Créez une matrice clairsemée aléatoire avec 0,01% de ses données sous forme de zéros.
>>> X = sp.Rand(1000, 1000, density=0.0001)
Appliquez-y PCA:
>>> clf = TruncatedSVD(100)
>>> Xpca = clf.fit_transform(X)
Maintenant, vérifiez les résultats:
>>> type(X)
scipy.sparse.coo.coo_matrix
>>> type(Xpca)
numpy.ndarray
>>> print np.count_nonzero(Xpca), Xpca.size
95000, 100000
ce qui suggère que 95000 des entrées sont non nulles, cependant,
>>> np.isclose(Xpca, 0, atol=1e-15).sum(), Xpca.size
99481, 100000
99481 éléments sont proches de 0
(<1e-15
), mais pas0
.
Ce qui signifie, en bref, que pour un PCA, même si l'entrée est une matrice clairsemée, la sortie ne l'est pas. Ainsi, si vous essayez d'extraire 100 000 000 (1e8
) composants de votre matrice, vous vous retrouverez avec un 1e8 x n_features
(dans votre exemple 1e8 x 1617899
) matrice dense, qui bien sûr, ne peut pas être gardée en mémoire.
Je ne suis pas un statisticien expert, mais je crois qu'il n'y a actuellement aucune solution de contournement pour cela en utilisant scikit-learn, car ce n'est pas un problème de mise en œuvre de scikit-learn, c'est juste la définition mathématique de leur PCA clairsemée (au moyen de SVD clairsemée) ce qui rend le résultat dense.
La seule solution de contournement qui pourrait fonctionner pour vous consiste à partir d'une petite quantité de composants et à l'augmenter jusqu'à ce que vous obteniez un équilibre entre les données que vous pouvez conserver en mémoire et le pourcentage des données expliquées (que vous pouvez calculer comme suit):
>>> clf.explained_variance_ratio_.sum()
PCA (X) est SVD (X-mean (X)). Même si X est une matrice clairsemée, la moyenne X (X) est toujours une matrice dense. Ainsi, la SVD randomisée (TruncatedSVD) n'est pas efficace comme la SVD randomisée d'une matrice clairsemée. Cependant, une évaluation retardée
retard (X-moyenne (X))
peut éviter d'étendre la matrice clairsemée X à la matrice dense X-moyenne (X). L'évaluation différée permet une ACP efficace d'une matrice clairsemée en utilisant la SVD randomisée.
Ce mécanisme est implémenté dans mon package:
https://github.com/niitsuma/delayedsparse/
Vous pouvez voir le code de l'APC en utilisant ce mécanisme: https://github.com/niitsuma/delayedsparse/blob/master/delayedsparse/pca.py
Les comparaisons de performances avec les méthodes existantes montrent que ce mécanisme réduit considérablement la taille de la mémoire requise: https://github.com/niitsuma/delayedsparse/blob/master/demo-pca.sh
Une description plus détaillée de cette technique peut être trouvée dans mon brevet: https://patentscope2.wipo.int/search/ja/detail.jsf?docId=JP225380312