使用Python处理非常大的netCDF文件

14
我试图处理非常大的netCDF文件(每个约400 GB)。每个文件都有几个变量,所有变量都比系统内存大得多(例如180 GB vs 32 GB RAM)。我尝试使用numpy和netCDF4-python对这些变量执行一些操作,通过逐个拷贝切片并对其进行操作。不幸的是,仅读取每个切片就需要很长时间,这影响了性能。
例如,其中一个变量是形状为(500、500、450、300)的数组。我想要操作切片[:,:,0],所以我按照以下方式操作:
import netCDF4 as nc

f = nc.Dataset('myfile.ncdf','r+')
myvar = f.variables['myvar']
myslice = myvar[:,:,0]

但最后一步需要很长时间才能完成(在我的系统上大约需要5分钟)。例如,如果我将一个形状为(500, 500, 300)的变量保存到netcdf文件中,那么同样大小的读操作只需要几秒钟。

有没有方法可以加快速度?一个显而易见的路径是转置数组,使我选择的索引出现在前面。但在这样一个大文件中,这不可能在内存中完成,而且即使已经花费了很长时间来执行简单的操作,尝试它似乎也更慢。我想要的是一种快速读取netcdf文件切片的方法,类似于Fortran的get_vara函数接口。或者一些有效地转置数组的方法。


1
如果您想对数据进行更多操作而不仅仅是转置,请查看 xarray 模块:它提供了一个非常好的接口来处理 dask 的内存外数组。 - j08lue
2个回答

8
你可以使用 nccopy 工具转换 netCDF 变量,以便处理那些太大而无法放入内存的变量。nccopy 的文档在此处。

http://www.unidata.ucar.edu/netcdf/docs/guide_nccopy.html

这个想法是通过指定变量的多维切片形状(多维度瓦片)来“重新分块”文件。您可以指定要用作缓冲区的内存量和用于块缓存的内存量,但是如何在这些用途之间最优地使用内存并不清楚,因此您可能需要尝试一些示例并计时它们。与其完全转置一个变量,您可能希望通过指定在切片的2个大维度上具有大量数据且在其他维度上仅具有少量值的块来“部分转置”它。

感谢Russ的回答。这很有趣,因为我从未深入研究过分块。假设我有一个带有尺寸(500, 500, 300, 400)的变量。如果我在第三个维度上进行分块,这是否类似于进行部分转置,其中该轴是最快的轴(即连续的轴)?我确实更改了我将要读取更多的轴上的分块,但仍需要很长时间才能获得3D切片。我将调查这是否是文件系统/网络问题。 - tiago
不,将第三个维度的块长度设置为1会使该维度变得最慢,因为在沿着该维度读取时,每个4字节值都需要访问400 MB的块。但是,如果您沿着每个维度使用10个块(每个块50x40x30x40),则每个块将包含约12 MB的数据(假设每个值占用4个字节),并且只需要进行10次读取即可访问任何维度上的“圆柱形”值(一个50x50x30x40的块)。有关如何改善某些方向上的访问时间的示例,请参见2张幻灯片:http://www.unidata.ucar.edu/netcdf/workshops/2011/chunk_cache/Problem.html - Russ Rew
以上评论更正:将“(a 50x50x30x40 chunk)”替换为“(10个50x50x30x40的chunk)”... - Russ Rew
我有点困惑。假设变量大小为(500,500,300,400),我想快速访问像(:,:,0,0)这样的切片。我认为在最后两个维度上使用1进行分块是最好的选择(除了整体转置)。那种类型的访问最好的分块方式是什么?在您的链接中,它说使用第一个维度的大值和最后几个维度的小值重新分块将加速对这些最后几个维度的访问,但您似乎在说相反的话。 - tiago

3
这是一条评论,不是答案,但很抱歉我无法对上面的内容发表评论。
我明白你想要处理 myvar[:,:,i],其中i取值range(450)。在这种情况下,你需要做的是类似于以下操作:
for i in range(450):
    myslice = myvar[:,:,i]
    do_something(slice)

瓶颈在于访问 myslice = myvar[:,:,i]。您尝试过比较访问 moreslices = myvar[:,:,0:n] 花费的时间吗?这将是连续的数据,也许您可以节省时间。您可以选择尽可能大的 n(取决于存储器容量),然后处理下一批数据 moreslices = myvar[:,:,n:2n] 然后继续。


谢谢你的回答。我已经比较了访问 myvar[:,:,0:n] 和访问 myvar[:,:,0],它们所需的时间大致相同。所以这至少是一种方法,但我仍在努力找出为什么一开始就会有这样的惩罚。请注意,myvar[:,:,0:n] 不是连续的。 - tiago
确实,myvar[1,0,0]myvar[2,0,0]不是连续的。但是它们所需的时间大致相同,因为myvar[i,i,0]实际上与myvar[i,i,1]是连续的。现在更有意义了吗? - gg349

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