2013-07-15 16 views
5

In Pandas, esiste un modo per estrarre in modo efficiente tutti gli indici MultiIndex presenti in un HDFStore in formato tabella?Pandas HDFStore di MultiIndex DataFrames: come ottenere in modo efficiente tutti gli indici

Posso usare where= in modo efficiente utilizzando where=, ma voglio tutti gli indici e nessuna delle colonne. Posso anche select() usando iterator=True per risparmiare RAM, ma ciò significa comunque leggere praticamente tutto il disco dal disco, quindi è ancora lento.

Sono stato a caccia nelle cose store.root..table. *, Sperando di ottenere un elenco di valori di indice. Sono sulla buona strada?

Il piano B sarebbe quello di mantenere un DataFrame MultiIndex più breve che contiene solo DataFrames vuoti aggiunti ogni volta che aggiungo quello principale. Posso recuperarlo e ottenere l'indice molto più a buon mercato di quello principale. Inelegante però.

risposta

5

creare un multi-indice di df

In [35]: df = DataFrame(randn(100000,3),columns=list('ABC')) 

In [36]: df['one'] = 'foo' 

In [37]: df['two'] = 'bar' 

In [38]: df.ix[50000:,'two'] = 'bah' 

In [40]: mi = df.set_index(['one','two']) 

In [41]: mi 
Out[41]: 
<class 'pandas.core.frame.DataFrame'> 
MultiIndex: 100000 entries, (foo, bar) to (foo, bah) 
Data columns (total 3 columns): 
A 100000 non-null values 
B 100000 non-null values 
C 100000 non-null values 
dtypes: float64(3) 

Conservarlo come una tabella

In [42]: store = pd.HDFStore('test.h5',mode='w') 

In [43]: store.append('df',mi) 

get_storer restituirà l'oggetto memorizzato (ma non recuperare i dati)

In [44]: store.get_storer('df').levels 
Out[44]: ['one', 'two'] 

In [2]: store 
Out[2]: 
<class 'pandas.io.pytables.HDFStore'> 
File path: test.h5 
/df   frame_table (typ->appendable_multi,nrows->100000,ncols->5,indexers->[index],dc->[two,one]) 

Il i livelli indice sono creati come colonne_dati, il che significa che puoi usarli nelle selezioni Questo è come selezionare solo l'indice

In [48]: store.select('df',columns=['one']) 
Out[48]: 
<class 'pandas.core.frame.DataFrame'> 
MultiIndex: 100000 entries, (foo, bar) to (foo, bah) 
Empty DataFrame 

Per selezionare una singola colonna e restituire come mi-frame

In [49]: store.select('df',columns=['A']) 
Out[49]: 
<class 'pandas.core.frame.DataFrame'> 
MultiIndex: 100000 entries, (foo, bar) to (foo, bah) 
Data columns (total 1 columns): 
A 100000 non-null values 
dtypes: float64(1) 

Per selezionare una singola colonna come una serie (che può anche essere indice come questi sono memorizzati come colonne). Questo sarà abbastanza veloce.

In [2]: store.select_column('df','one') 
Out[2]:  
0     foo 
1     foo 
2     foo 
3     foo 
4     foo 
5     foo 
6     foo 
7     foo 
8     foo 
9     foo 
10    foo 
11    foo 
12    foo 
13    foo 
14    foo 
... 
99985    foo 
99986    foo 
99987    foo 
99988    foo 
99989    foo 
99990    foo 
99991    foo 
99992    foo 
99993    foo 
99994    foo 
99995    foo 
99996    foo 
99997    foo 
99998    foo 
99999    foo 
Length: 100000, dtype: object 

Se si vuole veramente la scelta più veloce solo l'indice

In [4]: %timeit store.select_column('df','one') 
100 loops, best of 3: 8.71 ms per loop 

In [5]: %timeit store.select('df',columns=['one']) 
10 loops, best of 3: 43 ms per loop 

O per ottenere un indice completo

In [6]: def f(): 
    ...:  level_1 = store.select_column('df','one') 
    ...:  level_2 = store.select_column('df','two') 
    ...:  return MultiIndex.from_arrays([ level_1, level_2 ]) 
    ...: 

In [17]: %timeit f() 
10 loops, best of 3: 28.1 ms per loop 

Se si desidera che i valori per ogni livello, una piuttosto veloce modo di farlo

In [2]: store.select_column('df','one').unique() 
Out[2]: array(['foo'], dtype=object) 

In [3]: store.select_column('df','two').unique() 
Out[3]: array(['bar', 'bah'], dtype=object) 
+0

Risposta fantastica, grazie Jeff. Immagino che la risposta diretta sia che guardare nel tavolo di store.root. *. È infruttuoso. Ad ulteriore considerazione, ispirata alla tua risposta, ha senso che non ci sia una scorciatoia - devi permettere alla selezione di considerare tutti i dati. Cercando di ottenere alcuni metadati per dire quali valori di indice avranno solo lo stesso spazio. A titolo di spiegazione, non tutte le combinazioni possibili del mio multiindice sono riempite, quindi non basta avere i livelli del multiindice. Grazie. – Tony

+0

potresti trovare '' select_column (...). Unique() '' anche utile, che in effetti ti farà ottenere i valori di un particolare livello, non sono sicuro se ti sia utile – Jeff

+0

Ho aggiunto il metodo I appena suggerito – Jeff

1

Chi lavora con tabelle ancora più grandi può trovare la soluzione suggerita da Jeff per finire con Memory Error. È una soluzione molto più elegante, ma non ho potuto usare nel mio caso (per una tabella di righe 2e9, indice datetime, su un desktop RAM da 16 GB). ho finito con la seguente soluzione (purtroppo non elegante), dove h5store è l'oggetto HDFStore, un dataframe multi-indicizzato, salvato come un tavolo, con timestamp indice (Float64) che è un CSI uno:

%%time 
#ts = h5store.select_column(h5store.keys()[0], column='timestamp').unique() 

chunkshape = int(1e7) # can vary due to machine and hdf5 

## get a list of chunks unique timestamps 
ts = [indx.index.get_level_values('timestamp').unique() 
      for indx in h5full.select(h5full.keys()[0], columns=['timestamp'], 
            stop=None, # change for a smaller selection 
            chunksize=chunkshape) 
     ] 
## drop duplicates at the the end-points 
for i in range(len(ts)-1): 
    if ts[i][-1]==ts[i+1][0]: 
     ts[i] = ts[i][:-1] 
## merge to single ndarray 
ts = np.concatenate(ts) 

Il tempo per questa corsa (oltre 2e9 righe):

CPU times: user 14min 16s, sys: 2min 34s, total: 16min 50s 
Wall time: 14min 45s 
Problemi correlati