Файл NetCDF - почему размер файла 1/3 после фиксации размера записи?
Я изо всех сил пытаюсь справиться с этим.
Я создаю файл netcdf4 со следующими размерами и переменными (обратите внимание, в частности, неограниченное point
измерение):
dimensions:
point = UNLIMITED ; // (275935 currently)
realization = 24 ;
variables:
short mod_hs(realization, point) ;
mod_hs:scale_factor = 0.01 ;
short mod_ws(realization, point) ;
mod_ws:scale_factor = 0.01 ;
short obs_hs(point) ;
obs_hs:scale_factor = 0.01 ;
short obs_ws(point) ;
obs_ws:scale_factor = 0.01 ;
short fchr(point) ;
float obs_lat(point) ;
float obs_lon(point) ;
double obs_datetime(point) ;
}
У меня есть программа на Python, которая заполняет этот файл данными в цикле (отсюда и размер записи без ограничений - я не знаю, насколько большой будет размер файла).
После заполнения файла его размер составляет 103 МБ.
Моя проблема в том, что чтение данных из этого файла происходит довольно медленно. Я догадался, что это как-то связано с чанкингом и point
измерение?
Я побежал ncks --fix_rec_dmn
на файл и (после многократного использования) он создал новый файл netCDF, размер которого составляет всего 32 МБ (что примерно соответствует размеру данных, которые он содержит).
Это огромная разница в размерах - почему исходный файл так раздут? Также - доступ к данным в этом файле на несколько порядков быстрее. Например, в Python, чтобы прочитать содержимое hs
Переменная занимает 2 секунды в исходном файле и 40 миллисекунд в файле измерений с фиксированной записью.
У меня проблема в том, что некоторые из моих файлов содержат много точек и кажутся слишком большими для запуска ncks
(на моей машине заканчиваются памятки, и у меня 8 ГБ), поэтому я не могу преобразовать все данные в фиксированное измерение записи.
Может кто-нибудь объяснить, почему размеры файлов так различны, и как я могу сделать оригинальные файлы меньше и эффективнее для чтения?
Кстати, я не использую сжатие zlib (я выбрал масштабирование значений с плавающей запятой до целочисленного короткого).
Крис
РЕДАКТИРОВАТЬ Мой код Python по сути создает один файл временных рядов совместно размещенной модели и данные наблюдений из нескольких отдельных файлов прогноза модели за 3 месяца. Моя модель прогноза выполняется 4 раза в день, и я собираю данные за 3 месяца, что составляет ~120 файлов.
Программа извлекает подмножество прогнозируемого периода из каждого файла (например, T+24h -> T+48h), поэтому объединение файлов не является простым делом.
Это грубое приближение к тому, что делает мой код (на самом деле он читает / записывает больше переменных, но я просто показываю здесь 2 для ясности):
# Create output file:
dout = nc.Dataset(fn, mode='w', clobber=True, format="NETCDF4")
dout.createDimension('point', size=None)
dout.createDimension('realization', size=24)
for varname in ['mod_hs','mod_ws']:
v = ncd.createVariable(varname, np.short,
dimensions=('point', 'realization'), zlib=False)
v.scale_factor = 0.01
# Cycle over dates
date = <some start start>
end_dat = <some end date>
# Keeo track if record dimension ('point') size:
n = 0
while date < end_date:
din = nc.Dataset("<path to input file>", mode='r')
fchr = din.variables['fchr'][:]
# get mask for specific forecast hour range
m = np.logical_and(fchr >= 24, fchr < 48)
sz = np.count_nonzero(m)
if sz == 0:
continue
dout.variables['mod_hs'][n:n+sz,:] = din.variables['mod_hs'][:][m,:]
dout.variables['mod_ws'][n:n+sz,:] = din.variables['mod_wspd'][:][m,:]
# Increment record dimension count:
n += sz
din.close()
# Goto next file
date += dt.timedelta(hours=6)
dout.close()
Интересно, если я сделаю выходной формат файла NETCDF3_CLASSIC
скорее что NETCDF4
размер вывода размер, который я ожидал бы. Выход NETCDF4 кажется раздутым.
3 ответа
Пожалуйста, попробуйте предоставить код, который работает без изменений, если это возможно, мне пришлось отредактировать, чтобы он заработал, но это было не слишком сложно.
import netCDF4 as nc
import numpy as np
dout = nc.Dataset('testdset.nc4', mode='w', clobber=True, format="NETCDF4")
dout.createDimension('point', size=None)
dout.createDimension('realization', size=24)
for varname in ['mod_hs','mod_ws']:
v = dout.createVariable(varname, np.short,
dimensions=('point', 'realization'), zlib=False,chunksizes=[1000,24])
v.scale_factor = 0.01
date = 1
end_date = 5000
n = 0
while date < end_date:
sz=100
dout.variables['mod_hs'][n:n+sz,:] = np.ones((sz,24))
dout.variables['mod_ws'][n:n+sz,:] = np.ones((sz,24))
n += sz
date += 1
dout.close()
Основное отличие заключается в команде createVariable. Для размера файла, не предоставляя "chunksizes" при создании переменной, я также получил в два раза больший файл по сравнению с тем, когда я его добавил. Так что для размера файла это должно сработать. Для чтения переменных из файла я не заметил никакой разницы на самом деле, может быть, я должен добавить больше переменных? В любом случае, теперь должно быть понятно, как добавить размер чанка. Возможно, вам нужно немного протестировать, чтобы получить хороший конф для вашей проблемы. Не стесняйтесь спрашивать больше, если это все еще не работает для Вас, и если Вы хотите понять больше о чанкинге, прочитайте hdf5 документы
Мой опыт показывает, что размер фрагмента по умолчанию для измерений записей зависит от версии библиотеки netCDF, расположенной внизу. Для 4.3.3.1 это 524288. 275935 записей - это примерно половина записи. ncks автоматически выбирает (не сообщая вам) более разумных размеров кусков, чем значения по умолчанию для netCDF, поэтому вывод лучше оптимизируется. Я думаю, что это то, что происходит. Смотрите http://nco.sf.net/nco.html
Я думаю, что ваша проблема в том, что размер чанка по умолчанию для неограниченных размеров равен 1, что создает огромное количество внутренних структур HDF5. Если явно установить размер фрагмента (очевидно, подходит для неограниченных размеров), второй пример значительно лучше в пространстве и времени.
В HDF5/netCDF4 для неограниченных размеров требуется разделение на части, поэтому, если вам нужны неограниченные размеры, вы должны подумать о производительности разделения, как вы обнаружили.
Больше здесь:
https://www.unidata.ucar.edu/software/netcdf/docs/netcdf_perf_chunking.html