2012-08-22 14 views
10

Sto provando a lavorare con dati da file netCDF molto grandi (~ 400 GB ciascuno). Ogni file ha alcune variabili, tutte molto più grandi della memoria di sistema (ad esempio 180 Gb vs 32 Gb RAM). Sto cercando di usare numpy e netCDF4-python per fare alcune operazioni su queste variabili copiando una slice alla volta e operando su quella slice. Sfortunatamente, ci vuole molto tempo solo per leggere ogni sezione, che sta uccidendo la performance.Gestione di file netCDF molto grandi in python

Ad esempio, una delle variabili è una matrice di forma (500, 500, 450, 300). Voglio operare sulla fetta [:,:,0], così faccio la seguente:

import netCDF4 as nc 

f = nc.Dataset('myfile.ncdf','r+') 
myvar = f.variables['myvar'] 
myslice = myvar[:,:,0] 

Ma l'ultimo passaggio richiede un tempo molto lungo (~ 5 min sul mio sistema). Se ad esempio ho salvato una variabile di forma (500, 500, 300) nel file netcdf, un'operazione di lettura della stessa dimensione richiederà solo pochi secondi.

C'è un modo per accelerare? Un percorso ovvio sarebbe quello di trasporre la matrice in modo che gli indici che sto selezionando emergessero per primi. Ma in un file così grande non sarebbe possibile farlo in memoria, e sembra ancora più lento tentare, visto che un'operazione semplice richiede già molto tempo. Quello che mi piacerebbe è un modo rapido per leggere una porzione di un file netcdf, nel modo in cui la funzione get_vara dell'interfaccia di Fortran. O un modo per trasporre efficacemente la matrice.

+1

Se vuoi fare di più con i dati che semplicemente trasponendoli, dai un'occhiata al modulo ['xarray'] (http://xarray.pydata.org/en/stable/): Fornisce un ottimo interfaccia a ['dask'] (http://dask.pydata.org/en/latest/) array di memoria esaurita. – j08lue

risposta

7

È possibile trasporre variabili netCDF troppo grande per entrare in memoria utilizzando l'utilità nccopy, che è documentata qui:

http://www.unidata.ucar.edu/netcdf/docs/guide_nccopy.html

L'idea è quella di "rechunk" il file specificando quali forme dei pezzi (tessere multidimensionali) che si desidera per le variabili. È possibile specificare la quantità di memoria da utilizzare come buffer e quanto utilizzare per le porzioni di blocchi nella quantità di , ma non è chiaro come utilizzare la memoria in modo ottimale tra questi usi, pertanto è possibile che si debba semplicemente provare alcuni esempi e cronometrare. Anziché trasporre completamente una variabile, probabilmente si desidera "trasporla parzialmente", specificando blocchi che hanno molti dati lungo le 2 grandi dimensioni della propria sezione e che hanno solo pochi valori lungo le altre dimensioni.

+0

Grazie Russ per la tua risposta. E 'stato molto interessante visto che non ho mai guardato molto nel chunking. Supponendo che ho una variabile con dimensioni (500, 500, 300, 400). Se faccio un chunking di 1 sulla terza dimensione, è analogo fare una trasposizione parziale in cui quell'asse è il più veloce (cioè contiguo)? Ho cambiato il chunking sull'asse che stavo per leggere di più, ma ci vuole ancora molto tempo solo per ottenere una fetta 3D. Indagherò se si tratta di un problema di filesystem/rete. – tiago

+0

No, la lunghezza del blocco nella terza dimensione 1 rende quella dimensione più lenta, poiché si accede a un blocco da 400 MB per ciascun valore a 4 byte durante la lettura lungo quella dimensione. Ma se si utilizzavano 10 blocchi lungo ogni dimensione (ogni blocco 50x40x30x40), ogni blocco comprendeva circa 12 MB (supponendo 4 byte per valore) e sarebbero necessari solo 10 letture per accedere a un "cilindro" di valori lungo qualsiasi dimensione (a 50x50x30x40 pezzo). Per un esempio di come questo può migliorare i tempi di accesso in alcune direzioni, vedere le 2 diapositive: http://www.unidata.ucar.edu/netcdf/workshops/2011/chunk_cache/Problem.html –

+0

Correzione del commento sopra: sostituire " (un pezzo 50x50x30x40) "con" (10 pezzi 50x50x30x40) "... –

3

Questo è un commento, non una risposta, ma non posso commentare quanto sopra, mi spiace.

Capisco che si desidera elaborare myvar[:,:,i], con i in range(450). In tal caso, si sta andando a fare qualcosa di simile:

for i in range(450): 
    myslice = myvar[:,:,i] 
    do_something(slice) 

e il collo di bottiglia è nell'accesso myslice = myvar[:,:,i]. Hai provato a confrontare il tempo necessario per accedere a moreslices = myvar[:,:,0:n]? Sarebbe contiguos data, e forse si può risparmiare tempo con quello. Dovresti scegliere n grande quanto la tua memoria lo offre, quindi elaborare il prossimo pezzo di dati moreslices = myvar[:,:,n:2n] e così via.

+0

Grazie per la risposta. Ho paragonato l'accesso a 'myvar [:,:, 0: n]' e richiede all'incirca lo stesso tempo di 'myvar [:,:, 0]'. Quindi questo è almeno un modo, ma sto ancora cercando di scoprire perché c'è una tale penalità per iniziare. Si noti che 'myvar [:,:, 0: n]' non è contiguo. – tiago

+0

Bene, è vero che 'myvar [1,0,0]' non è contiguo a 'myvar [2,0,0]'.Ma ci vuole circa allo stesso tempo perché 'myvar [i, i, 0]' è in realtà contigua a 'myvar [i, i, 1]'. Ha più senso ora? – gg349

Problemi correlati