2015-07-15 16 views
7

Ho appena provato ad utilizzare l'IncrementalPCA da sklearn.decomposition, ma ha gettato un MemoryError proprio come il PCA e il RandomizedPCA in precedenza. Il mio problema è che la matrice che sto cercando di caricare è troppo grande per adattarsi alla RAM. In questo momento è memorizzato in un database hdf5 come set di dati di forma ~ (1000000, 1000), quindi ho 1.000.000.000 di valori float32. Ho pensato che IncrementalPCA carichi i dati in batch, ma a quanto pare tenta di caricare l'intero set di dati, il che non aiuta. Come si intende utilizzare questa libreria? Il formato hdf5 è il problema?PCA incrementale su big data

from sklearn.decomposition import IncrementalPCA 
import h5py 

db = h5py.File("db.h5","r") 
data = db["data"] 
IncrementalPCA(n_components=10, batch_size=1).fit(data) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/software/anaconda/2.3.0/lib/python2.7/site-packages/sklearn/decomposition/incremental_pca.py", line 165, in fit 
    X = check_array(X, dtype=np.float) 
    File "/software/anaconda/2.3.0/lib/python2.7/site-packages/sklearn/utils/validation.py", line 337, in check_array 
    array = np.atleast_2d(array) 
    File "/software/anaconda/2.3.0/lib/python2.7/site-packages/numpy/core/shape_base.py", line 99, in atleast_2d 
    ary = asanyarray(ary) 
    File "/software/anaconda/2.3.0/lib/python2.7/site-packages/numpy/core/numeric.py", line 514, in asanyarray 
    return array(a, dtype, copy=False, order=order, subok=True) 
    File "h5py/_objects.pyx", line 54, in h5py._objects.with_phil.wrapper (-------src-dir-------/h5py/_objects.c:2458) 
    File "h5py/_objects.pyx", line 55, in h5py._objects.with_phil.wrapper (-------src-dir-------/h5py/_objects.c:2415) 
    File "/software/anaconda/2.3.0/lib/python2.7/site-packages/h5py/_hl/dataset.py", line 640, in __array__ 
    arr = numpy.empty(self.shape, dtype=self.dtype if dtype is None else dtype) 
MemoryError 

Grazie per l'aiuto

risposta

14

programma voi è probabilmente fallendo nel tentativo di caricare l'intero set di dati nella RAM. 32 bit per float32 × 1,000,000 × 1000 è 3,7 GiB. Questo può essere un problema su macchine con solo 4 GB di RAM. Per verificare che in realtà è il problema, provare a creare un array di questa sola dimensione:

>>> import numpy as np 
>>> np.zeros((1000000, 1000), dtype=np.float32) 

Se vedi un MemoryError, vi sia bisogno di più RAM, o avete bisogno di elaborare il set di dati un pezzo alla volta.

Con set di dati h5py abbiamo appena dovremmo evitare di passare l'intero set di dati per i nostri metodi, e passare le fette di set di dati, invece. Uno alla volta.

Come io non ho i dati, vorrei iniziare dalla creazione di un set di dati a caso della stessa dimensione:

import h5py 
import numpy as np 
h5 = h5py.File('rand-1Mx1K.h5', 'w') 
h5.create_dataset('data', shape=(1000000,1000), dtype=np.float32) 
for i in range(1000): 
    h5['data'][i*1000:(i+1)*1000] = np.random.rand(1000, 1000) 
h5.close() 

crea un bel file di 3,8 GB.

Ora, se siamo in Linux, siamo in grado di limitare la quantità di memoria disponibile per il nostro programma:

$ bash 
$ ulimit -m $((1024*1024*2)) 
$ ulimit -m 
2097152 

Ora, se proviamo a eseguire il codice, otterremo il MemoryError. (Premere Ctrl-D per uscire la nuova sessione bash e reimpostare il limite più tardi)

Proviamo a risolvere il problema. Creeremo un oggetto IncrementalPCA e chiameremo il suo metodo .partial_fit() molte volte, fornendo ogni volta una porzione diversa del set di dati.

import h5py 
import numpy as np 
from sklearn.decomposition import IncrementalPCA 

h5 = h5py.File('rand-1Mx1K.h5') 
data = h5['data'] # it's ok, the dataset is not fetched to memory yet 

n = data.shape[0] # how many rows we have in the dataset 
chunk_size = 1000 # how many rows we feed to IPCA at a time, the divisor of n 
icpa = IncrementalPCA(n_components=10, batch_size=16) 

for i in range(0, n//chunk_size): 
    ipca.partial_fit(data[i*chunk_size : (i+1)*chunk_size]) 

E sembra funzionare per me, e se guardo quello top relazioni, i soggiorni di allocazione di memoria al di sotto 200M.

+0

Ok, quindi in sostanza non dovrei chiamare in forma ma partial_fit più volte. Non ho visto quel metodo, perché il tutorial usa in forma. Sai perché fit ha il parametro batch_size per, se carica l'intero set di dati in una volta? – KrawallKurt

+0

Il trucco di non caricare tutti i dati in memoria è probabilmente curato dalla libreria h5py. Il suo oggetto dataset ('h5 ​​['data']') sembra comportarsi come un normale array numpy, ma non lo è. 'IncrementalPCA' non sa che si tratta di una struttura dati su disco e ad un certo punto legge tutte le righe (' MemoryError'!). Il calcolo è ancora eseguito in batch 'batch_size'. – sastanin

+1

Questo succede in 'fit()' che [chiama check_array()] (https://github.com/scikit-learn/scikit-learn/blob/0.16.1/sklearn/decomposition/incremental_pca.py#L165) che si suppone per convertire i dati di una serie regolare NumPy (https://github.com/scikit-learn/scikit-learn/blob/0.16.1/sklearn/utils/validation.py#L268) chiamata 'partial_fit() 'ignora questa conversione. – sastanin