Export in CSV Datei sehr langsam

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
pythondata
User
Beiträge: 3
Registriert: Donnerstag 10. Oktober 2019, 10:52

Guten Tag,

ich versuche einen DataFrame mit ca. 30 Mio Datensätzen in eine CSV zu exportieren. Das funktioniert auch, ist aber extrem langsam.

Die Anwendung selbst läuft in 2 Min durch und bereitet Daten auf, das bringt mir aber wenig wenn der Export danach 30 Minuten dauert.
Ist das richtig so, oder was gäbe es für Alternativen?

Der DataFrame hat 5 Spalten.
Die Funktion für den Export:
export_csv = df.to_csv (r'test.csv', index = None, header=True, chunksize = 100000)
Die chunksize habe ich schon variiert, da gibt es jedoch wenig Unterschiede.
Die Anwendung läuft auf meinem Lokalen PC mit 4 CPU und 32 GB Arbeitsspeicher.

Hat da jemand Erfahrungen mit wie ich die Daten aus Python performant herausbekomme?

Vielen Dank!
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also wenn ich mich da nicht verrechnet habe, dann kommst du bei den Zahlen auf ~60 uS / Datensatz. Da das ein Bereich ist, in dem zB Betriebssystem-aufrufe liegen, von denen ja zumindestens *einer* stattfinden muss (write) - dann wird das IMHO eng, das zu optimieren. Wie gross ist denn eine Zeile des Frames?

Anzahl der CPUs und Arbeitsspeicher sind in diesem Zusammenhang im uebrigen eher irrelevant. Schreiben kann immer nur einer, und was schon im Speicher ist, muss da ja nicht nochmal rein.
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich muss mich korrigieren, den write-Aufruf muss man natuerlich nur einmal pro Chunk machen. Trotzdem sind 60uS pro Datensatz nicht viel.
pythondata
User
Beiträge: 3
Registriert: Donnerstag 10. Oktober 2019, 10:52

Hallo,

vielen Dank für die schnelle Antwort!

In einer Zeile stehen 3 Zahlen mit ca. 20 Zeilen, ein Datum und zwei "Komma"-Zahlen.
Oder was meinst Du mit der Größe einer Zeile des Frames?
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

So, ich habe mal rumgespielt, und komme bei einem simplen Testbeispiel das Daten faked auf deutlich geringere Werte. Irgendwas ist da also durchaus komisch.

Code: Alles auswählen

import time


def timed(f):
    def _d(*a, **k):
        start = time.monotonic()
        try:
            return f(*a, **k)
        finally:
            print(f, time.monotonic() - start)
    return _d


@timed
def generate_data():
    return [f"{i} row of juicy data" for i in range(30_000_000)]


@timed
def write_data(outf, data, blocksize=10000):
    count = 0
    buffer = []

    def do_write():
        outf.write(b"".join(buffer))
        buffer.clear()

    for line in data:
        count += len(line)
        buffer.append(line.encode("ascii"))
        if count >= blocksize:
            do_write()
            count = 0

    do_write()


def main():
    data = generate_data()
    with open("/tmp/test.data", "wb") as outf:
        write_data(outf, data)


if __name__ == '__main__':
    main()
Da sind's bei mir ~7 Sekunden zum speichern von ~700MB. Mein System hat allerdings auch eine NVME-ssd und ist ein Ryzen Threadripper.

Der MacPro ist (wie generell) doppelt so langsam.

Pandas macht ja sehr viel, vielleicht verschwendet es viel Zeit beim aufbereiten der Daten. Darum nochmal die Frage: wie genau sehen die aus?
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Deine Beschreibung der Daten ist mir unklar. Wie kann in einer Zeile etwas mit 20 Zeilen stehen?
pythondata
User
Beiträge: 3
Registriert: Donnerstag 10. Oktober 2019, 10:52

Hallo zusammen,

sorry, da habe ich mich verschrieben, ich meinte 3 Zahlen mit 20 Zeichen!?! :-)
Eine Zeile sieht so aus, sind gar keine 20 Zeichen in den ersten 3 Spalten:

Col 1 Col 2 Col 3 Date V1 V2
16100000 27100000 1000 01.01.2019 50 -40

(einmal untereinander für die bessere Lesbarkeit)
Col 1: 16100000
Col 2: 27100000
Col 3: 1000
Date: 01.01.2019
V1: 50
V2:-40

und davon eben 86 Mio Zeilen.
Die CSV davon ist ca. 6 GB groß.
Das sollte ja nicht mehr als 1-2 Min dauern, zumindest in anderen ETL Tools geht genau dieser Vorgang problemlos schnell.

Wie lange dürfte das dauern?
Oder liegt das an der Visual Studio Code Umgebung in der ich das laufen lasse, und es geht per Kommandozeile schneller?
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Einen Einfluss von VS Code wuerde ich erstmal aussschliessen. Das Verdachtsmoment ist ganz klar die Datumsspalte. Probier mal, die aus dem Frame vorher rauszukicken, und dann zu serialisieren. Mir ist klar das du das ultimativ nicht brauchen kannst, aber es geht darum, die Hypothese mal zu testen.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

pythondata hat geschrieben: Donnerstag 10. Oktober 2019, 11:24 In einer Zeile stehen 3 Zahlen mit ca. 20 Zeilen, ein Datum und zwei "Komma"-Zahlen.
Ich kann das selbst nicht testen, aber laut diesem Beitrag braucht to_csv() deutlich länger, wenn Date und/oder Time Typen vorkommen, was ja durch das Datum bei dir anscheinend der Fall ist. Dort wird empfohlen, dass man die betreffende Spalte vorher in einen String umwandeln soll. Vielleicht willst du das auch mal probieren...?
Antworten