memory error mit pandas pivottable()

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Stephan12
User
Beiträge: 20
Registriert: Mittwoch 29. Januar 2014, 14:52

Hallo,

ich will aus einem Pandas Dataframe einen Pivittable machen. Dabei bekomme ich
jedesmal einen memory error.
Gibt es irgend eine Möglichkeit, das Vollaufen des Speichers zu verhindern?
Mein System: 3GB RAM, WinXP, Anaconda 32 bit distribution mit Spyder als Editor.
Der dataframe, den ich umwandeln will, hat ca. 205MB Größe, alle Werte sind
als 64bit abgespeichert. Nichtbenötigte Spalten habe ich bereits entfernt.
Zunächst hat mich überrascht, daß der Speicher überhaupt volläuft.
Oder ist das eine Python-interne Limitierung?

Kann man den durch Python verwaltbaren Speicherbereich irgendwie vergrößern oder
einige der 64bit Floats und Integers in 32Bit-Zahlen umwandeln?
Oder gibts sonst irgendwas, das man tun kann?
BlackJack

@Stephan12: Der Adressraum von Prozessen hat eine Obergrenze. Du hast Deine Daten, und die Pivottabelle braucht auch Platz. Und dann gibt es vielleicht noch Zwischenergebnisse die zumindest temporär gleichzeitig in den Speicher passen müssen. Und vielleicht hast Du selbst auch noch ein paar Daten zusätzlich bei der Vorverarbeitung angesammelt?

Allgemein empfiehlt es sich einzelne Arbeitsschritte in Funktionen zu stecken, damit nicht benötigtes nach ablauf der Funktion automatisch wieder abgereäumt werden kann.

Bei Numpy muss man manchmal aufpassen, dass das Slicen von Arrays ein Objekt liefern kann welches intern immer noch die originalen Daten referenziert, also nur einen kleinen Ausschnitt zugreifbar macht, aber immer noch alle Daten im Speicher hält.

Wenn es die Daten zulassen kannst Du natürlich auch einzelne Spalten umkodieren so dass sie weniger Speicher verwenden in dem Du den Wertebreich über den Datentyp verkleinerst.

Wie sieht denn der Dataframe von der Struktur her aus, damit man sich das zum Nachvollziehen mal mit Zufallsdaten erstellen kann? Wie viele Spalten, welchen Typ haben die jeweils, was für ein Index, und wie viele Zeilen gibt es? Wie sieht der Aufruf zum erstellen der Pivottabelle aus?
Stephan12
User
Beiträge: 20
Registriert: Mittwoch 29. Januar 2014, 14:52

@Blackjack:
"Der Adressraum von Prozessen hat eine Obergrenze".
Was heißt das(für mich als Laien)? Das der Prozess nur soviel Speicher benutzen kann, wie noch frei ist?
Der Fehler wird ausgeworfen, wenn der RAM zu gerademal 66% genutzt wird.

Mein Dataframe:
Int64Index: 2690014 entries, 0 to 2690013
Columns: 10 entries, date to unadjusted stock price
dtypes: datetime64[ns](1), float64(3), int64(3), object(3)

Tabellenkopf und erste Zeile:
date,adjusted stock close price,expiration,strike,call/put,ask,bid,volume,open interest,unadjusted stock price
2002-05-16,5047.0,2002-05-18 00:00:00,4300,C,802.0,788.0,0,38,5047.0

Ich muss den leider komplett, also alle Spalten verarbeiten. Der Dataframe hat ja auch nur 200MB.
Das Programm:

Code: Alles auswählen

import pandas
import time
inputpfad="mein Dateipfad"
start=time.clock()
df=pandas.DataFrame.from_csv(inputpfad,index_col=0, parse_dates=[0,5])
stop=time.clock()
diff=stop-start
print 'Einlesezeit:', diff
print 'resette Index...'
df=df.reset_index()
print 'berechne Pivottable...'
pv=pandas.pivot_table(df, rows=['expiration', 'strike', 'date', 'call/put'], cols=['bid', 'ask'])
print 'fertig'
Beim Erstellen der Pivot-Tabelle steigt das Programm aus mit der Meldung:
mask = np.zeros(np.prod(self.full_shape), dtype=bool)
MemoryError

Wenn es mit Pivot gar nicht geht, muß ich mir möglicherweise mit Sortierfunktionen behelfen.
Dann ist aber die Frage, ob ich für das Algotrading-Modul, das ich eigentlich schreiben will, überhaupt Pandas o. Python nehmen sollte oder lieber was anderes, wo bei 66% RAM-Konsum und einer zu verarbeitenden 200MB-Datei keine Fehler
ausgeworfen werden.
Zuletzt geändert von Anonymous am Montag 10. Februar 2014, 18:11, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@Stephan12: unter WinXP ist der Addressraum auf 2GB begrenzt, da muß Python mit allen DLLs und alle Daten hineinpassen.
Also wenn Deine 200Mb so ungefähr 5 mal im Speicher sind, dann läuft der über.
Stephan12
User
Beiträge: 20
Registriert: Mittwoch 29. Januar 2014, 14:52

Wird da nicht eine Auslagerungsdatei erstellt, bevor der Speicher überläuft?
Bei meinem Script ist die Datei einmal im Speicher, siehe vorheriger Eintrag.
Das, was im Windows-Task-Manager Verfügbarer physikal. Speicher angezeigt wird,
ist doch das, auf was mit meinem BS auch tatsächlich zugegriffen werden kann, oder?
Und das, was bei Python/Spyder rechts unten unter Memory % angezeigt wird,
ist doch das, was mit meinem BS tatsächlich verfügbar bzw. genutzt wird?
Demnach dürfte nichts überlaufen.
BlackJack

@Stephan12: 66% von 3 GiB sind 1,98 GiB, also so fast genau die 2 GiB-Grenze die ein Prozess anfordern kann. Das Betriebssystem kann auf den gesamten Speicher + Auslagerungsdatei zugreifen, also eventuell auch deutlich mehr als physikalischer Arbeitsspeicher im Rechner steckt, aber der Adressraum eines einzelnen Benutzerprozesses ist trotzdem auf das beschränkt was er mit Zeigern adressieren kann, und die sind bei 32-Bit nun mal beschränkt. Und Windows XP beschränkt das auf 2 GiB.

Zu Spyder kann ich nichts sagen.

Eventuell kann hier noch Speicherfragmentation eine Rolle spielen, also das zwar an sich genug Speicher insgesamt frei ist, der aber nach dem Einlesen der CSV-Datei nicht an einem Stück vorliegt und eine grosse Speicheranforderung deshalb fehl schlägt.

Was sind denn die drei `object`-Spalten? An der einen Beispielzeile kann man nur 'call/put' als solche erkennen, die anderen sind ja numerisch. Die 'call/put'-Spalte könnte man beispielsweise versuchen auch numerisch zu machen oder als Zeichenketten mit fester Länge. Wenn da nur 'C' und 'P' drin stehen oder generell nur ein Buchstabe wäre der Numpy-Typ 'c' also Zeichen/fixe Zeichenkette der Länge 1 sparsamer als`object` was ein Zeiger pro Wert also mindestens vier Bytes + was immer die Objekte insgesamt verbrauchen auf die verwiesen wird, bedeutet.

Und wie hast Du die 205 MiB für den Dataframe ermittelt?
Stephan12
User
Beiträge: 20
Registriert: Mittwoch 29. Januar 2014, 14:52

Vor dem Start des Scriptes sind noch kanpp 2GB frei.
Tatsächlich wird der Memory-Error erzeugt, wenn der verfügbare Speicher
im Taskmanager auf unter 1GB sinkt. Also wird hier scheinbar nicht der adressierbare (2GB),
sondern der physisch vorhandene Speicher angezeigt. Das sieht ja dann nicht gut aus
und der Pivot-Befehl ist sehr speicherintensiv.

hab gerade nochmal den Frame gecheckt:
Int64Index: 2690014 entries, 0 to 2690013
Columns: 10 entries, date to unadjusted stock price
dtypes: datetime64[ns](2), float64(4), int64(3), object(1)

Also nur ein Object, vermutlich ist das die call/put-Spalte. Ja, da steht nur C oder P drin.
Diese Spalte könnte man schon umformatieren, vermutlich kann man auch die int64-Spalten zu int32 machen.
Aber wie geht das und gibt es irgendwo eine Liste, welche Formate verfügbar sind und wie die Eingaben dafür jeweils lauten?
Habs gerade versucht mit df['call/put']=df['call/put'].astype('c').
Es kam zwar keine Fehlermeldung, aber danach ists immer noch object.
Die Framegröße hab ich berechnet mit 64 bit pro Tabelleneintrag mal Spaltenzahl mal Zeilenzahl.
Da sind natürlich die Spaltennamen und die Objektkonstruktion nicht mit dabei, aber die Größenordnnung sollte ja schon stimmen.
Antworten