Jag använder rutinmässigt tiotals gigabyte data på just detta sätt. Jag har tabeller på disk som jag läser via frågor, skapar data och lägger tillbaka.
Det är värt att läsa dokumenten och sent i den här tråden för flera förslag på hur du lagrar din data.
Detaljer som kommer att påverka hur du lagrar din data, som:
Ge så mycket detaljer du kan; och jag kan hjälpa dig att utveckla en struktur.
- Storlek på data, antal rader, kolumner, typer av kolumner; lägger du till rader eller bara kolumner?
- Hur kommer typiska operationer att se ut. T.ex. gör en fråga på kolumner för att välja ett gäng rader och specifika kolumner, gör sedan en operation (i minnet), skapa nya kolumner, spara dessa.
(Om du ger ett leksaksexempel kan vi ge mer specifika rekommendationer. ) - Vad gör du efter den bearbetningen? Är steg 2 ad hoc eller repeterbart?
- Inmatning av platta filer:hur många, grov total storlek i Gb. Hur är dessa organiserade t.ex. av register? Innehåller var och en olika fält, eller har de några poster per fil med alla fält i varje fil?
- Väljer du någonsin delmängder av rader (poster) baserat på kriterier (t.ex. välj raderna med fält A> 5)? och gör sedan något, eller väljer du bara fält A, B, C med alla poster (och gör sedan något)?
- Arbetar du med alla dina kolumner (i grupper) eller finns det en bra andel som du bara kan använda för rapporter (t.ex. vill du behålla informationen men behöver inte dra in den kolumn explicit fram till slutresultatet)?
Lösning
Se till att du har pandor minst 0.10.1
installerat.
Läs itererande filer bit för bit och flera tabellfrågor.
Eftersom pytables är optimerat för att arbeta på radvis (vilket är vad du frågar efter), kommer vi att skapa en tabell för varje grupp av fält. På så sätt är det lätt att välja en liten grupp av fält (som kommer att fungera med en stor tabell, men det är mer effektivt att göra det på det här sättet... Jag tror att jag kanske kan fixa den här begränsningen i framtiden... det här är mer intuitivt i alla fall):
(Följande är pseudokod.)
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'] ]))
Läser in filerna och skapar lagringen (gör i huvudsak vad append_to_multiple
gör):
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'])
Nu har du alla tabeller i filen (du kan faktiskt lagra dem i separata filer om du vill, du skulle förmodligen behöva lägga till filnamnet till group_map, men förmodligen är detta inte nödvändigt).
Så här får du kolumner och skapar nya:
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)
När du är redo för efterbehandling:
# 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)
Om data_columns behöver du faktiskt inte definiera NÅGON data_kolumner; de låter dig undermarkera rader baserat på kolumnen. T.ex. något som:
store.select(group, where = ['field_1000=foo', 'field_1001>0'])
De kan vara mest intressanta för dig i det slutliga rapportgenereringsskedet (i huvudsak är en datakolumn separerad från andra kolumner, vilket kan påverka effektiviteten något om du definierar mycket).
Du kanske också vill:
- skapa en funktion som tar en lista med fält, slår upp grupperna i groups_map, väljer sedan dessa och sammanfogar resultaten så att du får den resulterande ramen (detta är i huvudsak vad select_as_multiple gör). På detta sätt skulle strukturen vara ganska transparent för dig.
- indexerar på vissa datakolumner (gör radunderställning mycket snabbare).
- aktivera komprimering.
Meddela mig när du har frågor!