Обработка очень больших файлов netCDF на python

Я пытаюсь работать с данными из очень больших файлов netCDF (~ 400 Gb каждый). Каждый файл имеет несколько переменных, все намного больше, чем системная память (например, 180 ГБ против 32 ГБ ОЗУ). Я пытаюсь использовать numpy и netCDF4-python делать некоторые операции над этими переменными, копируя срез за раз и работая на этом срезе. К сожалению, на самом деле требуется очень много времени, чтобы прочитать каждый кусочек, который убивает производительность.

Например, одна из переменных - это массив формы (500, 500, 450, 300). Я хочу работать с срезом [:,:,0], поэтому я делаю следующее:

import netCDF4 as nc

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

Но последний шаг занимает очень много времени (~ 5 минут в моей системе). Если, например, я сохранил переменную формы (500, 500, 300) в файле netcdf, то операция чтения того же размера займет всего несколько секунд.

Есть ли способ ускорить это? Очевидным путем было бы преобразование массива таким образом, чтобы индексы, которые я выбираю, выходили первым. Но в таком большом файле это невозможно сделать в памяти, и кажется еще медленнее попытаться это сделать, если простая операция уже занимает много времени. Мне бы хотелось, это быстрый способ прочитать фрагмент файла netcdf, в соответствии с функцией get_vara интерфейса Fortran. Или какой-то способ эффективного переноса массива.

Ответ 1

Вы можете переместить переменные netCDF слишком большими, чтобы они соответствовали памяти, используя утилиту nccopy, которая описана здесь:

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

Идея состоит в том, чтобы "переписать" файл, указав, какие формы кусков (многомерные плитки) вы хотите переменные. Вы можете указать, сколько памяти использовать в качестве буфера и сколько использовать для кеш-памяти, но не ясно, как оптимально использовать память между этими видами использования, поэтому вы возможно, придется просто попробовать несколько примеров и время их. Вместо того, чтобы полностью транспонировать переменную, вы, вероятно, захотите "частично перенести" его, указав куски, у которых много данных вдоль 2 больших размера вашего среза и имеют только несколько значений по другим параметрам.

Ответ 2

Это комментарий, а не ответ, но я не могу прокомментировать это, извините.

Я понимаю, что вы хотите обработать myvar[:,:,i], i в range(450). В этом случае вы будете делать что-то вроде:

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

и узкое место находится в доступе к myslice = myvar[:,:,i]. Вы пытались сравнить, сколько времени требуется для доступа к moreslices = myvar[:,:,0:n]? Это будут данные contiguos, и, возможно, вы сможете сэкономить время. Вы бы выбрали n размером с памятью, а затем обработали следующий фрагмент данных moreslices = myvar[:,:,n:2n] и т.д.