2012-12-18 5 views
15

Jak mogę pobrać określone kolumny z pandy HDFStore? Regularnie pracuję z bardzo dużymi zbiorami danych, które są zbyt duże, aby manipulować nimi w pamięci. Chciałbym czytać w pliku csv iteracyjnie, dołączyć każdą porcję do obiektu HDFStore, a następnie pracować z podzbiorami danych. Czytałem w prostym pliku csv i załadowaniu go do HDFStore z następującego kodu:Wybieranie kolumn z pandas.HDFStore table

tmp = pd.HDFStore('test.h5') 
chunker = pd.read_csv('cars.csv', iterator=True, chunksize=10, names=['make','model','drop']) 
tmp.append('df', pd.concat([chunk for chunk in chunker], ignore_index=True)) 

a wyjście:

In [97]: tmp 
Out[97]: 
<class 'pandas.io.pytables.HDFStore'> 
File path: test.h5 
/df  frame_table (typ->appendable,nrows->1930,indexers->[index]) 

Moje pytanie brzmi: w jaki sposób mogę uzyskać dostęp do wybranych wierszy z tmp['df']? W dokumentacji podano wzmiankę o metodzie select() i niektórych obiektach . Podane przykłady są stosowane do danych panelu; jednakże jestem zbyt początkującym, aby rozszerzyć go na prostszy przypadek ramki danych. Domyślam się, że muszę jakoś utworzyć indeks kolumn. Dzięki!

Odpowiedz

11

Sposób, w jaki HDFStore rejestruje tabele, a kolumny są przechowywane według typu jako pojedynczych tablic numpy. Zawsze otrzymujesz zwrot wszystkich kolumn, możesz je filtrować, dzięki czemu otrzymasz zwrot za to, o co poprosisz. W 0.10.0 można przekazać wyrażenie, które obejmuje kolumny.

store.select('df', [ Term('index', '>', Timestamp('20010105')), 
        Term('columns', '=', ['A','B']) ]) 

lub można reindex potem

df = store.select('df', [ Term('index', '>', Timestamp('20010105') ]) 
df.reindex(columns = ['A','B']) 

axes naprawdę nie jest tu rozwiązaniem (co faktycznie utworzony był w efekcie przechowywania transpozycji ramkę). Ten parametr pozwala na zmianę kolejności przechowywania osi, aby umożliwić wyrównanie danych na różne sposoby. W przypadku ramek danych to naprawdę niewiele znaczy; w przypadku struktur 3d lub 4d wyrównanie danych na dysku jest kluczowe dla naprawdę szybkich zapytań.

0.10.1 pozwoli na bardziej eleganckie rozwiązanie, a mianowicie kolumny danych, to znaczy, że możesz wybrać pewne kolumny, które mają być reprezentowane jako własne kolumny w magazynie tabeli, więc naprawdę możesz wybrać tylko te kolumny. Oto smak tego, co nadchodzi.

store.append('df', columns = ['A','B','C']) 
store.select('df', [ 'A > 0', Term('index', '>', Timestamp(2000105)) ]) 

Innym sposobem, aby nie iść na ten temat jest do przechowywania odrębnych tablic w różnych węzłach pliku, a następnie można wybrać tylko to, czego potrzebujesz.

Ogólnie polecam ponownie naprawdę szerokie tabele. Hayden oferuje rozwiązanie panelu, co może być dla ciebie korzystne, ponieważ rzeczywisty zestaw danych powinien odzwierciedlać sposób wyszukiwania danych.

+0

Czy istnieje ta funkcja w wersji 0.10.1? Nie mogłem go użyć. Jaki jest otwarty problem na Github? – alexbw

+0

0.10.1 obsługuje kolumny danych; jakie problemy masz? – Jeff

+0

Myślę, że powinniśmy to zaktualizować, aby uniknąć nieporozumień, Jeff? –

11

można przechowywać dataframe z indeksem kolumny w następujący sposób:

import pandas as pd 
import numpy as np 
from pandas.io.pytables import Term 

index = pd.date_range('1/1/2000', periods=8) 
df = pd.DataFrame(np.random.randn(8,3), index=index, columns=list('ABC')) 

store = pd.HDFStore('mydata.h5') 
store.append('df_cols', df, axes='columns') 

a następnie wybierz jak można mieć nadzieję:

In [8]: store.select('df_cols', [Term('columns', '=', 'A')]) 
Out[8]: 
2000-01-01 0.347644 
2000-01-02 0.477167 
2000-01-03 1.419741 
2000-01-04 0.641400 
2000-01-05 -1.313405 
2000-01-06 -0.137357 
2000-01-07 -1.208429 
2000-01-08 -0.539854 

Gdzie:

In [9]: df 
Out[9]: 
        A   B   C 
2000-01-01 0.347644 0.895084 -1.457772 
2000-01-02 0.477167 0.464013 -1.974695 
2000-01-03 1.419741 0.470735 -0.309796 
2000-01-04 0.641400 0.838864 -0.112582 
2000-01-05 -1.313405 -0.678250 -0.306318 
2000-01-06 -0.137357 -0.723145 0.982987 
2000-01-07 -1.208429 -0.672240 1.331291 
2000-01-08 -0.539854 -0.184864 -1.056217 

.

Dla mnie nie jest to idealne rozwiązanie, ponieważ możemy indeksować ramkę DataFrame tylko jedną rzeczą! Niepokojące the docs zdają się sugerować Ci może tylko indeksować DataFrame o jednej rzeczy, przynajmniej za pomocą axes:

Pass the axes keyword with a list of dimension (currently must by exactly 1 less than the total dimensions of the object).

I może być czytanie to nieprawidłowo, w którym to przypadku mam nadzieję, że ktoś może okazać się mnie źle!

.

Uwaga: Jednym ze sposobów, dla których znalazłem indeksowanie obiektu DataFrame przez dwie rzeczy (indeks i kolumny), jest przekonwertowanie go na panel, który można następnie pobrać za pomocą dwóch indeksów. Jednak musimy przekonwertować do wybranego subpanelu do DataFrame za każdym razem, gdy elementy są odzyskiwane ... znowu, nie idealne.

+0

Czy indeks powinien być datetime? Użyłem znaków jako indeksu i postępowałem w taki sam sposób jak ty. Jednak, gdy przyszedłem do instrukcji select w twoim kodzie (w [8]). Pobrał całą ramkę danych. Czy coś mi umyka ?? – JustInTime

+0

zobacz moją odpowiedź poniżej; twoje są zasadniczo przechowywania transponowanych ramek. argumenty dotyczące osi nie są tu potrzebne. – Jeff

+3

Większość rzeczy w tym przykładzie działa dla mnie z wyjątkiem tego wiersza: 'store.append ('df_cols', df, axes = 'columns')' Podnosi błąd 'ValueError: Nie oś o nazwie c dla typu obiektu ' Po zastąpieniu tej linii przez: ' store.append ('df_cols', df, data_columns = True) ' to błąd idzie z dala, a reszta przykładu działa. – karenyng