sql >> Database >  >> NoSQL >> MongoDB

Grote gegevensworkflows met panda's

Ik gebruik routinematig tientallen gigabytes aan gegevens op precies deze manier. Ik heb tabellen op schijf die ik lees via query's, gegevens creëer en weer toevoeg.

Het is de moeite waard om de documenten te lezen en laat in deze thread voor verschillende suggesties voor het opslaan van uw gegevens.

Details die van invloed zijn op hoe u uw gegevens opslaat, zoals:
Geef zoveel mogelijk details; en ik kan je helpen een structuur te ontwikkelen.

  1. Grootte van gegevens, # rijen, kolommen, typen kolommen; voeg je rijen toe, of alleen kolommen?
  2. Hoe zullen typische bewerkingen eruit zien. bijv. voer een query uit op kolommen om een ​​aantal rijen en specifieke kolommen te selecteren, voer vervolgens een bewerking uit (in het geheugen), maak nieuwe kolommen en sla deze op.
    (Door een speelgoedvoorbeeld te geven, kunnen we meer specifieke aanbevelingen doen. )
  3. Wat doe je na die verwerking? Is stap 2 ad hoc of herhaalbaar?
  4. Invoer platte bestanden:hoeveel, ruwe totale grootte in Gb. Hoe zijn deze georganiseerd b.v. door records? Bevat elk veld verschillende velden, of hebben ze een aantal records per bestand met alle velden in elk bestand?
  5. Selecteer je ooit subsets van rijen (records) op basis van criteria (bijvoorbeeld de rijen selecteren met veld A> 5)? en doe dan iets, of selecteer je gewoon de velden A, B, C met alle records (en doe je dan iets)?
  6. Werkt u aan al uw kolommen (in groepen), of is er een goede verhouding die u alleen voor rapporten mag gebruiken (u wilt bijvoorbeeld de gegevens behouden, maar hoeft dat niet in te voeren kolom expliciet tot eindresultaten tijd)?

Oplossing

Zorg dat je minimaal 0.10.1 panda's hebt geïnstalleerd.

Lees itererende bestanden stuk voor stuk en meerdere tabelquery's.

Omdat pytables is geoptimaliseerd om rijgewijs te werken (dat is waar u op zoekt), zullen we een tabel maken voor elke groep velden. Op deze manier is het gemakkelijk om een ​​kleine groep velden te selecteren (wat zal werken met een grote tabel, maar het is efficiënter om het op deze manier te doen... Ik denk dat ik deze beperking in de toekomst kan oplossen... dit is hoe dan ook intuïtiever):
(Het volgende is 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'] ]))

De bestanden inlezen en de opslag maken (in wezen doen wat append_to_multiple doet):

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 heb je alle tabellen in het bestand (je zou ze desgewenst in aparte bestanden kunnen opslaan, je zou waarschijnlijk de bestandsnaam aan de group_map moeten toevoegen, maar waarschijnlijk is dit niet nodig).

Zo krijgt u kolommen en maakt u nieuwe:

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)

Wanneer u klaar bent voor post_processing:

# 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)

Over data_columns, u hoeft ANY eigenlijk niet te definiëren data_kolommen; hiermee kunt u rijen subselecteren op basis van de kolom. bijv. zoiets als:

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

Ze zijn misschien het meest interessant voor u in de fase van het genereren van het definitieve rapport (in wezen is een gegevenskolom gescheiden van andere kolommen, wat de efficiëntie enigszins kan beïnvloeden als u veel definieert).

Misschien wil je ook:

  • maak een functie die een lijst met velden nodig heeft, de groepen opzoekt in de groups_map, deze selecteert en de resultaten samenvoegt zodat je het resulterende frame krijgt (dit is in wezen wat select_as_multiple doet). Op deze manier zou de structuur behoorlijk transparant voor je zijn.
  • indexeert op bepaalde gegevenskolommen (maakt het instellen van rijen veel sneller).
  • compressie inschakelen.

Laat het me weten als je vragen hebt!



  1. Hoe kan ik wachten tot een docker-container operationeel is?

  2. Veldfout in object 'doel' op veld '':afgewezen waarde []; codes [typeMismatch.target.,typeMismatch.,typeMismatch.java.util.Date,typeMismatch]

  3. redis:teller elke dag resetten

  4. Laravel Socket.io Verbonden maar geen gegevens ontvangen