【问题标题】:Reading non-contiguous subsets of a variable in a fast way快速读取变量的非连续子集
【发布时间】:2018-01-30 16:03:29
【问题描述】:

我有一个netCDF4.Variable 对象:

<class 'netCDF4._netCDF4.Variable'>
int16 myvar(time, latitude, longitude)
    standard_name: my_var
    long_name: Something
    units: (0 - 1)
    add_offset: 0.499999843485
    scale_factor: 1.54488841466e-05
    _FillValue: -32767
    missing_value: -32767
unlimited dimensions: time
current shape = (13148, 1441, 2880)
filling off

此变量是 3D 变量,其中第一个维度是时间维度,第二个维度是空间维度。

我想访问该变量的一个子集,其中包含:

  • 时间范围的子集(例如,从 70008000)。
  • 由空间范围的扁平化版本中的索引标识的点的子集 - 在上面的示例中,索引的范围在 01441 * 2880 之间。

基本上,我有:

tmin = 7000
tmax = 8000
upts = [42829, 9289, 3242]

我目前的访问方式是:

z = np.zeros(len(upts),  tmax - tmin)
for i in range(tmin, tmax):
    z[:, i - tmin] = my_var[i, :, :].flatten()[upts]

我想知道是否有更快的方法来做到这一点?

我无法将整个数据集加载到内存中,因为它已经很大,而且可能更大。

我也不能只使用单个i,因为我想对z 的行(对应于my_var 中的“列”)进行操作。

【问题讨论】:

  • 我已经很久没用newCDF了,但你不能用my_var[tmin:tmax, :, upts]吗?这就是我使用 numpy 数组和 h5py 的方式。
  • @hpaulj 很抱歉,我完全忘记指定 upts 包含数组的扁平数组“空间”部分的索引。在此示例中,upts 值的范围可以从 01441 * 2880
  • 您是否有空间加载my_var[tmin:tmax,:,:],然后对数组进行upts 索引?与时间范围相比,upts 通常很小吗?如果必须迭代,请在最小范围内进行。
  • @hpaulj 大部分时间我都没有足够的空间,但如果您知道tmax - tmin 何时很小,我会很高兴听到。 upts 通常比 tmax - tmin 大,但不会大几个数量级。即使upts 接近tmax - tmin(或更小),我认为由于数据存储在netCDF(行主要)中的方式,迭代第一个维度要快得多。
  • 数据是否分块?如果是这样,访问它的最佳方式将取决于分块。对于大型 netCDF 文件,分块通常是个好主意。

标签: python python-3.x numpy netcdf


【解决方案1】:

不确定这是否在内存方面有效,但您是否考虑先从 python 外部的命令行使用 NCO 或 CDO 删除文件,然后从 python 读取该文件?这取决于您是否需要重复访问文件的不同块,或者这是否是一次性访问。

NCO 中 hyperslab 的命令是

ncks -d dim_name,val1,val2 in.nc -O out.nc 

如果 val 是整数,则使用索引进行切割,如果是浮点数,则根据维度的值进行切割。您可以在参数列表中放置多个维度。 (在这个答案中给出:NCO cropping a netcdf file using dimension values rather than indices

CDO 需要您似乎拥有的标准维度、纬度、经度和时间,因此您可以使用

切割一个经纬度框和一系列时间步长
cdo seltimestep,7000,8000 -sellonlatbox,lon1,lon2,lat1,lat2 in.nc out.nc

CDO 的优点是您还可以使用日期格式缩短时间。所以你可以使用

从 7000 减少到 8000
cdo seldate,yyyymmdd,yyyymmdd in.nc out.nc

我觉得非常有用。

根据我的经验,当 NCO 工作正常时,CDO 似乎会因内存需求而窒息,因此这可能会影响您的选择。无论如何,如果您需要反复挑选文件的不同部分,这个建议对您来说不是很有用,但希望对其他人有用。

【讨论】:

    【解决方案2】:

    如果您想以只读方式访问数据,则不必将子集中的所有元素复制到新列表中。相反,您可以只复制对列表的引用:

    z = [my_var[i] for i in range(tmin, tmax)]
    

    如果您需要一个可以在不影响整个集合的情况下编辑的子集副本,那么您必须像当前代码一样制作元素的副本。

    【讨论】:

    • 我想以只读方式访问数据,但我需要在z 中按列访问它们,所以我不能按照你的方式进行(除非我遍历列表,但这会慢一点)。
    • @Holt 我有点困惑,因为在您的问题中复制列表的代码会以时间作为第一个维度来复制它们。在您的代码和我的代码中,第二个空间维度是连续存储的。您希望连续存储哪个维度?
    • 是的,第一个维度是您示例中的时间是我的,但实际上我在循环之后转置了z,因为我希望空间维度连续存储。我已经尝试一次读取一个“列”并直接使用它,但这要慢得多,因为 netCDF(我认为)以行主要格式存储数据。我将更新我的问题以使这部分更清晰。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 2018-06-22
    相关资源
    最近更新 更多