So speichern Sie einen Datenrahmen mit Pandas

317

Im Moment importiere CSVich jedes Mal, wenn ich das Skript ausführe , einen ziemlich großen Datenrahmen. Gibt es eine gute Lösung, um diesen Datenrahmen zwischen den Läufen ständig verfügbar zu halten, damit ich nicht die ganze Zeit auf die Ausführung des Skripts warten muss?

jeffstern
quelle
2
Ja, dies ist eine meiner Hauptbeschwerden bei der Verwendung von Python - es gibt keine einfache Möglichkeit, Datenrahmen zu speichern und abzurufen. R und SAS sind in dieser Hinsicht weitaus benutzerfreundlicher.
RobertF

Antworten:

481

Am einfachsten ist es, es mit folgenden Zutaten zu beizento_pickle :

df.to_pickle(file_name)  # where to save it, usually as a .pkl

Dann können Sie es wieder laden mit:

df = pd.read_pickle(file_name)

Hinweis: vor 0.11.1 saveund loadwaren der einzige Weg , dies zu tun (sie sind jetzt für veraltet to_pickleund read_picklerespectively).


Eine weitere beliebte Option ist die Verwendung von HDF5 ( pytables ), das sehr schnelle Zugriffszeiten für große Datenmengen bietet :

store = HDFStore('store.h5')

store['df'] = df  # save it
store['df']  # load it

Weiterführende Strategien werden im Kochbuch besprochen .


Seit 0.13 gibt es auch msgpack, das für die Interoperabilität besser geeignet ist , als schnellere Alternative zu JSON oder wenn Sie pythonobjekt- / textlastige Daten haben (siehe diese Frage ).

Andy Hayden
quelle
8
@geekazoid save ist auf to_pickle veraltet (wodurch eher ein Pickle als ein CSV erstellt wird, was ein viel schnelleres / anderes Objekt ist).
Andy Hayden
9
@geekazoid Falls die Daten nach dem Laden transformiert werden müssen (dh Zeichenfolge / Objekt in datetime64), muss dies nach dem Laden einer gespeicherten CSV erneut durchgeführt werden, was zu Leistungseinbußen führt. pickle speichert den Datenrahmen in seinem aktuellen Zustand, sodass die Daten und ihr Format erhalten bleiben. Dies kann zu massiven Leistungssteigerungen führen.
Harbun
4
Sowohl pickle als auch HDFStore können Datenrahmen nicht mehr als 8 GB speichern. Gibt es Alternativen?
user1700890
1
@ user1700890 versuchen, aus zufälligen Daten (Text und Arrays) zu generieren und eine neue Frage zu stellen. Ich denke nicht, dass dies richtig sein kann / ich vermute, dass uns etwas fehlt. Neue Frage wird mehr Augen bekommen, aber versuchen Sie, einen DataFrame einzuschließen / zu generieren, der reproduziert :)
Andy Hayden
1
@ YixingLiu können Sie den Modus nach der Tatsache ändern stackoverflow.com/a/16249655/1240268
Andy Hayden
100

Obwohl es bereits einige Antworten gibt, habe ich einen schönen Vergleich gefunden, bei dem verschiedene Möglichkeiten zur Serialisierung von Pandas DataFrames ausprobiert wurden: Effizientes Speichern von Pandas DataFrames .

Sie vergleichen:

  • pickle: Original-ASCII-Datenformat
  • cPickle, eine C-Bibliothek
  • pickle-p2: Verwendet das neuere Binärformat
  • json: standardlib json Bibliothek
  • json-no-index: wie json, aber ohne index
  • msgpack: binäre JSON-Alternative
  • CSV
  • hdfstore: HDF5-Speicherformat

In ihrem Experiment serialisieren sie einen DataFrame mit 1.000.000 Zeilen, wobei die beiden Spalten separat getestet werden: eine mit Textdaten, die andere mit Zahlen. Ihr Haftungsausschluss lautet:

Sie sollten nicht darauf vertrauen, dass das Folgende auf Ihre Daten verallgemeinert wird. Sie sollten sich Ihre eigenen Daten ansehen und selbst Benchmarks durchführen

Der Quellcode für den Test, auf den sie sich beziehen, ist online verfügbar . Da dieser Code nicht direkt funktionierte, habe ich einige kleinere Änderungen vorgenommen, die Sie hier erhalten können: serialize.py Ich habe die folgenden Ergebnisse erhalten:

Zeitvergleichsergebnisse

Sie erwähnen auch, dass mit der Konvertierung von Textdaten in kategoriale Daten die Serialisierung viel schneller ist. In ihrem Test etwa 10 mal so schnell (siehe auch Testcode).

Bearbeiten : Die höheren Zeiten für Pickle als CSV können durch das verwendete Datenformat erklärt werden. Standardmäßig picklewird eine druckbare ASCII-Darstellung verwendet, die größere Datenmengen generiert. Wie aus der Grafik ersichtlich ist, hat Pickle mit dem neueren Binärdatenformat (Version 2 pickle-p2) viel kürzere Ladezeiten.

Einige andere Referenzen:

ein Gold
quelle
1
Ich habe meine Antwort aktualisiert, um Ihre Frage zu erklären. Zusammenfassend: Pickle speichert standardmäßig Daten in einem ASCII-Format.
Agold
1
Ah, danke für diese Erklärung! Als Hinweis scheint Pandas DataFrame .to_pickle das pkl.HIGHEST_PROTOCOL (sollte 2 sein) zu verwenden
ntg
2
Es scheint, dass der oben verlinkte Blog ( Effizientes Speichern von Pandas DataFrames wurde gelöscht. Ich habe meine eigenen Vergleiche mit .to_pickle()(der Binärspeicher verwendet) gegen .to_hdf()(ohne Komprimierung) durchgeführt. Das Ziel war Geschwindigkeit, Dateigröße für HDF war 11x Pickle und Zeit zum Laden war 5x Pickle. Meine Daten waren ~ 5k Dateien mit ~ 7k Zeilen x 6 Spalten, meistens numerisch.
hamx0r
1
Die Seite existiert noch, Sie müssen nur den abschließenden
IanSR
2
@ Mike Williamson, in meinem Test war Pickle 5x schneller zu laden als HDF und beanspruchte auch 1/11 des Speicherplatzes (dh HDF war 11x größer auf der Festplatte und benötigte 5x so viel Zeit zum Laden von der Festplatte wie Pickle). Dies war alles auf Python 3 mit Pandas 0.22.0.
hamx0r
35

Wenn ich das richtig verstehe, verwenden Sie bereits pandas.read_csv(), möchten aber den Entwicklungsprozess beschleunigen, damit Sie die Datei nicht jedes Mal laden müssen, wenn Sie Ihr Skript bearbeiten. Stimmt das? Ich habe ein paar Empfehlungen:

  1. Sie können nur einen Teil der CSV-Datei pandas.read_csv(..., nrows=1000)laden, indem Sie nur das oberste Bit der Tabelle laden, während Sie die Entwicklung durchführen

  2. Verwenden Sie ipython für eine interaktive Sitzung, sodass Sie die Pandas-Tabelle beim Bearbeiten und erneuten Laden Ihres Skripts im Speicher behalten.

  3. Konvertieren Sie die CSV in eine HDF5-Tabelle

  4. aktualisierte Verwendung DataFrame.to_feather()und pd.read_feather()zum Speichern von Daten im R-kompatiblen Feder- Binärformat, das superschnell ist (in meinen Händen etwas schneller als pandas.to_pickle()bei numerischen Daten und viel schneller bei String-Daten).

Diese Antwort zum Stackoverflow könnte Sie auch interessieren .

Noah
quelle
Wissen Sie, warum Sie to_feathermit Zeichenfolgendaten gut arbeiten können? Ich habe ein Benchmarking durchgeführt to_pickleund to_featureauf meinem numerischen Datenrahmen ist Pickle ungefähr dreimal schneller.
Zyxue
@zyxue gute Frage, ich habe ehrlich gesagt nicht viel mit dem Federmaterial gespielt, also habe ich keine Antwort
Noah
20

Gurke funktioniert gut!

import pandas as pd
df.to_pickle('123.pkl')    #to save the dataframe, df to 123.pkl
df1 = pd.read_pickle('123.pkl') #to load 123.pkl back to the dataframe df
Anbarasu Ramachandran
quelle
8
Beachten Sie, dass die generierten Dateien keine CSV-Dateien sind. Vielleicht ist es besser, die Erweiterung zu verwenden, .pklwie in der Antwort von @Andy Haydens vorgeschlagen.
Agold
5

Sie können eine Datei im Federformat verwenden. Es ist extrem schnell.

df.to_feather('filename.ft')
Huanyu Liao
quelle
Und die Daten können dann direkt Rüber die featherBibliothek verwendet werden.
James Hirschorn
4

Pandas DataFrames haben die to_pickleFunktion, die zum Speichern eines DataFrames nützlich ist:

import pandas as pd

a = pd.DataFrame({'A':[0,1,0,1,0],'B':[True, True, False, False, False]})
print a
#    A      B
# 0  0   True
# 1  1   True
# 2  0  False
# 3  1  False
# 4  0  False

a.to_pickle('my_file.pkl')

b = pd.read_pickle('my_file.pkl')
print b
#    A      B
# 0  0   True
# 1  1   True
# 2  0  False
# 3  1  False
# 4  0  False
mgoldwasser
quelle
4

Wie bereits erwähnt, gibt es verschiedene Optionen und Dateiformate ( HDF5 , JSON , CSV , Parkett , SQL ) zum Speichern eines Datenrahmens. Ist picklejedoch kein erstklassiger Bürger (abhängig von Ihrer Einrichtung), weil:

  1. pickleist ein potenzielles Sicherheitsrisiko. Bilden Sie die Python-Dokumentation für pickle :

Warnung Das pickleModul ist nicht sicher gegen fehlerhafte oder böswillig erstellte Daten. Entfernen Sie niemals Daten, die von einer nicht vertrauenswürdigen oder nicht authentifizierten Quelle stammen.

  1. pickleist langsam. Finden Sie hier und hier Benchmarks.

Abhängig von Ihrem Setup / Ihrer Verwendung gelten beide Einschränkungen nicht, aber ich würde nicht pickleals Standardpersistenz für Pandas-Datenrahmen empfehlen .

Michael Dorner
quelle
1

Numpy Dateiformate sind für numerische Daten ziemlich schnell

Ich bevorzuge die Verwendung von Numpy-Dateien, da diese schnell und einfach zu bearbeiten sind. Hier ist ein einfacher Benchmark zum Speichern und Laden eines Datenrahmens mit 1 Spalte mit 1 Million Punkten.

import numpy as np
import pandas as pd

num_dict = {'voltage': np.random.rand(1000000)}
num_df = pd.DataFrame(num_dict)

mit der %%timeitmagischen Funktion von ipython

%%timeit
with open('num.npy', 'wb') as np_file:
    np.save(np_file, num_df)

die Ausgabe ist

100 loops, best of 3: 5.97 ms per loop

um die Daten wieder in einen Datenrahmen zu laden

%%timeit
with open('num.npy', 'rb') as np_file:
    data = np.load(np_file)

data_df = pd.DataFrame(data)

die Ausgabe ist

100 loops, best of 3: 5.12 ms per loop

NICHT SCHLECHT!

Nachteile

Es gibt ein Problem, wenn Sie die Numpy-Datei mit Python 2 speichern und dann versuchen, sie mit Python 3 zu öffnen (oder umgekehrt).

Mark Jay
quelle
6
Beachten Sie, dass diese Lösung alle Ihre Spaltennamen löscht und alle Ihre ganzzahligen Daten in float ändert :(
Joseph Garvin
0

https://docs.python.org/3/library/pickle.html

Die Pickle-Protokollformate:

Protokollversion 0 ist das ursprüngliche, für Menschen lesbare Protokoll und abwärtskompatibel mit früheren Versionen von Python.

Protokollversion 1 ist ein altes Binärformat, das auch mit früheren Versionen von Python kompatibel ist.

Protokoll Version 2 wurde in Python 2.3 eingeführt. Es bietet ein viel effizienteres Beizen von Klassen neuen Stils. Informationen zu Verbesserungen durch Protokoll 2 finden Sie in PEP 307.

Protokollversion 3 wurde in Python 3.0 hinzugefügt. Es unterstützt explizit Byte-Objekte und kann von Python 2.x nicht entfernt werden. Dies ist das Standardprotokoll und das empfohlene Protokoll, wenn Kompatibilität mit anderen Python 3-Versionen erforderlich ist.

Protokollversion 4 wurde in Python 3.4 hinzugefügt. Es bietet Unterstützung für sehr große Objekte, das Beizen weiterer Objekttypen und einige Optimierungen des Datenformats. Informationen zu Verbesserungen durch Protokoll 4 finden Sie in PEP 3154.

Gilco
quelle
0

Pyarrow-Kompatibilität zwischen Versionen

Insgesamt ging es um Pyarrow / Feder (Verfallswarnungen von Pandas / Msgpack). Ich habe jedoch eine Herausforderung mit Pyarrow mit vorübergehender Spezifikation. Mit Pyarrow 0.15.1 serialisierte Daten können mit 0.16.0 ARROW-7961 nicht deserialisiert werden . Ich verwende Serialisierung, um Redis zu verwenden, daher muss eine binäre Codierung verwendet werden.

Ich habe verschiedene Optionen erneut getestet (mit Jupyter Notebook)

import sys, pickle, zlib, warnings, io
class foocls:
    def pyarrow(out): return pa.serialize(out).to_buffer().to_pybytes()
    def msgpack(out): return out.to_msgpack()
    def pickle(out): return pickle.dumps(out)
    def feather(out): return out.to_feather(io.BytesIO())
    def parquet(out): return out.to_parquet(io.BytesIO())

warnings.filterwarnings("ignore")
for c in foocls.__dict__.values():
    sbreak = True
    try:
        c(out)
        print(c.__name__, "before serialization", sys.getsizeof(out))
        print(c.__name__, sys.getsizeof(c(out)))
        %timeit -n 50 c(out)
        print(c.__name__, "zlib", sys.getsizeof(zlib.compress(c(out))))
        %timeit -n 50 zlib.compress(c(out))
    except TypeError as e:
        if "not callable" in str(e): sbreak = False
        else: raise
    except (ValueError) as e: print(c.__name__, "ERROR", e)
    finally: 
        if sbreak: print("=+=" * 30)        
warnings.filterwarnings("default")

Mit folgenden Ergebnissen für meinen outDatenrahmen (in Jupiter-Variable)

pyarrow before serialization 533366
pyarrow 120805
1.03 ms ± 43.9 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pyarrow zlib 20517
2.78 ms ± 81.8 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
msgpack before serialization 533366
msgpack 109039
1.74 ms ± 72.8 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
msgpack zlib 16639
3.05 ms ± 71.7 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
pickle before serialization 533366
pickle 142121
733 µs ± 38.3 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pickle zlib 29477
3.81 ms ± 60.4 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
feather ERROR feather does not support serializing a non-default index for the index; you can .reset_index() to make the index into column(s)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
parquet ERROR Nested column branch had multiple children: struct<x: double, y: double>
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=

Feder und Parkett funktionieren nicht für meinen Datenrahmen. Ich werde weiterhin Pyarrow verwenden. Ich werde jedoch mit Gurke ergänzen (keine Kompression). Speichern Sie beim Schreiben in den Cache serialisierte Formulare für Pyarrow und Pickle. Beim Lesen vom Cache-Fallback zum Pickle, wenn die Deserialisierung von Pyarrows fehlschlägt.

Rob Raymond
quelle
Dies beantwortet die Frage nicht
Jason S
0

Das Format hängt von Ihrem Anwendungsfall ab

  • Speichern Datenrahmen zwischen Notebook - Sitzungen - Feder , wenn Sie es gewohnt sind beizen - auch ok.
  • Speichern Sie DataFrame in der kleinstmöglichen Dateigröße - Parkett oder pickle.gz (prüfen Sie, was für Ihre Daten besser ist).
  • Speichern Sie einen sehr großen DataFrame (mehr als 10 Millionen Zeilen) - hdf
  • Sie können die Daten auf einer anderen Plattform (nicht Python) lesen, die keine anderen Formate unterstützt - csv , csv.gz. Überprüfen Sie, ob Parkett unterstützt wird
  • In der Lage sein, mit Ihren Augen / mit Excel / Google Sheets / Git diff - csv zu überprüfen
  • Speichern Sie einen DataFrame, der fast den gesamten RAM - csv belegt

Ein Vergleich der Pandas-Dateiformate finden Sie in diesem Video .

Artoby
quelle