我有一个 4 维的 netCDF 文件。我想通过给出其中一个维度的名称来从 netCDF 文件中提取切片
我知道如何按位置执行此操作。例如
from netCDF4 import Dataset
hndl_nc = Dataset(path_to_nc)
# Access by slice
hndl_nc.variables['name_variable'][:,5,:,:]
鉴于我知道尺寸的名称,请说
A
、B
、C
、D
。如何通过维度名称而不是位置进行访问?
您可以使用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))
所以,我可能想出了一些可以称为“解决方案”的东西。
numpy 数组显然可以使用可迭代的单例列表进行索引,例如
a = np.reshape(range(0,16),(4,4),order='F')
a = a[ [[0,1], [1]] ]
返回
a
等于 array([4,5])
。另一个例子是[[range(3),[1 2],3]]
。这些单例列表以 *subscripts
的方式展开,就好像您直接查询 a[[0,1],1]
而不是 a[ [[0,1],1] ]
。
因此,如果您能够查询 netCDF 变量中每个维度的位置和长度(使用
nc_fid[var].dimension
和 nc_fid[var].shape
非常简单),那么您可以简单地根据每个维度的位置排列列表。例如,如果您有按 lon 按 lat 的形状时间数据,并且需要 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
测试后,似乎全整数索引存在一些特殊的延迟,例如list_query = [0,0,0,0]
将需要 80ms,而 list_query = [range(1),0,0,0]
甚至 list_query = [[0,1,2,3,4,5],0,0,0]
将需要 1ms。非常神秘;无论如何,显然你应该尝试确保 list_query
不仅仅是一个整数列表。
目前最接近的解决方案似乎是
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
方法之间的主要差异。
希望有人对此提出更完整的答案;对于不同的数据集非常有用。