用R从.CSV创建NetCDF

3

我正在尝试从一个 .csv 文件创建一个 NetCDF 文件。我已经阅读了这里和其他地方的几个教程,并且仍然有一些疑问。

我有一个表格如下:

lat,long,time,rh,temp
41,-109,6,1,1
40,-107,18,2,2
39,-105,6,3,3
41,-103,18,4,4
40,-109,6,5,2
39,-107,18,6,4

我使用R中的ncdf4包创建NetCDF文件。
xvals <- data$lon
yvals <- data$lat 
nx <- length(xvals)
ny <- length(yvals)
lon1 <- ncdim_def("longitude", "degrees_east", xvals)
lat2 <- ncdim_def("latitude", "degrees_north", yvals)
time <- data$time
mv <- -999 #missing value to use

var_temp <- ncvar_def("temperatura", "celsius", list(lon1, lat2, time), longname="Temp. da superfície", mv) 

var_rh <- ncvar_def("humidade", "%", list(lon1, lat2, time), longname = "humidade relativa", mv )

ncnew <- nc_create(filename, list(var_temp, var_rh))
ncvar_put(ncnew, var_temp, dadostemp, start=c(1,1,1), count=c(nx,ny,nt))

当我按照流程操作时,提示NC预期的数据量是我所拥有数据的3倍。我明白为什么会这样,每个维度都需要一个矩阵,因为我声明了变量是根据经度、纬度和时间来确定的。
那么,我应该如何导入这种数据,其中每个数据采集已经有了一个Lon、Lat、Time和其他变量?
能否有人指点一下?
注:这里使用的数据不是我的真实数据,只是我在教程中使用的一些示例数据。
1个回答

4

我觉得你的代码存在多个问题。请逐步进行以下操作:

创建尺寸

在nc文件中,尺寸不是作为键值对工作的,它们只是一组表示变量数组中每个位置代表什么的值向量。

这意味着你应该这样创建尺寸:

xvals <- unique(data$lon)
xvals <- xvals[order(xvals)]
yvals <- yvals[order(unique(data$lat))] 
lon1 <- ncdim_def("longitude", "degrees_east", xvals)
lat2 <- ncdim_def("latitude", "degrees_north", yvals)
time <- data$time
time_d <- ncdim_def("time","h",unique(time))

我所在的工作环境中,我们将无限维度仅用作索引,而具有与该维度相同名称的1d变量则保存值。我不确定在R中如何使用无限维度。既然您没有要求我解释它,我就不做过多说明 :-)

定义变量

mv <- -999 #missing value to use
var_temp <- ncvar_def("temperatura", "celsius", 
                      list(lon1, lat2, time_d), 
                      longname="Temp. da superfície", mv) 
var_rh <- ncvar_def("humidade", "%", 
                     list(lon1, lat2, time_d), 
                     longname = "humidade relativa", mv )

添加数据

创建一个nc文件:ncnew <- nc_create(f, list(var_temp, var_rh))

添加值时,保存数据的对象会被融合成一个一维数组,并从指定的起始位置开始进行顺序写入。写入的维度由count中的值控制。如果您有以下数据:

long, lat, time, t
   1,   1,    1, 1
   2,   1,    1, 2
   1,   2,    1, 3
   2,   2,    1, 4

命令ncvar_put(ncnew, var_temp,data$t,count=c(2,2,1))会得到您期望的结果。
对于您的数据,第一步是为维度创建索引:
data$idx_lon <- match(data$long,xvals)
data$idx_lat <- match(data$lat,yvals)
data$idx_time <- match(data$time,unique(time))

然后创建一个维度适合你的数据的数组:
m <- array(mv,dim = c(length(yvals),length(xvals),length(unique(time))))

然后使用你的数值填充数组:

for(i in 1:NROW(data)){
  m[data$idx_lat[i],data$idx_lon[i],data$idx_time[i]] <- data$temp[i]
}

如果速度是一个问题,您可以向量化地计算线性索引向量,并将其用于值分配。
写入数据。
ncvar_put(ncnew, var_temp,m)

请注意,您不需要使用 start count
最后关闭nc文件以将数据写入磁盘 nc_close(ncnew)。我建议您使用 ncdump 控制台命令可选地检查文件。
关于您是否编写完整数组或使用 start count 的问题,我认为两种方法都很可靠。首选哪种取决于您的数据和个人偏好。
我认为构建一个数组,添加值,然后将其作为整体写入的方法更容易理解。但是,当询问哪种方法更有效时,这取决于数据。如果您的数据很大并且有许多NA值,我认为使用带有start和count的多个写入可能更快。如果NA很少,则创建一个矩阵并进行单个写入会更快。如果您的数据非常大,创建额外的数组将超出可用内存,则必须结合使用两种方法。

Bueffish,首先非常感谢您抽出时间来帮助我。其次,我非常感激您清晰的答案和示例代码。它对我帮助很大。我一直在围绕这个想法打转,也有同样的想法,但对解决方案不是很清楚。我的主要担忧是可能会给定维度赋予错误的值。使用startcount属性是可靠的吗?还是使用您展示的索引更合适?两种方法都完美地工作了。我将更深入地研究无限维度,因为我认为这将是必要的。谢谢你,伙计。问候 - aoceano
嗨,谢谢你的赞美之词。我编辑了我的答案,并尝试解释一下何时使用哪种方法。还要注意,在?ncvar_put中有一个写入沿无限维度的三维数据的示例。 - bluefish
嗨,再次感谢@Bluefish。你的答案再次帮助我澄清了一些想法。现在我读到的关于这个主题的所有内容都更加清晰了。再次感谢,伙计。最好的问候。 - aoceano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接