2012-12-18 22 views
15

Wie kann ich bestimmte Spalten aus einem Pandas HDFStore abrufen? Ich arbeite regelmäßig mit sehr großen Datensätzen, die zu groß sind, um sie im Speicher zu manipulieren. Ich würde gerne in einer CSV-Datei iterativ lesen, jeden Chunk in HDFStore-Objekt anhängen und dann mit Teilmengen der Daten arbeiten. Ich habe in einer einfachen CSV-Datei lesen und lud sie in ein HDFStore mit dem folgenden Code:Auswählen von Spalten aus der pandas.HDFStore-Tabelle

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

und den Ausgang:

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

Meine Frage ist, wie kann ich bestimmte Spalten aus tmp['df'] zugreifen? Die Dokumentation erwähnt eine select() Methode und einige Term Objekte. Die bereitgestellten Beispiele werden auf Panel-Daten angewendet; Allerdings, und ich bin zu sehr von einem Anfänger, um es auf den einfacheren Datenrahmen zu erweitern. Meine Vermutung ist, dass ich irgendwie einen Index der Spalten erstellen muss. Vielen Dank!

Antwort

11

Wie HDFStore Tabellen aufzeichnet, werden die Spalten nach Typ als einzelne numpy Arrays gespeichert. Sie erhalten immer alle Spalten zurück, Sie können sie filtern, so dass Sie für das zurückgegeben werden, was Sie fragen. In 0.10.0 können Sie einen Begriff mit Spalten übergeben.

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

oder können Sie indizieren danach

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

Die axes ist nicht wirklich die Lösung hier (was Sie tatsächlich in der Tat geschaffen war eine transponierte Rahmen zu speichern). Mit diesem Parameter können Sie den Speicher von Achsen neu ordnen, um die Datenausrichtung auf verschiedene Arten zu ermöglichen. Für einen Datenrahmen bedeutet das nicht viel; Für 3D- oder 4D-Strukturen ist die Datenausrichtung auf der Festplatte entscheidend für wirklich schnelle Abfragen.

0.10.1 erlaubt eine elegantere Lösung, nämlich Datenspalten, das heißt, Sie können bestimmte Spalten auswählen, die als eigene Spalten im Tabellenspeicher dargestellt werden, sodass Sie wirklich nur diese auswählen können. Hier ist ein Geschmack, was kommt.

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

Ein anderer Weg, um dies zu tun, gehen getrennte Tabellen in verschiedenen Knoten der Datei zu speichern, dann können Sie nur, was Sie brauchen.

Im Allgemeinen empfehle ich wieder wirklich große Tabellen. hayden bietet die Panel-Lösung an, was für Sie jetzt von Vorteil sein könnte, da die tatsächliche Datenanordnung widerspiegeln sollte, wie Sie die Daten abfragen möchten.

+0

Existiert diese Funktion in 0.10.1? Ich konnte es nicht benutzen. Was ist das offene Problem auf GitHub? – alexbw

+0

0.10.1 unterstützt Datenspalten; Welche Probleme hast du? – Jeff

+0

Ich denke, wir sollten dies aktualisieren, um Verwirrung zu vermeiden, Jeff? –

11

Sie können speichern Sie die Datenrahmen mit einem Index der Spalten wie folgt:

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

und wählen Sie dann, wie Sie hoffen könnten:

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 

Wo:

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 

.

Für mich ist das keine ideale Lösung, da wir den DataFrame nur durch eine Indizierung indexieren können! Beunruhigend the docs scheinen Sie können nur Index ein Datenrahmen durch eine Sache vorschlagen, zumindest mit axes:

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

ich dies falsch sein lesen kann, in welchem ​​Fall hoffentlich jemand beweisen kann mich nicht falsch!

.

Hinweis: Eine Möglichkeit, einen DataFrame mit zwei Dingen (Index und Spalten) zu indexieren, besteht darin, ihn in ein Panel zu konvertieren, das dann mithilfe von zwei Indizes abgerufen werden kann. Allerdings müssen wir jedes Mal, wenn Elemente abgerufen werden, in das ausgewählte Subpanel in einen DataFrame konvertieren ... wieder, nicht ideal.

+0

Sollte der Index datetime sein? Ich benutzte Zeichen als Index und ging genauso vor wie du. Allerdings, als ich durch die select-Anweisung in deinen Code kam (in [8]). Es hat den gesamten Datenrahmen abgerufen. Fehle ich hier etwas ?? – JustInTime

+0

siehe meine Antwort unten; Sie speichern grundsätzlich einen transponierten Rahmen. Das Achsenargument wird hier nicht benötigt – Jeff

+3

Die meisten Dinge in diesem Beispiel funktionieren für mich außer dieser Zeile: 'store.append ('df_cols', df, axes = 'columns')' Es löst den Fehler 'ValueError: No Achse namens c für Objekttyp ' Wenn Sie diese Zeile ersetzen mit: ' store.append ('df_cols', df, data_columns = True) ' dann der Fehler geht weg und der Rest des Beispiels funktioniert. – karenyng

Verwandte Themen