2013-07-15 13 views
5

Czy w Pandach można skutecznie wyciągnąć wszystkie indeksy MultiIndex obecne w magazynie HDF w formacie tabeli?Pandas HDFStore z MultiIndex DataFrames: jak sprawnie uzyskać wszystkie indeksy

Mogę select() efektywnie używać where=, ale chcę wszystkie indeksy i żadnej z kolumn. Mogę także select() użyć iterator=True, aby zaoszczędzić pamięć RAM, ale to nadal oznacza czytanie prawie całej tabeli z dysku, więc nadal jest wolna.

Byłem na polowaniu w sklepie.root..table. * Rzeczy, mając nadzieję, że mogę uzyskać listę wartości indeksu. Czy jestem na dobrej drodze?

Plan B to krótszy MultiIndex DataFrame, który będzie zawierał puste ramki DataFrames dołączane za każdym razem, gdy dołączę główny. Mogę to odzyskać i uzyskać indeks taniej niż główny. Nieelegancki.

Odpowiedz

5

Tworzenie multi-index 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) 

przechowywać je w postaci tabeli

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

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

get_storer zwróci przechowywany przedmiot (ale nie pobierania danych)

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]) 

poziomy indeksu są tworzone jako kolumny data_columns, co oznacza, że ​​można ich używać w selekcji W ten sposób wybrać tylko wskaźnik

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

Aby wybrać jedną kolumnę i powrót jako mi-ramki

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) 

Aby wybrać jedną kolumnę w postaci szeregu (które mogą być również indeks, ponieważ są one przechowywane jako kolumny). To będzie dość szybko.

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 

Jeśli naprawdę chcesz najszybszy wybór jedynego indeksu

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 

lub uzyskać pełny indeks

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 

Jeśli chcesz wartości dla poszczególnych poziomów, to dość szybko sposób wykonania tego:

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

Fantastyczna odpowiedź, dzięki Jeff. Myślę, że bezpośrednią odpowiedzią jest to, że zaglądanie do sklepu. Przy dalszej analizie, zainspirowanej twoją odpowiedzią, ma sens, że nie ma skrótu - musisz pozwolić, aby zaznaczenie uwzględniało wszystkie dane. Próbuję zdobyć metadane, aby określić, które wartości indeksu zajmą to samo miejsce. Tytułem wyjaśnień nie wszystkie możliwe kombinacje mojego multiindeksu są wypełnione, więc samo uzyskanie poziomów wieluindeksów nie jest wystarczające. Dziękuję Ci. – Tony

+0

możesz znaleźć '' select_column (...). Unique() '' również użyteczne, co w efekcie da ci wartości określonego poziomu, nie wiesz, czy to ci się przydaje – Jeff

+0

Dodałem metodę I just recommended – Jeff

1

Osoby pracujące z jeszcze większymi tabelami mogą znaleźć rozwiązanie sugerowane przez Jeffa, aby uzyskać błąd pamięci. Jest to o wiele bardziej eleganckie rozwiązanie, ale nie mogłem go wykorzystać w moim przypadku (dla tabeli 2e9 wierszy, indeksu datetime, na 16GB pamięci RAM). skończyło się następująco (niestety nie elegancki) roztworu, gdzie h5store obiektem HDFStore, multi-indeksowane DataFrame, zapisane w postaci tabeli, z timestamp Index (Float64), która jest CSI jeden:

%%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) 

Czas trwania tego biegu (ponad 2e9 wierszy):

CPU times: user 14min 16s, sys: 2min 34s, total: 16min 50s 
Wall time: 14min 45s 
Powiązane problemy