在python中加速读取非常大的netcdf文件
我有一个非常大的netCDF文件,我正在用python中的netCDF4阅读它 我无法一次全部读取此文件,因为它的尺寸(1200 x 720 x 1440)太大,无法一次将整个文件存储在内存中。第一个维度代表时间,接下来的两个维度分别代表纬度和经度在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
import netCDF4
nc_file = netCDF4.Dataset(path_file, 'r', format='NETCDF4')
for yr in years:
nc_file.variables[variable_name][int(yr), :, :]
然而,一年一次的阅读速度是极其缓慢的。对于下面的用例,我如何加快速度
--编辑
块大小为1
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 ...