Преобразовать данные netcdf в R для интерполяции

Итак, у меня есть некоторые переменные из файла.nc, которые находятся в 4D массивах (x,y,z,t). Дело в том, что координаты z не расположены равномерно, как координаты x и y, т. Е. Z проходит примерно 25 метров, 75 метров, 125, 175,..., 500, 600, 700,..., 20000, 21000, 22000. Я пытаюсь линейно интерполировать данные, чтобы получить равномерный интервал 50 м по оси z. Но функция приближения в R работает слишком медленно (я думаю, что массивы слишком велики):

library(ncdf)  
x = get.var.ncdf(nc,'x'); y = get.var.ncdf(nc,'y'); z = get.var.ncdf(nc,'z')  
t = get.var.ncdf(nc,'t')  # time
qc1 = get.var.ncdf(nc,'qc',start=c(1,1,1,1),count=c(-1,-1,-1,-1))  

zlin = seq(z[1],z[length(z)],50)  
qc1_lin = array(0,c(length(x),length(y),length(zlin),length(t)))  
for (i in 1:length(x)) {  
    for (j in 1:length(y)) {  
        for (k in 1:length(t)) {  
            qc1_lin[i,j,,k] = approx(z,qc1[i,j,,k],xout = zlin)  
        }  
    }  
}

Есть ли способ сделать это быстрее? Или, кто-то сказал мне, чтобы изучить данные, чтобы сделать это проще, но я не совсем уверен, что он имеет в виду. Кто-нибудь может мне помочь? Благодарю.

1 ответ

Поскольку у меня нет вашего ncdf файла, я использовал набор данных о температуре воздуха NOAA в качестве примера:

library(ncdf)
url <- paste("ftp://ftp.cdc.noaa.gov/Datasets/ncep/air.",format(Sys.Date(),"%Y"),".nc",sep="")
download.file(url,destfile="air.nc")
nc <- open.ncdf("air.nc")
x <- get.var.ncdf(nc,'lon')
y <- get.var.ncdf(nc,'lat')
z <- get.var.ncdf(nc,'level')
t <- get.var.ncdf(nc,'time')
qc1 <- get.var.ncdf(nc,'air')

Здесь z в диапазоне значений от 1000 до 50, чтобы привести короткий пример, давайте возьмем обычную сетку, разнесенную на каждые 100 уровней (я также ограничу операцию в первые 20 дней набора данных, чтобы пример был относительно небольшим):

zlin <- seq(z[1],z[length(z)],-100)

Используя ваш метод:

qc1_lin <- array(0,dim=c(144,73,10,20))
system.time({
    for (i in 1:length(x)) {  
         for (j in 1:length(y)) {  
             for (k in 1:20) {  
                 # Don't forget that approx outputs a list
                 qc1_lin[i,j,,k] = approx(z,qc1[i,j,,k],xout = zlin)$y
                 }  
             }  
          }
     })
   user  system elapsed 
 26.793   1.196  27.886 

Но вы можете использовать apply выполнить ту же операцию: аргумент MARGIN также может принимать вектор значения. Здесь мы хотим применить approxфункция для измерений 1, 2 и 4 (поскольку мы изменяем 3-е измерение):

system.time({
    qc1_lin2 <- apply(qc1[,,,1:20],c(1,2,4),function(X)approx(z,X,xout=zlin)$y)
    })
   user  system elapsed 
 24.413   0.144  24.408 

apply к сожалению, выводит новое измерение как первое измерение, поэтому нам нужно переставить результат:

qc1_lin3 <- aperm(qc1_lin2, perm=c(2,3,1,4))

Давайте проверим, совпадают ли результаты:

all(qc1_lin3==qc1_lin)
[1] TRUE

Выигрыш во времени относительно невелик, но, вероятно, того стоит.

Это не ответ на R, но просто чтобы сказать, что эту задачу можно быстро выполнить из командной строки с помощью CDO.

 cdo intlevel,`seq -s "," 50 50 22000` in.nc out.nc

команда seq создает список, разделенный запятыми, от 50 до 22000 с интервалом в 50 метров.

Другие вопросы по тегам