在python中加速读取非常大的netcdf文件

在python中加速读取非常大的netcdf文件,python,numpy,netcdf,dask,python-xarray,Python,Numpy,Netcdf,Dask,Python Xarray,我有一个非常大的netCDF文件,我正在用python中的netCDF4阅读它 我无法一次全部读取此文件,因为它的尺寸(1200 x 720 x 1440)太大,无法一次将整个文件存储在内存中。第一个维度代表时间,接下来的两个维度分别代表纬度和经度 import netCDF4 nc_file = netCDF4.Dataset(path_file, 'r', format='NETCDF4') for yr in years: nc_file.variables[variable_n

我有一个非常大的netCDF文件,我正在用python中的netCDF4阅读它

我无法一次全部读取此文件,因为它的尺寸(1200 x 720 x 1440)太大,无法一次将整个文件存储在内存中。第一个维度代表时间,接下来的两个维度分别代表纬度和经度

import netCDF4 
nc_file = netCDF4.Dataset(path_file, 'r', format='NETCDF4')
for yr in years:
    nc_file.variables[variable_name][int(yr), :, :]
然而,一年一次的阅读速度是极其缓慢的。对于下面的用例,我如何加快速度

--编辑

块大小为1

  • 我可以读取一系列年份:nc_文件。变量[变量名称][0:100,:,:]

  • 有几个用例:

    年数:

    numpy.ma.sum(nc_file.variables[variable_name][int(yr), :, :])
    



  • 检查文件的分块
    ncdump-s
    将给出答案。如果时间维度中的块大小大于1,则一次读取的年数应相同,否则一次从磁盘读取数年,一次仅使用一个。 慢到底有多慢?对于这种大小的数组,每个时间步最多几秒听起来是合理的。
    稍后提供有关您如何处理数据的更多信息,可能会为我们提供有关问题所在的更多指导。

    这有点老套,但可能是最简单的解决方案:


    将文件的子集读入内存,然后cPickle()将文件读回磁盘以备将来使用。从pickle数据结构加载数据可能比每次解析netCDF都要快。

    我强烈建议您查看和项目。使用这些功能强大的工具,您可以轻松地将计算分块进行。这带来了两个好处:您可以对内存中不适合的数据进行计算,并且可以使用机器中的所有内核来获得更好的性能。您可以通过适当选择块大小来优化性能(请参阅)

    您可以通过执行以下简单操作从netCDF加载数据

    import xarray as xr
    ds = xr.open_dataset(path_file)
    
    如果要沿时间维度以年为单位对数据进行分块,请指定
    chunks
    参数(假设年坐标命名为“年”):

    由于其他坐标不出现在
    dict中,因此将为它们使用单个块。(请参阅文档中的更多详细信息。)。这对于您的第一个需求非常有用,您需要每年乘以一个2D数组。您只需执行以下操作:

    ds['new_var'] = ds['var_name'] * arr_2d
    
    现在,
    xarray
    dask
    正在惰性地计算结果。为了触发实际计算,您可以简单地要求
    xarray
    将结果保存回netCDF:

    ds.to_netcdf(new_file)
    
    计算是通过
    dask
    触发的,它负责将处理分块进行,从而能够处理内存中不适合的数据。此外,
    dask
    将负责使用所有处理器内核来计算块

    xarray
    dask
    项目仍然不能很好地处理块不能很好地“对齐”以进行并行计算的情况。因为在这种情况下,我们只在“年”维度中分块,所以我们希望没有问题

    如果要将两个不同的netCDF文件添加到一起,操作非常简单:

    ds1 = xr.open_dataset(path_file1, chunks={'year': 10})
    ds2 = xr.open_dataset(path_file2, chunks={'year': 10})
    (ds1 + ds2).to_netcdf(new_file)
    

    我提供了一个完整的工作示例,使用

    [1]中的
    
    将xarray作为xr导入
    将numpy作为np导入
    #加载样本数据并去掉其中的大部分:
    ds=xr.open_数据集('ECMWF_ERA-40_subset.nc',chunks={'time':4})
    ds.attrs={}
    ds=ds[[纬度、经度、时间、tcw']]
    ds
    出[1]:
    尺寸:(纬度:73,经度:144,时间:62)
    协调:
    *纬度(纬度)浮动3290.087.585.082.580.077.575.072.5。。。
    *经度(经度)浮动32 0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0。。。
    *时间日期时间64[ns]2002-07-01T12:00:00 2002-07-01T18:00:00。。。
    数据变量:
    tcw(时间、纬度、经度)浮动64 10.15 10.15 10.15 10.15。。。
    在[2]中:
    arr2d=np.one((73144))*3。
    arr2d.shape
    出[2]:
    (73, 144)
    在[3]中:
    myds=ds
    myds['new_var']=ds['tcw']*arr2d
    在[4]中:
    myds
    出[4]:
    尺寸:(纬度:73,经度:144,时间:62)
    协调:
    *纬度(纬度)浮动3290.087.585.082.580.077.575.072.5。。。
    *经度(经度)浮动32 0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0。。。
    *时间日期时间64[ns]2002-07-01T12:00:00 2002-07-01T18:00:00。。。
    数据变量:
    tcw(时间、纬度、经度)浮动64 10.15 10.15 10.15 10.15。。。
    新变量(时间、纬度、经度)浮动64 30.46 30.46 30.46 30.46 30.46。。。
    在[5]中:
    myds.to_netcdf('myds.nc'))
    xr.open_数据集('myds.nc'))
    出[5]:
    尺寸:(纬度:73,经度:144,时间:62)
    协调:
    *纬度(纬度)浮动3290.087.585.082.580.077.575.072.5。。。
    *经度(经度)浮动32 0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0。。。
    *时间日期时间64[ns]2002-07-01T12:00:00 2002-07-01T18:00:00。。。
    数据变量:
    tcw(时间、纬度、经度)浮动64 10.15 10.15 10.15 10.15。。。
    新变量(时间、纬度、经度)浮动64 30.46 30.46 30.46 30.46 30.46。。。
    在[6]中:
    (myds+myds)。至网络CDF('myds2.nc'))
    xr.open_数据集('myds2.nc'))
    出[6]:
    尺寸:(纬度:73,经度:144,时间:62)
    协调:
    *时间日期时间64[ns]2002-07-01T12:00:00 2002-07-01T18:00:00。。。
    *纬度(纬度)浮动3290.087.585.082.580.077.575.072.5。。。
    *经度(经度)浮动32 0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0。。。
    数据变量:
    tcw(时间、纬度、经度)浮动64 20.31 20.31 20.31 20.31 20.31。。。
    新的变量(时间、纬度、经度)浮动64 60.92 60.92 60.92 60.92 60.92。。。
    
    您确定读取任何其他内容(例如一次读取整个文件)会更快吗?你能试着用一个裁剪过的文件吗?完成了吗?一旦你读了一年的数据,你会用它做什么吗?你能读一系列的年吗,例如:
    [1997:2007,:,:]
    ?谢谢@hapulj,我能读一系列的年。有几个用例
    ds['new_var'] = ds['var_name'] * arr_2d
    
    ds.to_netcdf(new_file)
    
    ds1 = xr.open_dataset(path_file1, chunks={'year': 10})
    ds2 = xr.open_dataset(path_file2, chunks={'year': 10})
    (ds1 + ds2).to_netcdf(new_file)
    
    In [1]:
    
    import xarray as xr
    import numpy as np
    
    # Load sample data and strip out most of it:
    ds = xr.open_dataset('ECMWF_ERA-40_subset.nc', chunks = {'time': 4})
    ds.attrs = {}
    ds = ds[['latitude', 'longitude', 'time', 'tcw']]
    ds
    
    Out[1]:
    
    <xarray.Dataset>
    Dimensions:    (latitude: 73, longitude: 144, time: 62)
    Coordinates:
      * latitude   (latitude) float32 90.0 87.5 85.0 82.5 80.0 77.5 75.0 72.5 ...
      * longitude  (longitude) float32 0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0 ...
      * time       (time) datetime64[ns] 2002-07-01T12:00:00 2002-07-01T18:00:00 ...
    Data variables:
        tcw        (time, latitude, longitude) float64 10.15 10.15 10.15 10.15 ...
    
    In [2]:
    
    arr2d = np.ones((73, 144)) * 3.
    arr2d.shape
    
    Out[2]:
    
    (73, 144)
    
    In [3]:
    
    myds = ds
    myds['new_var'] = ds['tcw'] * arr2d
    
    In [4]:
    
    myds
    
    Out[4]:
    
    <xarray.Dataset>
    Dimensions:    (latitude: 73, longitude: 144, time: 62)
    Coordinates:
      * latitude   (latitude) float32 90.0 87.5 85.0 82.5 80.0 77.5 75.0 72.5 ...
      * longitude  (longitude) float32 0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0 ...
      * time       (time) datetime64[ns] 2002-07-01T12:00:00 2002-07-01T18:00:00 ...
    Data variables:
        tcw        (time, latitude, longitude) float64 10.15 10.15 10.15 10.15 ...
        new_var    (time, latitude, longitude) float64 30.46 30.46 30.46 30.46 ...
    
    In [5]:
    
    myds.to_netcdf('myds.nc')
    xr.open_dataset('myds.nc')
    
    Out[5]:
    
    <xarray.Dataset>
    Dimensions:    (latitude: 73, longitude: 144, time: 62)
    Coordinates:
      * latitude   (latitude) float32 90.0 87.5 85.0 82.5 80.0 77.5 75.0 72.5 ...
      * longitude  (longitude) float32 0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0 ...
      * time       (time) datetime64[ns] 2002-07-01T12:00:00 2002-07-01T18:00:00 ...
    Data variables:
        tcw        (time, latitude, longitude) float64 10.15 10.15 10.15 10.15 ...
        new_var    (time, latitude, longitude) float64 30.46 30.46 30.46 30.46 ...
    
    In [6]:
    
    (myds + myds).to_netcdf('myds2.nc')
    xr.open_dataset('myds2.nc')
    
    Out[6]:
    
    <xarray.Dataset>
    Dimensions:    (latitude: 73, longitude: 144, time: 62)
    Coordinates:
      * time       (time) datetime64[ns] 2002-07-01T12:00:00 2002-07-01T18:00:00 ...
      * latitude   (latitude) float32 90.0 87.5 85.0 82.5 80.0 77.5 75.0 72.5 ...
      * longitude  (longitude) float32 0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0 ...
    Data variables:
        tcw        (time, latitude, longitude) float64 20.31 20.31 20.31 20.31 ...
        new_var    (time, latitude, longitude) float64 60.92 60.92 60.92 60.92 ...