[Python-Leipzig] Pandas unter 7 Minuten!

Mike Müller mmueller at python-academy.de
Do Aug 13 21:31:59 UTC 2015


Hallo,

wir versprochen hier die Fortsetzung vom Dienstag.

Die Pandas-Version ist mit Abstand die schnellste und kann auch helfen
Speicher zu sparen. Ich habe die Input-Dateien immer wieder gelesen, so dass
diese wohl vom Betriebssystem im Cache gehalten werden.

Beim Einlesen aller Gebiete auf einmal braucht das Programm ca. 6,5 Minuten
bei etwas über 4 GB Speichernutzung. Bei einer Batch-Größe von 4.000, d.h.
bei den etwas über 16.000 Gebieten 5 mal teilweise lesen, steigt die Zeit
auf ca. 7,5 Minuten. Das Programm braucht dann aber nur etwas mehr als
1 GB Speicher.

Hier der relevante Code:

def add_input_tables_pandas(h5_file_name, t_file_name, p_file_name,
                            q_file_name, batch_size=None, total=365*24):
    """Add input with pandas.
    """
    # Option um Datei zu komprimieren.
    filters = tables.Filters(complevel=5, complib='zlib')
    # Datei anlegen.
    h5_file = tables.open_file(h5_file_name, mode='a')
    get_child = h5_file.root._f_get_child
    all_ids = ids = find_ids(h5_file)
    # usecols erlaubt nur bestimmte Spalten aus einer Datei zu lesen.
    usecols = None
    # Ein paar vorbereitende Schritte.
    if batch_size is None:
        batch_size = sys.maxsize
    if batch_size < len(all_ids):
        usecols = True
    counter = 0
    total_ids = len(all_ids)
    # Schleife über alle Gebiete.
    while all_ids:
        # IDs für Batch auswählen. Wenn der Batch größer als die Gesamtanzahl
        # ist, sind das alle.
        ids = all_ids[-batch_size:]
        all_ids = all_ids[:-batch_size]
        if usecols:
            usecols = ids
        # Pandas in Aktion.
        temp = pandas.read_csv(t_file_name, sep=';', parse_dates=True,
                               usecols=usecols)
        precip = pandas.read_csv(p_file_name, sep=';', parse_dates=True,
                                 usecols=usecols)
        dis = pandas.read_csv(q_file_name, sep=';', parse_dates=True,
                              usecols=usecols)
        # Tageswerte auf Stundenwerte auffüllen.
        temp_hourly = temp.reindex(dis.index, method='ffill')
        # Nun in HDF5 schreiben.
        for id_ in ids:
            counter += 1
            # Tabelle mit drei Spalten mit je einer Spalte aus drei
            # Tabellen zusammenbauen.
            inputs = pandas.concat([temp_hourly[id_], precip[id_], dis[id_]],
                                   axis=1)
            inputs.columns = ['temperature', 'precipitation', 'discharge']
            # Record-Arrays lassen sich in einem Schritt in HDF5 schreiben.
            input_table = inputs.to_records(index=False)
            name = 'catch_{}'.format(id_)
            group = get_child(name)
            h5_file.create_table(group, 'inputs', input_table,
                                 'time varying inputs', expectedrows=total,
                                 filters=filters)
    # Zeitschritte gibt es nur einmal, da gleich für alle ids.
    int_steps = pandas.DataFrame(dis.index.to_series()).astype(numpy.int64)
    int_steps.columns = ['timesteps']
    time_steps = int_steps.to_records(index=False)
    h5_file.create_table('/', 'time_steps', time_steps,
                         'time steps for all catchments')
    h5_file.close()
    # Das war es schon.

Damit ist der gesamte CVS-Reader mit dem __next__ überflüssig.
Der Quelltext ist also auch viel kürzer.

@Arnold: Ob eine In-PostgreSQL-Importieren-Variante noch schneller sein
könnte. ;)

Viele Grüße
Mike


Am 12.08.15 um 08:00 schrieb Mike Müller:
> Hallo zusammen,
> 
> nach der doch sehr anregenden Diskussion bei unserem Treffen gestern, habe
> ich mich an eine Pandas-Version gemacht. Bei etwas über 4 GB Speicherbedarf
> war die Sache in weniger als 7 Minuten erledigt. Das ist nochmal dreimal
> schneller als meine NumPy-Variante mit den Python-Schleifen. Ich werde auch
> noch eine Pandas-Version mit stückweiser Verarbeitung bauen. Ich schicke die
> Quelltexte dann hier auf die Liste.
> 
> Viele Grüße
> Mike
> 
> _______________________________________________
> Python-Leipzig mailing list
> Python-Leipzig at python.net
> http://starship.python.net/mailman/listinfo/python-leipzig
> 
> Website der Leipzig Python User Group:
> http://www.python-academy.de/User-Group/
> 




Mehr Informationen über die Mailingliste Python-Leipzig