Běžně používám desítky gigabajtů dat právě tímto způsobem, např. Mám na disku tabulky, které čtu pomocí dotazů, vytvářím data a připojuji zpět.
Stojí za to si přečíst dokumenty a na konci tohoto vlákna, kde najdete několik návrhů, jak ukládat data.
Podrobnosti, které ovlivní způsob ukládání dat, jako:
Uveďte co nejvíce podrobností; a mohu vám pomoci vytvořit strukturu.
- velikost dat, počet řádků, sloupců, typy sloupců; připojujete řádky, nebo jen sloupce?
- Jak budou vypadat typické operace. Např. proveďte dotaz na sloupce, abyste vybrali spoustu řádků a konkrétních sloupců, pak proveďte operaci (v paměti), vytvořte nové sloupce a uložte je.
(Uvedení příkladu hraček by nám mohlo umožnit nabídnout konkrétnější doporučení. ) - Co uděláte po tomto zpracování? Je krok 2 ad hoc nebo opakovatelný?
- Vstupní ploché soubory:kolik, přibližná celková velikost v Gb. Jak jsou tyto organizovány např. podle záznamů? Obsahuje každá jiná pole, nebo mají nějaké záznamy na soubor se všemi poli v každém souboru?
- Vybíráte někdy podmnožiny řádků (záznamů) na základě kritérií (např. vybíráte řádky s polem A> 5)? a pak něco udělat, nebo prostě vyberete pole A, B, C se všemi záznamy (a pak něco uděláte)?
- Pracujete na všech svých sloupcích (ve skupinách), nebo existuje dobrý podíl, který můžete použít pouze pro přehledy (např. chcete data ponechat, ale nemusíte je stahovat sloupec explicitně až do času konečných výsledků)?
Řešení
Ujistěte se, že máte pandy alespoň 0.10.1
nainstalován.
Číst iterující soubory po částech a dotazy na více tabulek.
Vzhledem k tomu, že pytables je optimalizován pro provoz po řádcích (což je to, na co se dotazujete), vytvoříme tabulku pro každou skupinu polí. Tímto způsobem je snadné vybrat malou skupinu polí (která bude fungovat s velkou tabulkou, ale je efektivnější to udělat tímto způsobem... Myslím, že toto omezení možná budu moci v budoucnu opravit... toto je každopádně intuitivnější):
(Následující je pseudokód.)
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'] ]))
Čtení souborů a vytváření úložiště (v podstatě dělá to, co append_to_multiple
dělá):
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'])
Nyní máte všechny tabulky v souboru (ve skutečnosti je můžete uložit do samostatných souborů, pokud chcete, pravděpodobně byste museli přidat název souboru do group_map, ale pravděpodobně to není nutné).
Takto získáte sloupce a vytvoříte nové:
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)
Až budete připraveni na následné zpracování:
# 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)
Pokud jde o data_columns, ve skutečnosti nemusíte definovat ANY datové_sloupce; umožňují podvýběr řádků na základě sloupce. Např. něco jako:
store.select(group, where = ['field_1000=foo', 'field_1001>0'])
Nejzajímavější pro vás mohou být ve fázi generování závěrečné zprávy (v podstatě je datový sloupec oddělen od ostatních sloupců, což může poněkud ovlivnit efektivitu, pokud hodně definujete).
Můžete také chtít:
- vytvořte funkci, která vezme seznam polí, vyhledá skupiny v mapě skupin, poté je vybere a zřetězí výsledky, abyste získali výsledný snímek (to je v podstatě to, co select_as_multiple dělá). Tímto způsobem by pro vás byla struktura docela transparentní.
- indexuje určité datové sloupce (mnohem rychlejší je podmnožina řádků).
- povolit kompresi.
Dejte mi vědět, až budete mít otázky!