加快阅读python中非常大的netcdf文件

use*_*827 13 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_name][int(yr), :, :]
Run Code Online (Sandbox Code Playgroud)

然而,一次阅读一年是非常缓慢的.如何加快以下用例的速度?

- 编辑

chunksize是1

  1. 我可以阅读一系列年份:nc_file.variables [variable_name] [0:100,:,]

  2. 有几个用例:

    多年来:

    numpy.ma.sum(nc_file.variables[variable_name][int(yr), :, :])
    
    Run Code Online (Sandbox Code Playgroud)

# Multiply each year by a 2D array of shape (720 x 1440)
for yr in years:
    numpy.ma.sum(nc_file.variables[variable_name][int(yr), :, :] * arr_2d)
Run Code Online (Sandbox Code Playgroud)
# Add 2 netcdf files together 
for yr in years:
    numpy.ma.sum(nc_file.variables[variable_name][int(yr), :, :] + 
                 nc_file2.variables[variable_name][int(yr), :, :])
Run Code Online (Sandbox Code Playgroud)

Ped*_*rte 23

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

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

import xarray as xr
ds = xr.open_dataset(path_file)
Run Code Online (Sandbox Code Playgroud)

如果要在时间维度上按年划分数据,则指定chunks参数(假设年坐标名为'year'):

ds = xr.open_dataset(path_file, chunks={'year': 10})
Run Code Online (Sandbox Code Playgroud)

由于其他坐标没有出现在chunksdict中,因此将使用单个块.(请在此处的文档中查看更多详细信息.)这对于您的第一个要求非常有用,您希望每年将其乘以2D数组.你只需要这样做:

ds['new_var'] = ds['var_name'] * arr_2d
Run Code Online (Sandbox Code Playgroud)

现在,xarraydask是计算你的结果懒洋洋地.为了触发实际计算,您可以简单地要求xarray将结果保存回netCDF:

ds.to_netcdf(new_file)
Run Code Online (Sandbox Code Playgroud)

计算通过触发dask,其负责将处理分成块,从而使得能够处理不适合存储器的数据.此外,dask还将使用所有处理器内核来计算块.

xarraydask项目仍然没有很好地处理了的情况下块不"对齐"以及并行计算.因为在这种情况下我们只在"年"维度中进行了分类,所以我们希望没有问题.

如果要将两个不同的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)
Run Code Online (Sandbox Code Playgroud)

我使用在线提供的数据集提供了一个完整的工作示例.

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 ...
Run Code Online (Sandbox Code Playgroud)