当前位置: 首页 > 知识库问答 >
问题:

从netCDF中快速读取时间序列?

吴弘壮
2023-03-14

我有一些大型 netCDF 文件,其中包含 6 个分辨率为 0.5 度的地球每小时数据。

每年有360个纬度点,720个经度点和1420个时间点。我有年度文件(12 GB ea)和一个包含110年数据(1.3 TB)的文件存储为netCDF-4(这是1901年数据,1901.nc,其使用策略以及我开始使用的原始公共文件的示例)。

根据我的理解,从一个netCDF文件中读取应该比遍历最初提供的由年份和变量分隔的文件集更快。

我想为每个网格点提取一个时间序列,例如从特定的纬度和经度中提取 10 年或 30 年。但是,我发现这很慢。例如,尽管我可以在 0.002 秒内从单个时间点读取 10000 个值的全局切片(维度的顺序是纬度、lon、时间),但随着时间的推移,我从一个点位置读取 10 个值需要 0.01 秒:

## a time series of 10 points from one location:
library(ncdf4)
met.nc <- nc_open("1901.nc")
system.time(a <- ncvar_get(met.nc, "lwdown", start = c(100,100,1), 
                                             count = c(1,1,10)))
   user  system elapsed 
  0.001   0.000   0.090 

## close down session

## a global slice of 10k points from one time
library(ncdf4)
system.time(met.nc <- nc_open("1901.nc"))
system.time(a <- ncvar_get(met.nc, "lwdown", start = c(100,100,1), 
                                             count = c(100,100,1)))
   user  system elapsed 
  0.002   0.000   0.002 

我怀疑这些文件是为了优化空间层的读取而编写的,因为a)变量的顺序是lat,lon,time,b)这将是生成这些文件的气候模型的逻辑顺序,c)因为全球范围是最常见的可视化。

我尝试重新排序变量,以便时间优先:

ncpdq -a time,lon,lat 1901.nc 1901_time.nc

(ncpdq来自NCO(netCDF运营商)软件)

> library(ncdf4)

## first with the original data set:
> system.time(met.nc <- nc_open("test/1901.nc"))
   user  system elapsed 
  0.024   0.045  22.334 
> system.time(a <- ncvar_get(met.nc, "lwdown", start = c(100,100,1), count = c(1, 1, 1000))
+ )
   user  system elapsed 
  0.005   0.027  14.958 

## now with the rearranged dimensions:
> system.time(met_time.nc <- nc_open("test/1901_time.nc"))
   user  system elapsed 
  0.025   0.041  16.704 
> system.time(a <- ncvar_get(met_time.nc, "lwdown", start = c(100,100,1), count = c(1, 1, 1000)))
   user  system elapsed 
  0.001   0.019   9.660 

我如何在一个时间点优化阅读时间序列,而不是在一个时点优化大面积的分层?例如,如果文件写得不同,比如time、lat、lon,会更快吗?有没有一种“简单”的方法来转换netCDF-4文件中的维度顺序?

(@mdsumner请求的基准测试)

library(rbenchmark)
library(ncdf4)
nc <- nc_open("1901.nc")
benchmark(timeseries = ncvar_get(nc, "lwdown", 
                                 start = c(1, 1, 50), 
                                 count = c(10, 10, 100)), 
          spacechunk = ncvar_get(nc, "lwdown", 
                                  start = c(1, 1, 50), 
                                  count = c(100, 100, 1)),           
          replications = 1000)

        test replications elapsed relative user.self sys.self user.child
2 spacechunk         1000   0.909    1.000     0.843    0.066          0
1 timeseries         1000   2.211    2.432     1.103    1.105          0
  sys.child
2         0
1         0

我已经开始在这里开发一个解决方案。这些片段位于github . com/ebi modeling/model-drivers/tree/master/met/cruncep中的一组脚本中

这些脚本仍然需要一些工作和组织——并不是所有的脚本都有用。但阅读速度非常快。与上述结果不完全相同,但在一天结束时,我可以立即从1.3TB文件(0.5度分辨率,2.5秒)中读取100年、6小时的时间序列:

system.time(ts <- ncvar_get(met.nc, "lwdown", start = c(50, 1, 1), count = c(160000, 1, 1)))
   user  system elapsed 
  0.004   0.000   0.004 

(注意:尺寸的顺序已经改变,如这里所述:当使用ncdf4::ncvar_get时,我如何指定尺寸顺序?)

共有3个答案

易成双
2023-03-14

不确定有没有考虑过cdo提取点?

cdo remapnn,lon=x/lat=y in.nc point.nc 

有时CDO会耗尽内存,如果发生这种情况,您可能需要循环遍历年度文件,然后用

cdo mergetime point_${yyyy}.nc point_series.nc 
壤驷安和
2023-03-14

编辑:原始问题有一个错误,但开始阅读时也可能有不同的开销,所以多次重复是公平的。< code>rbenchmark使这变得容易。

示例文件有点大,所以我使用了一个较小的文件,您可以与您的文件进行相同的比较吗?

更易于访问的示例文件:ftp://ftp.cdc.noaa.gov/Datasets/noaa.oisst.v2/sst.wkmean.1990-present.nc

我得到的时间是时间序列的两倍:

library(ncdf4)

nc <- nc_open("sst.wkmean.1990-present.nc")

library(rbenchmark)
benchmark(timeseries = ncvar_get(nc, "sst", start = c(1, 1, 50), count = c(10, 10, 100)), 
spacechunk = ncvar_get(nc, "sst", start = c(1, 1, 50), count = c(100, 100, 1)),           
replications = 1000)
##        test replications elapsed relative user.self sys.self user.child sys.child
##2 spacechunk         1000    0.47    1.000      0.43     0.03         NA        NA
##1 timeseries         1000    1.04    2.213      0.58     0.47         NA        NA
宗政天逸
2023-03-14

我认为这个问题的答案不会是对数据重新排序,而是将数据分块。有关分块netCDF文件的含义的完整讨论,请参阅Unidata首席netCDF开发人员Russ Rew的以下博客文章:

  • 分块数据:为什么重要
  • 分块数据:选择形状

结果是,虽然采用不同的分块策略可以大大提高访问速度,但选择正确的策略是非常重要的。

在较小的样本数据集上,sst.wkmean.1990-present。nc</code>,我在使用基准测试命令时看到了以下结果:

1)未分块:

## test replications elapsed relative user.self sys.self user.child sys.child
## 2 spacechunk         1000   0.841    1.000     0.812    0.029          0         0
## 1 timeseries         1000   1.325    1.576     0.944    0.381          0         0

2)天真的矮胖:

## test replications elapsed relative user.self sys.self user.child sys.child
## 2 spacechunk         1000   0.788    1.000     0.788    0.000          0         0
## 1 timeseries         1000   0.814    1.033     0.814    0.001          0         0

天真的分块简直是瞎猜;我是这样使用< code>nccopy实用程序的:

$ nccopy -c"lat/100,lon/100,time/100,nbnds/" SST . wk mean . 1990-present . NC chunked . NC

nccopy实用程序的Unidata文档可以在这里找到。

我希望我能推荐一种特定的策略来对数据集进行分块,但它高度依赖于数据。希望上面链接的文章能让您了解如何将数据分块以实现您想要的结果!

下面由Marco Hermida撰写的博客文章展示了在读取特定netCDF文件的时间序列时,不同的分块策略是如何影响速度的。这可能只能用作一个起点。

  • AR-4 3D数据文件的Netcdf-4分块性能结果

关于通过nc复制重新分块显然挂起;该问题似乎与默认的块缓存大小4MB有关。通过将其增加到4GB(或更多),您可以将大文件的复制时间从超过24小时减少到不到11分钟!

  • Nccopy非常慢/挂起
  • Unidata JIRA Trouble Ticket System:NCF-85,改进nccopy实用程序中块缓存的使用,使其适用于重新存储大型文件

有一点我不确定;在第一个链接中,讨论的是块缓存,但传递给nccopy的参数-m指定了复制缓冲区中的字节数。nccopy的-m参数控制块缓存的大小。

 类似资料:
  • 我在1998-01-01到1998-12-31期间使用TRMM_3B42_Daily产品创建了这个文件。这是我在R中使用的脚本: 通过这个链接,我试图提取值来绘制时间序列,但似乎我正在平均两个单元格的值,而不仅仅是提取单个单元格的值。我该如何解决这个问题?有没有办法创建一个循环,以便它提取不同单元格的值?(在这种情况下,它将是13 x 21=273) 我还发现了另外两个问题,即 excel 文件中

  • 一个与R有关的新手问题。如何使用R从netdcf文件中提取特定位置的时间序列数据。例如,下面的快照显示位置(1、2)的时间序列为13、28、43。 提前谢谢。

  • 我对R相对较新。我正在尝试从 netCDF 文件中获取温度数据的不同点(纬度、纬度)的时间序列。我的示例数据文件在这里,这里是小文件。我已经尝试了netCDF包和到目前为止我使用的代码 有人能帮我得到一个时间序列的数据帧(第一列)和另一列中某个特定点(lat,lon)的数据值吗。在这种情况下,我正在寻找一个特定纬度点(并对许多兴趣点重复)和给定变量(在本例中为tasmin)的时间序列(1950-0

  • 问题内容: 我需要将包含4个字节整数(小尾数)的二进制文件读入我的Android应用程序的2D数组中。我当前的解决方案如下: 对于2k * 2k的阵列,这非常慢,大约需要25秒。我在DDMS中可以看到垃圾收集器正在加班,因此这可能是速度缓慢的原因之一。 必须有一种使用ByteBuffer将该文件读入数组的更有效的方法,但是目前我看不到它。关于如何加快速度的任何想法? 问题答案: 为什么不读入4字节

  • 我想使用R从每个位置(X和Y)的Netcdf数据集中提取时间序列数据并将其转换为csv文件。这是我第一次处理NetCDF数据。有人能告诉我使用R或Matlab的相关代码吗? 这是我的数据描述: IRI FD季节性预测降水问题:Tercile概率数据 独立变量(网格): Tercile Classes网格:/C(ids)无序[(低于正常)(正常)(高于正常)]:发布的网格月份预测 网格:/F(自19

  • 此过程中的主要问题是下面的代码: 产生以下错误: 我有两个CSV文件,其中一个包含变量(降水量)的所有实际数据,每一列都是一个站点,它们的对应坐标在第二个单独的CSV文件中。我的示例数据在这里的谷歌驱动器中。 如果您想查看数据本身,但我的第一个 CSV 文件具有形状(39811、144),第二个 CSV 文件具有形状(171、10),但请注意;我仅将切片数据帧用作 (144, 2)。 这是代码: