Преобразовать данные 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 метров.