2013-04-09 16 views
6

Sto provando a selezionare righe casuali da una tabella HDFStore di circa 1 GB. L'utilizzo della RAM esplode quando chiedo circa 50 righe casuali.HDFStore: table.select e utilizzo RAM

Sto usando i panda 0-11-dev, python 2.7, linux64.

In questo primo caso l'utilizzo di RAM si adatta alle dimensioni del chunk

with pd.get_store("train.h5",'r') as train: 
for chunk in train.select('train',chunksize=50): 
    pass 

In questo secondo caso, sembra che l'intera tabella viene caricato nella RAM

r=random.choice(400000,size=40,replace=False) 
train.select('train',pd.Term("index",r)) 

In questo ultimo caso, l'utilizzo della RAM si inserisce l'equivalente chunk dimensioni

r=random.choice(400000,size=30,replace=False)  
train.select('train',pd.Term("index",r)) 

Sono perplesso, perché il passaggio da 30 a 40 righe casuali induce un così drammatico aumento nell'utilizzo della RAM.

Nota la tabella è stata indicizzata quando realizzati in modo che index = intervallo (nrows (tabella)) usando il codice seguente:

def txtfile2hdfstore(infile, storefile, table_name, sep="\t", header=0, chunksize=50000): 
    max_len, dtypes0 = txtfile2dtypes(infile, sep, header, chunksize) 

    with pd.get_store(storefile,'w') as store: 
     for i, chunk in enumerate(pd.read_table(infile,header=header,sep=sep,chunksize=chunksize, dtype=dict(dtypes0))): 
      chunk.index= range(chunksize*(i), chunksize*(i+1))[:chunk.shape[0]] 
      store.append(table_name,chunk, min_itemsize={'values':max_len}) 

Grazie per la comprensione

EDIT RISOLVERE Zelazny7

Ecco il file che ho usato per scrivere Train.csv su train.h5. Ho scritto questo utilizzando gli elementi di codice di Zelazny7 da How to trouble-shoot HDFStore Exception: cannot find the correct atom type

import pandas as pd 
import numpy as np 
from sklearn.feature_extraction import DictVectorizer 


def object_max_len(x): 
    if x.dtype != 'object': 
     return 
    else: 
     return len(max(x.fillna(''), key=lambda x: len(str(x)))) 

def txtfile2dtypes(infile, sep="\t", header=0, chunksize=50000): 
    max_len = pd.read_table(infile,header=header, sep=sep,nrows=5).apply(object_max_len).max() 
    dtypes0 = pd.read_table(infile,header=header, sep=sep,nrows=5).dtypes 

    for chunk in pd.read_table(infile,header=header, sep=sep, chunksize=chunksize): 
     max_len = max((pd.DataFrame(chunk.apply(object_max_len)).max(),max_len)) 
     for i,k in enumerate(zip(dtypes0[:], chunk.dtypes)): 
      if (k[0] != k[1]) and (k[1] == 'object'): 
       dtypes0[i] = k[1] 
    #as of pandas-0.11 nan requires a float64 dtype 
    dtypes0.values[dtypes0 == np.int64] = np.dtype('float64') 
    return max_len, dtypes0 


def txtfile2hdfstore(infile, storefile, table_name, sep="\t", header=0, chunksize=50000): 
    max_len, dtypes0 = txtfile2dtypes(infile, sep, header, chunksize) 

    with pd.get_store(storefile,'w') as store: 
     for i, chunk in enumerate(pd.read_table(infile,header=header,sep=sep,chunksize=chunksize, dtype=dict(dtypes0))): 
      chunk.index= range(chunksize*(i), chunksize*(i+1))[:chunk.shape[0]] 
      store.append(table_name,chunk, min_itemsize={'values':max_len}) 

applicato come

txtfile2hdfstore('Train.csv','train.h5','train',sep=',') 
+0

Sembra che tu stia utilizzando HDFStore in modo simile a come vorrei utilizzarlo. Non ho avuto il tempo di creare il codice wrapper che gestisce gran parte della memorizzazione e del recupero. Ti dispiacerebbe condividere il tuo codice 'txtfile2dtypes'? Inoltre, i tuoi dati hanno molti dati di carattere? Ho riscontrato problemi durante l'archiviazione di un file CSV in un HDFStore con dati a carattere variabile. La dimensione del file esplode perché devo impostare 'min_itemsize' su un valore così grande. Attendo con impazienza l'aggiunta di un'opzione 'truncate'. – Zelazny7

+1

@ Zelazny7 Ho aggiornato la discussione con il codice. In realtà lo sto usando sugli stessi dati del tuo, la cosa del bulldozer di Kaggle.Non ho ancora inventato le variabili categoriali per usare 'sklearn' ancora. – user17375

+1

Grazie mille! Sembra che le dimensioni del tuo fumetto siano uguali a quelle del mio. Il file ~ 120mb finisce oltre 1 GB. Mi chiedo se tu o Jeff sapeste se è meglio memorizzare colonne 'object' di lunghezza variabile (in realtà solo stringhe) usando' put' e mantenendo ciascuna colonna di testo come se fosse un oggetto HDFStore. – Zelazny7

risposta

6

Questo è un problema noto, vedi il riferimento qui: https://github.com/pydata/pandas/pull/2755

In sostanza la query viene trasformato in un numexpr espressione per la valutazione. C'è un problema in cui non posso passare molte condizioni or a numexpr (dipende dalla lunghezza totale dell'espressione generata ).

Quindi limito solo l'espressione che passiamo a numexpr. Se supera un certo numero di condizioni or, la query viene eseguita come filtro, anziché come selezione nel kernel. Fondamentalmente questo significa che la tabella viene letta e quindi reindicizzata.

Questo è nell'elenco dei miei miglioramenti: https://github.com/pydata/pandas/issues/2391 (17).

Come soluzione, basta dividere le query in più e concatenare i risultati. Dovrebbe essere molto più veloce e utilizzare una quantità costante di memoria

+1

Ok grazie. Ho perso il thread del problema, avrei dovuto prima cercare i forum di Github. A proposito, mi rendo conto che sei lo sviluppatore di hdfstore, quindi grazie per l'ottimo lavoro! – user17375

+0

Questo è piuttosto oscuro e sfortunato facile da perdere :) – Jeff

Problemi correlati