Jeg bruger rutinemæssigt titusindvis af gigabyte data på netop denne måde. Jeg har tabeller på disk, som jeg læser via forespørgsler, opretter data og tilføjer tilbage.
Det er værd at læse dokumenterne og sent i denne tråd for adskillige forslag til, hvordan du gemmer dine data.
Detaljer, som vil påvirke, hvordan du gemmer dine data, såsom:
Giv så mange detaljer, som du kan; og jeg kan hjælpe dig med at udvikle en struktur.
- Størrelse af data, antal rækker, kolonner, typer af kolonner; tilføjer du rækker eller bare kolonner?
- Hvordan vil typiske operationer se ud. For eksempel. lav en forespørgsel på kolonner for at vælge en masse rækker og specifikke kolonner, foretag derefter en handling (i hukommelsen), opret nye kolonner, gem disse.
(Hvis du giver et legetøjseksempel, kan vi give mere specifikke anbefalinger. ) - Hvad gør du så efter den behandling? Kan trin 2 ad hoc eller gentages?
- Indtast flade filer:hvor mange, grov samlet størrelse i Gb. Hvordan er disse organiseret f.eks. efter optegnelser? Indeholder hver enkelt felter forskellige, eller har de nogle poster pr. fil med alle felterne i hver fil?
- Vælger du nogensinde undersæt af rækker (poster) baseret på kriterier (vælg f.eks. rækkerne med felt A> 5)? og så gør noget, eller vælger du bare felterne A, B, C med alle posterne (og gør så noget)?
- Arbejder du på alle dine kolonner (i grupper), eller er der en god del, som du kun må bruge til rapporter (f.eks. vil du beholde dataene, men behøver ikke at trække det ind kolonneeksplicit indtil det endelige resultattidspunkt)?
Løsning
Sørg for, at du mindst har pandaer 0.10.1
installeret.
Læs itererende filer stykke for stykke og flere tabelforespørgsler.
Da pytables er optimeret til at fungere på rækkevis (hvilket er det, du forespørger på), vil vi oprette en tabel for hver gruppe af felter. På denne måde er det nemt at vælge en lille gruppe af felter (som vil fungere med en stor tabel, men det er mere effektivt at gøre det på denne måde... Jeg tror, jeg kan være i stand til at rette denne begrænsning i fremtiden... dette er mere intuitiv alligevel):
(Det følgende er pseudokode.)
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æsning af filerne og oprettelse af lageret (i det væsentlige gør hvad 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 alle tabellerne i filen (faktisk kan du gemme dem i separate filer, hvis du ønsker det, du ville sandsynligvis skulle tilføje filnavnet til group_map, men det er sandsynligvis ikke nødvendigt).
Sådan får du kolonner og opretter nye:
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 er klar til 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 faktisk ikke at definere ENHVER data_kolonner; de giver dig mulighed for at undervælge rækker baseret på kolonnen. For eksempel. noget som:
store.select(group, where = ['field_1000=foo', 'field_1001>0'])
De kan være mest interessante for dig i den endelige rapportgenereringsfase (i det væsentlige er en datakolonne adskilt fra andre kolonner, hvilket kan påvirke effektiviteten noget, hvis du definerer meget).
Du vil måske også:
- opret en funktion, som tager en liste over felter, slår grupperne op i grupper_kortet, vælger disse og sammenkæder resultaterne, så du får den resulterende ramme (dette er i bund og grund, hvad select_as_multiple gør). På denne måde ville strukturen være ret gennemsigtig for dig.
- indekserer på bestemte datakolonner (gør underindstilling af rækker meget hurtigere).
- aktiver komprimering.
Sig til, når du har spørgsmål!