Изменить кусок переменной Netcdf с помощью R

Регулярно я сталкиваюсь с одной и той же проблемой при использовании R для работы с большими файлами netcdf (больше, чем память компьютера). Не существует очевидного способа изменить фрагмент данных. Это, вероятно, единственная общая задача netcdf, которую я не могу понять, как сделать это эффективным способом в R. Раньше я решал эту проблему, используя NCO или nccopy, в зависимости от ситуации. Даже CDO имеет возможность копировать nc, изменяя фрагмент, но гораздо менее гибкий, чем предыдущие инструменты. Мне интересно, есть ли какой-нибудь эффективный способ сделать это в R.

В следующем примере создается игрушка nc, разделенная на Chunking: [100,100,1].

library(ncdf4)

foo_nc_path=paste0(tempdir(),"/thing.nc")
xvals <- 1:100
yvals <- 1:100

lon <- ncdim_def("longitude", "Km_east", xvals)
lat <- ncdim_def("latitude", "Km_north", yvals)

time <- ncdim_def("Time","hours", 1:1000, unlim=TRUE)
var<- ncvar_def("foo_var", "nothing", list(lon, lat, time), chunksizes=c(100,100,1),
                      longname="xy chunked numbers", missval=-9) 

foo_nc <- nc_create(foo_nc_path, list(var))

data <- array(runif(100*100*1000),dim = c(100,100,1000))

ncvar_put(foo_nc, var, data)

nc_close(foo_nc)


####Check speed

foo_nc <- nc_open(foo_nc_path)

system.time({timestep <- ncvar_get(foo_nc,"foo_var",start = c(1,1,1),count=c(-1,-1,1))})
system.time({timeserie <- ncvar_get(foo_nc,"foo_var",start = c(1,1,1),count=c(1,1,-1))})

Как видите, время чтения для timeserie намного больше, чем для timestep var.

Разница во времени экспоненциально увеличивается с размером .nc.

Кто-нибудь знает способ изменить фрагмент файла nc в R, размер которого больше, чем память компьютера?


person Lacococha    schedule 19.05.2020    source источник


Ответы (1)


Это зависит от вашей цели. Если вам нужно извлечь/анализировать срезы по карте (т. е. по матрице широты и долготы), сохраните стратегию фрагментации по пространственным координатам. Однако, если вы хотите провести временной анализ (например, извлечение временных рядов каждой ячейки сетки для расчета трендов), то мой совет — переключите свою стратегию фрагментации на временное измерение.

Попробуйте перезапустить свой код, заменив chunksizes=c(100,100,1) чем-то вроде, скажем, chunksizes=c(10,10,1000). Таким образом, чтение временных рядов становится намного быстрее.

Если ваш код на R очень медленный, вы можете попробовать более быструю альтернативу, такую ​​как (например) nccopy или nco.

Вы можете повторно разбить файл netcdf с помощью простой команды nccopy, например: nccopy -c time/1000,lat/10,lon/10 input.nc output.chunked.nc

В nco (который я рекомендую вместо nccopy для этой операции) вы можете сделать что-то вроде:

nco -O -4 -D 4 --cnk_plc g2d --cnk_dmn lat,10 --cnk_dmn lon,10 --cnk_dmn time,1000 in.nc out.nc

указав --cnk_dmn для ваших конкретных переменных с интересующим размером фрагмента. Дополнительные примеры см. на странице http://nco.sourceforge.net/nco.html#Chunking. .

В любом случае вам придется немного поиграть с разными размерами фрагментов, чтобы определить, что лучше всего подходит для вашего конкретного случая.

person thiagoveloso    schedule 20.07.2020
comment
Именно так, но что, если вы хотите перейти от режима карты к режиму времени массивного nc (скажем, сжатого 10Gb)? Чанк настолько отличается, что даже чтение прежнего nc для записи последнего становится чрезвычайно медленным в R - person Lacococha; 03.09.2020
comment
@Lacococha ознакомьтесь с правкой моего исходного ответа. - person thiagoveloso; 05.09.2020
comment
Спасибо за обновление. Как я уже сказал, это то, что я обычно делаю. Но я хотел бы знать, есть ли способ сделать это в R. Думаю, нет. - person Lacococha; 06.09.2020
comment
Вы определенно можете сделать это в R - ваш код показывает это. Но это будет медленно (как вы уже поняли). Лучше использовать специализированный инструмент. - person thiagoveloso; 10.09.2020