MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Große Datenworkflows mit Pandas

Ich verwende routinemäßig Dutzende von Gigabyte an Daten auf genau diese Weise, z. Ich habe Tabellen auf der Festplatte, die ich über Abfragen lese, Daten erstelle und wieder anhänge.

Es lohnt sich, die Dokumentation und später in diesem Thread einige Vorschläge zum Speichern Ihrer Daten zu lesen.

Details, die sich darauf auswirken, wie Sie Ihre Daten speichern, wie:
Geben Sie so viele Details wie möglich an; und ich kann Ihnen helfen, eine Struktur zu entwickeln.

  1. Datengröße, Anzahl Zeilen, Spalten, Spaltentypen; hängen Sie Zeilen oder nur Spalten an?
  2. Wie werden typische Operationen aussehen? Z.B. Führen Sie eine Spaltenabfrage durch, um eine Reihe von Zeilen und bestimmte Spalten auszuwählen, führen Sie dann eine Operation (im Speicher) durch, erstellen Sie neue Spalten und speichern Sie diese.
    (Ein Spielzeugbeispiel könnte es uns ermöglichen, spezifischere Empfehlungen zu geben. )
  3. Was machen Sie nach dieser Verarbeitung? Ist Schritt 2 ad hoc oder wiederholbar?
  4. Flatfiles eingeben:wie viele, ungefähre Gesamtgröße in GB. Wie sind diese organisiert, z. nach Aufzeichnungen? Enthält jeder unterschiedliche Felder oder haben sie einige Datensätze pro Datei mit allen Feldern in jeder Datei?
  5. Wählen Sie jemals Teilmengen von Zeilen (Datensätzen) basierend auf Kriterien aus (wählen Sie z. B. die Zeilen mit Feld A> 5 aus)? und dann etwas tun, oder wählen Sie einfach die Felder A, B, C mit allen Datensätzen aus (und dann etwas tun)?
  6. Arbeiten Sie an allen Ihren Spalten (in Gruppen) oder gibt es einen guten Teil, den Sie nur für Berichte verwenden können (z Spalte explizit bis zum endgültigen Ergebniszeitpunkt)?

Lösung

Stellen Sie sicher, dass Sie Pandas mindestens 0.10.1 haben installiert.

Iterierende Dateien Stück für Stück und mehrere Tabellenabfragen lesen.

Da pytables für den zeilenweisen Betrieb optimiert ist (was Sie abfragen), erstellen wir eine Tabelle für jede Gruppe von Feldern. Auf diese Weise ist es einfach, eine kleine Gruppe von Feldern auszuwählen (was mit einer großen Tabelle funktioniert, aber es ist effizienter, dies auf diese Weise zu tun ... Ich denke, ich kann diese Einschränkung in Zukunft beheben ... das ist sowieso intuitiver):
(Das Folgende ist Pseudocode.)

import numpy as np
import pandas as pd

# create a store
store = pd.HDFStore('mystore.h5')

# this is the key to your storage:
#    this maps your fields to a specific group, and defines 
#    what you want to have as data_columns.
#    you might want to create a nice class wrapping this
#    (as you will want to have this map and its inversion)  
group_map = dict(
    A = dict(fields = ['field_1','field_2',.....], dc = ['field_1',....,'field_5']),
    B = dict(fields = ['field_10',......        ], dc = ['field_10']),
    .....
    REPORTING_ONLY = dict(fields = ['field_1000','field_1001',...], dc = []),

)

group_map_inverted = dict()
for g, v in group_map.items():
    group_map_inverted.update(dict([ (f,g) for f in v['fields'] ]))

Einlesen der Dateien und Erstellen des Speichers (im Wesentlichen tun, was append_to_multiple tut):

for f in files:
   # read in the file, additional options may be necessary here
   # the chunksize is not strictly necessary, you may be able to slurp each 
   # file into memory in which case just eliminate this part of the loop 
   # (you can also change chunksize if necessary)
   for chunk in pd.read_table(f, chunksize=50000):
       # we are going to append to each table by group
       # we are not going to create indexes at this time
       # but we *ARE* going to create (some) data_columns

       # figure out the field groupings
       for g, v in group_map.items():
             # create the frame for this group
             frame = chunk.reindex(columns = v['fields'], copy = False)    

             # append it
             store.append(g, frame, index=False, data_columns = v['dc'])

Jetzt haben Sie alle Tabellen in der Datei (eigentlich könnten Sie sie in separaten Dateien speichern, wenn Sie möchten, Sie müssten wahrscheinlich den Dateinamen zur group_map hinzufügen, aber wahrscheinlich ist dies nicht notwendig).

So erhalten Sie Spalten und erstellen neue:

frame = store.select(group_that_I_want)
# you can optionally specify:
# columns = a list of the columns IN THAT GROUP (if you wanted to
#     select only say 3 out of the 20 columns in this sub-table)
# and a where clause if you want a subset of the rows

# do calculations on this frame
new_frame = cool_function_on_frame(frame)

# to 'add columns', create a new group (you probably want to
# limit the columns in this new_group to be only NEW ones
# (e.g. so you don't overlap from the other tables)
# add this info to the group_map
store.append(new_group, new_frame.reindex(columns = new_columns_created, copy = False), data_columns = new_columns_created)

Wenn Sie für die Nachbearbeitung bereit sind:

# This may be a bit tricky; and depends what you are actually doing.
# I may need to modify this function to be a bit more general:
report_data = store.select_as_multiple([groups_1,groups_2,.....], where =['field_1>0', 'field_1000=foo'], selector = group_1)

Über data_columns müssen Sie eigentlich ANY nicht definieren Datenspalten; Sie ermöglichen es Ihnen, Zeilen basierend auf der Spalte auszuwählen. Z.B. etwas wie:

store.select(group, where = ['field_1000=foo', 'field_1001>0'])

Sie könnten für Sie in der abschließenden Phase der Berichterstellung am interessantesten sein (im Wesentlichen wird eine Datenspalte von anderen Spalten getrennt, was die Effizienz etwas beeinträchtigen kann, wenn Sie viel definieren).

Vielleicht möchten Sie auch:

  • Erstellen Sie eine Funktion, die eine Liste von Feldern nimmt, die Gruppen in der groups_map nachschlägt, diese dann auswählt und die Ergebnisse verkettet, sodass Sie den resultierenden Frame erhalten (dies ist im Wesentlichen das, was select_as_multiple tut). Auf diese Weise wäre die Struktur für Sie ziemlich transparent.
  • indiziert bestimmte Datenspalten (beschleunigt die Unterteilung von Zeilen erheblich).
  • Komprimierung aktivieren.

Lassen Sie mich wissen, wenn Sie Fragen haben!