2015-11-09 32 views
6

Sto tentando di applicare PCA su una matrice sparsa enorme, nel seguente collegamento si dice che la PPA randomizzata di sklearn può gestire la matrice sparsa del formato sparse scipy. Apply PCA on very large sparse matrixEsecuzione di PCA su una matrice sparsa di grandi dimensioni utilizzando sklearn

Tuttavia, ottengo sempre l'errore. Qualcuno può far notare quello che sto facendo male.

matrice Input 'X_train' contiene i numeri in 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> 

che sto cercando di fare:

>>>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. 

se provo a convertire in matrice densa, penso di essere la memoria .

>>> 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 
+0

Hai visto questa risposta nella domanda che hai collegato? http://stackoverflow.com/a/10721425/2272172 – cel

+0

sì, ma voglio sapere se c'è un modo per applicare PCA su una matrice sparsa enorme (se possibile usando python e sklearn) – khassan

+0

Quindi hai già usato 'TruncatedSVD' e non ha funzionato? Se è così, per favore documentalo anche nella tua domanda. – cel

risposta

6

A causa della natura della PCA, anche se l'ingresso è una matrice sparsa, l'uscita non lo è. È possibile controllare con un esempio veloce:

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

Crea una matrice sparsa casuale con 0,01% dei suoi dati come non-zero.

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

Applicare PCA ad esso:

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

Ora, controllare i risultati:

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

che suggerisce che 95000 delle voci sono diverso da zero, tuttavia,

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

99481 elementi sono vicino a 0 (<1e-15), ma non0.

Il che significa, in breve, che per un PCA, anche se l'input è una matrice sparsa, l'output non lo è. Quindi, se provi ad estrarre 100.000.000 (1e8) componenti dalla tua matrice, ti ritroverai con una matrice densa 1e8 x n_features (nel tuo esempio 1e8 x 1617899), che ovviamente non può essere conservata in memoria.

io non sono uno statistico esperto, ma credo che non esiste attualmente alcuna workaraound per questo utilizzo scikit-learn, come non è un problema di implementazione scikit-learn di, è solo la definizione matematica della loro Sparse PCA (mediante di sparse SVD) che rende il risultato denso.

L'unica soluzione alternativa che potrebbe funzionare per te è iniziare da una piccola quantità di componenti e aumentarla finché non si ottiene un equilibrio tra i dati che è possibile conservare in memoria e la percentuale dei dati spiegati (che puoi calcolare come segue):

>>> clf.explained_variance_ratio_.sum() 
+0

Vedo, sono stato in grado di diminuire il numero di funzionalità da 1.6M a 500 (quanto basta per adattarsi alla memoria). Sembra che sia impossibile eseguire SVD su una matrice enorme a meno che non si abbia una RAM molto grande. – khassan