几次迭代后,在 R 中读取多个栅格/netCDF 数据会变慢

问题描述

我有 9000 多个 netCDF 文件,我正在从中提取数据。瓶颈是将数据读入 raster::bricks(或堆栈)。

netCDF 只有 1 个时间步长(一天),但有 72 个高程层和 84 个变量。我正在为每一天、每个变量和第 72 层提取数据。

我的方法是使用 raster::brick,然后使用 extract()。我使用 lapply(或 purrr::map,这里没有太大区别)。我的问题是,经过几次迭代后,数据的读取速度要慢得多。最初,读入一个变量需要约 0.25 秒,但随后会减慢到约 6 秒。光栅砖本身并没有在每次迭代中被保存 - 没有其他应该增长的东西,所以我不知所措。我在 Mac 上,R402。 TIA!

https://portal.nccs.nasa.gov/datashare/merra2_gmi/

示例代码:我只是将 print(x) 放在跟踪中,但一旦问题解决,最终会删除

z <- lapply(1:length(varnames),function(x) { 
         print(x)
         raster::brick(MERRA2.GMI.filenames.read[i],varname = varnames[x])[[72]] 
         %>% crop(US.extent)
     }
   ) 
%>% raster::brick()

解决方法

您提供的代码并不完全清楚。大概 i 是一天(9000 天之一)?然后 lapplyUS.extent 的 RasterBrick 放入列表 z 中,用于所有 varname。然后将这些层通过管道传输到 raster::brick 中。我假设在那之后您提取兴趣点的值,然后循环到第二天?

在这种情况下,您最多将保存 RasterBricks 两天(某些层为 168 层)的数据(直到一天的数据覆盖前一天之前;假设未使用的内存立即被释放)。

以下可能表现更好。在 brick 之后调用 lapply 比调用 stack 开销更大,因为后者实际上还没有读取任何值,它只指向文件。只使用一次 crop 也应该(但你永远不知道)更快;并且通过这样做,您不会在内存中创建包含栅格数据的列表(仅对文件的引用,直到调用 crop)。

z <- lapply(1:length(varnames),function(x) { 
         raster::brick(filenames[i],varname = varnames[x])[[72]] 
     }
   ) 
 s <- stack(z) %>% crop(US.extent)

我下载了一个文件,我建议使用以下工作流程,使用通常更快的 terra,尤其是在使用多边形提取时。但在这种情况下,terra 还可以更轻松地选择感兴趣的变量,完全避免使用 lapply

对于一个文件,我创建了一个 SpatRasterDataSet 来理解子数据集结构

library(terra)
f <- "MERRA2_GMI.inst0_3d_ovp_Nv.19900202_1200z.nc4"
s <- sds(f)
s
#class       : SpatRasterDataset 
#subdatasets : 74 
#dimensions  : 361,576 (nrow,ncol)
#nlyr        : 72,72,... 
#resolution  : 0.625,0.5  (x,y)
#extent      : -180.3125,179.6875,-90.25,90.25  (xmin,xmax,ymin,ymax)
#coord. ref. :  
#source(s)   : MERRA2_GMI.inst0_3d_ovp_Nv.19900202_1200z.nc4 
#names       : OVP10_AGE,OVP10_CH2O,OVP10_CH4,OVP10_CO,OVP10_EM_LGTNO,OVP10_EPV,OVP10_FCLD,OVP10_GOCART_SO2_VMR,OVP10_GOCART_SO2v_VMR,OVP10_NO,OVP10_NO2,OVP10_O3,OVP10_PL,OVP10_PPBL,OVP10_PS,OVP10_QLTOT,OVP10_QV_VMR,OVP10_T,OVP10_TAUTT,OVP10_TOTEXTTAU,OVP10_TROPP,OVP10_U10,OVP10_V10,OVP10_stO3,OVP14_AGE,OVP14_Br,OVP14_BrCl,OVP14_BrO,OVP14_BrONO2,OVP14_CH2O,OVP14_CH3Cl,OVP14_CH4,OVP14_CO,OVP14_Cl,OVP14_Cl2,OVP14_Cl2O2,OVP14_ClO,OVP14_ClONO2,OVP14_EM_LGTNO,OVP14_EPV,OVP14_FCLD,OVP14_GOCART_NH3_VMR,OVP14_GOCART_SO2_VMR,OVP14_GOCART_SO2v_VMR,OVP14_HBr,OVP14_HCOOH,OVP14_HCl,OVP14_HNO3,OVP14_HNO3COND,OVP14_HO2,OVP14_HOBr,OVP14_HOCl,OVP14_ISOP,OVP14_MOH,OVP14_N2O,OVP14_NO,OVP14_NO2,OVP14_O3,OVP14_OClO,OVP14_OH,OVP14_PAN,OVP14_PL,OVP14_PPBL,OVP14_PS,OVP14_QLTOT,OVP14_QV_VMR,OVP14_R4N2,OVP14_T,OVP14_TAUTT,OVP14_TOTEXTTAU,OVP14_TROPP,OVP14_U10,OVP14_V10,OVP14_stO3 

选择感兴趣的图层。有些变量只有一层,所以我把那些有这么多变量的第 72 层取了。

n <- nlyr(s)
i <- cumsum(n)
i <- i[n==72]

或者您可以执行以下操作,请注意 rast(f) 将所有子数据集合并为一个多层数据集

r <- rast(f)
#class       : SpatRaster 
#dimensions  : 361,576,4334  (nrow,ncol,nlyr)
#resolution  : 0.625,ymax)
#coord. ref. :  
#sources     : MERRA2_GMI.inst0_3d_ovp_Nv.19900202_1200z.nc4:OVP10_AGE  (72 layers) 
#              MERRA2_GMI.inst0_3d_ovp_Nv.19900202_1200z.nc4:OVP10_CH2O  (72 layers) 
#              MERRA2_GMI.inst0_3d_ovp_Nv.19900202_1200z.nc4:OVP10_CH4  (72 layers) 
#              ... and 71 more source(s)
#varnames    : OVP10_AGE (Age of air (uniform source) tracer_10am_local) 
#              OVP10_CH2O (Formaldehyde_10am_local) 
#              OVP10_CH4 (Methane_10am_local) 
#              ...
#names       : OVP10~lev=1,OVP10~lev=2,OVP10~lev=3,OVP10~lev=4,OVP10~lev=5,OVP10~lev=6,... 
#unit        :        days,days,... 
#time        : 0 
 
i <- grep("lev=72",names(r))
head(i)
#[1]  72 144 216 288 360 432

现在在文件名的循环中(如果您愿意,可以使用 lapply),创建一个 SpatRaster,带有 i 的子集,并使用 extract

r <- rast(f)[[i]]
extract(r,v)

其中 v 是 SpatVector。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...