按维度名称提取 netcdf4 变量切片

Extract netcdf4 variable slice by dimension name

我有一个 4 维的 netCDF 文件。我想通过给出其中一个维度的名称从 netCDF 文件中提取一个切片

我知道如何按位置执行此操作。例如

from netCDF4 import Dataset
hndl_nc = Dataset(path_to_nc)

# Access by slice
hndl_nc.variables['name_variable'][:,5,:,:]

鉴于我知道维度的名称,请说 ABCD。如何通过维度名称而不是位置访问?

您可以使用 xarray 的索引功能按维度名称访问 netcdf 数据。

import xarray as xr
ds = xr.open_dataset('./foo.nc')
var = ds['name_variable']
# Slice var by Dimension "A" between values 0 and 5
var_slice = var.sel(A=slice(0,5))

目前最接近的解决方案似乎是

np.take(nc4_variable[:],dim_ids,axis=dim)

nc4_variable[:].take(dim_ids,axis=dim)

其中 dim_ids 是切片的列表或元组,dim 是要切片的维度。不幸的是,这似乎首先加载了整个数据集,而且似乎没有办法解决这个问题; [:] 是必要的。在第一种方法中忽略它加载数据而不调整 add_offset_FillValue 等参数;在第二种方法中忽略它会产生错误。

在 Ipython 中使用 %timeit 进行的测试证实了正常切片与 np.take 方法之间的主要差异。

希望有人能对此给出更完整的答案;对于不同的数据集将非常有用。

所以,我可能想出了一些可以作为“解决方案”的东西。

numpy 数组显然可以用可迭代对象的单例列表进行索引,例如

a = np.reshape(range(0,16),(4,4),order='F')
a = a[ [[0,1], [1]] ]

returns a 等于 array([4,5])。另一个例子是 [[range(3),[1 2],3]]。这些单例列表以 *subscripts 的方式展开,就好像您直接查询了 a[[0,1],1] 而不是 a[ [[0,1],1] ].

因此,如果您能够查询 netCDF 变量中每个维度的位置和长度(使用 nc_fid[var].dimensionnc_fid[var].shape 非常容易),那么您可以根据每个维度的位置。例如,如果您有经纬度的形状时间数据,并且您想要 all 经度、all 纬度和时间索引 t=5,你可以使用像

这样的东西
order_want = ['lon', 'lat', 'time'] # must figure out dimension names a priori
nlon = nc_fid[var].shape[nc_fid[var].dimensions.index('lon')]
nlat = nc_fid[var].shape[nc_fid[var].dimensions.index('lat')]
ids = [ range(0,nlon), range(0,nlat), 5 ]
ids_permute = [order_want.index(n) for n in nc_fid[var].dimensions] 
ids_query = [l[i] for l,i in zip(ids,ids_permute)]

sliced_data = nc_fid[var][list_query]

这不需要维度位置的先验知识,并且不需要加载变量的所有维度。

请注意,在 IPython 中进行了一些 %timeit 测试后,all-integer 索引似乎有一些特殊的延迟,例如list_query = [0,0,0,0] 将花费 80mslist_query = [range(1),0,0,0] 甚至 list_query = [[0,1,2,3,4,5],0,0,0] 将花费 1ms。非常神秘;无论如何,显然你应该尝试确保 list_query 不仅仅是一个整数列表。