2012-08-22 39 views
10

Estoy tratando de trabajar con datos de archivos netCDF muy grandes (~ 400 Gb cada uno). Cada archivo tiene algunas variables, todas mucho más grandes que la memoria del sistema (por ejemplo, 180 Gb frente a 32 Gb de RAM). Estoy tratando de usar numpy y netCDF4-python hacer algunas operaciones en estas variables copiando un segmento a la vez y operando en ese segmento. Desafortunadamente, está tomando mucho tiempo leer cada porción, lo que está acabando con el rendimiento.Manejo de archivos netCDF muy grandes en python

Por ejemplo, una de las variables es una matriz de forma (500, 500, 450, 300). Quiero operar en el segmento de [:,:,0], así que hacer lo siguiente:

import netCDF4 as nc 

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

Pero el último paso lleva un tiempo muy largo (~ 5 min en mi sistema). Si, por ejemplo, guardé una variable de forma (500, 500, 300) en el archivo netcdf, entonces una operación de lectura del mismo tamaño tomará solo unos segundos.

¿Hay alguna manera de acelerar esto? Una ruta obvia sería transponer la matriz de modo que los índices que estoy seleccionando salgan primero. Pero en un archivo tan grande no sería posible hacerlo en la memoria, y parece incluso más lento intentarlo dado que una operación simple ya lleva mucho tiempo. Lo que me gustaría es una forma rápida de leer una porción de un archivo netcdf, a la manera de la función get_vara de la interfaz de Fortran. O alguna forma de transposición eficiente de la matriz.

+1

Si desea hacer más con los datos que simplemente transponerlo, eche un vistazo al módulo ['xarray'] (http://xarray.pydata.org/en/stable/): Proporciona un muy buen interfaz a ['dask'] (http://dask.pydata.org/en/latest/) matrices fuera de memoria. – j08lue

Respuesta

7

Puede transportar las variables netCDF demasiado grande para caber en la memoria mediante la utilidad nccopy, que se documenta aquí:

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

La idea es "rechunk" el archivo especificando qué formas de trozos (mosaicos multidimensionales) que desea para las variables. Puede especificar cuánta memoria usar como un búfer y cuánto usar para cachés de fragmentos, pero no está claro cómo utilizar la memoria de manera óptima entre estos usos, por lo que puede tener que probar algunos ejemplos y medir el tiempo. En lugar de transponer por completo una variable, , es probable que desee "transponerla parcialmente", especificando trozos que tienen una gran cantidad de datos a lo largo de las 2 dimensiones grandes de su sector y que tienen solo unos pocos valores a lo largo de las otras dimensiones.

+0

Gracias Russ por su respuesta. Fue muy interesante ya que nunca miré mucho en la fragmentación. Suponiendo que tengo una variable con dimensiones (500, 500, 300, 400). Si hago un agrupamiento de 1 en la tercera dimensión, ¿esto es análogo a hacer una transposición parcial donde ese eje es el más rápido uno (es decir, contiguo)? Cambié la división en el eje en el que iba a leer más, pero aún me lleva mucho tiempo obtener un corte en 3D. Investigaré si esto es un problema de sistema de archivos/red. – tiago

+0

No, la longitud del fragmento en la 3ª dimensión 1 hace que esa dimensión sea la más lenta, ya que accedería a un fragmento de 400 MB por cada valor de 4 bytes al leer a lo largo de esa dimensión. Pero si utilizó 10 fragmentos a lo largo de cada dimensión (cada fragmento 50x40x30x40), cada fragmento comprendería aproximadamente 12 MB (suponiendo 4 bytes por valor), y solo tomaría 10 lecturas para acceder a un "cilindro" de valores a lo largo de cualquier dimensión (Trozo de 50x50x30x40). Para ver un ejemplo de cómo esto puede mejorar los tiempos de acceso en algunas direcciones, consulte las 2 diapositivas: http://www.unidata.ucar.edu/netcdf/workshops/2011/chunk_cache/Problem.html –

+0

Corrección al comentario anterior: reemplazar " (un trozo de 50x50x30x40) "con" (10 trozos de 50x50x30x40) "... –

3

Esto es un comentario, no una respuesta, pero no puedo comentar lo anterior, lo siento.

Entiendo que desea procesar myvar[:,:,i], con i en range(450). En ese caso, se le va a hacer algo como:

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

y el cuello de botella en el acceso myslice = myvar[:,:,i]. ¿Has intentado comparar cuánto tiempo lleva acceder a moreslices = myvar[:,:,0:n]? Sería contiguos datos, y tal vez puedas ahorrar tiempo con eso. Debería elegir n tan grande como lo permita su memoria, y luego procesar el siguiente fragmento de datos moreslices = myvar[:,:,n:2n] y así sucesivamente.

+0

Gracias por su respuesta. He comparado el acceso a 'myvar [:,:, 0: n]' y toma aproximadamente el mismo tiempo que 'myvar [:,:, 0]'. Así que esto es al menos una forma, pero todavía estoy tratando de descubrir por qué hay una penalización así para empezar. Tenga en cuenta que 'myvar [:,:, 0: n]' no es contiguo. – tiago

+0

Bueno, es cierto que 'myvar [1,0,0]' no es contiguo a 'myvar [2,0,0]'.Pero lleva casi el mismo tiempo porque 'myvar [i, i, 0]' es realmente contiguo a 'myvar [i, i, 1]'. ¿Tiene más sentido ahora? – gg349

Cuestiones relacionadas