【问题标题】:Creating reference to HDF dataset in H5py using astype使用 astype 在 H5py 中创建对 HDF 数据集的引用
【发布时间】:2014-10-04 03:39:57
【问题描述】:

h5py docs,我看到我可以使用数据集的astype 方法将HDF 数据集转换为另一种类型。这将返回一个上下文管理器,它会即时执行转换。

但是,我想读入存储为 uint16 的数据集,然后将其转换为 float32 类型。此后,我想从这个数据集中提取不同的切片,作为演员类型float32。文档将其用法解释为

with dataset.astype('float32'):
   castdata = dataset[:]

这会导致整个数据集被读入并转换为float32,这不是我想要的。我想引用数据集,但将其转换为 float32 等效于 numpy.astype。如何创建对.astype('float32') 对象的引用,以便将其传递给另一个函数以供使用?

一个例子:

import h5py as HDF
import numpy as np
intdata = (100*np.random.random(10)).astype('uint16')

# create the HDF dataset
def get_dataset_as_float():
    hf = HDF.File('data.h5', 'w')
    d = hf.create_dataset('data', data=intdata)
    print(d.dtype)
    # uint16

    with d.astype('float32'):
    # This won't work since the context expires. Returns a uint16 dataset reference
       return d

    # this works but causes the entire dataset to be read & converted
    # with d.astype('float32'):
    #   return d[:]

此外,似乎 astype 上下文仅在访问数据元素时才适用。这意味着

def use_data():
   d = get_data_as_float()
   # this is a uint16 dataset

   # try to use it as a float32
   with d.astype('float32'):
       print(np.max(d))   # --> output is uint16
       print(np.max(d[:]))   # --> output is float32, but entire data is loaded

那么就没有一种 numpy 式的使用 astype 的方式吗?

【问题讨论】:

  • 我不认为np.max(d) 在这里做了什么特别聪明的事情。由于d 没有自己的.max() 方法,np.max() 会将数组读入内存并在其上调用np.core.umath.maximum.reduce(),使用d.dtype 设置输出类型。 np.max(d)np.max(d[:]) 的时间几乎相同。
  • @ali_m 你可能是对的。我只是选择 np.max 作为查看数组上的操作是否返回 dtype 的方式。这对我的计算并不重要。我将主要提取我使用的切片。

标签: python numpy h5py hdf


【解决方案1】:

d.astype() 返回一个AstypeContext 对象。如果您查看AstypeContext 的来源,您会更好地了解发生了什么:

class AstypeContext(object):

    def __init__(self, dset, dtype):
        self._dset = dset
        self._dtype = numpy.dtype(dtype)

    def __enter__(self):
        self._dset._local.astype = self._dtype

    def __exit__(self, *args):
        self._dset._local.astype = None

当您输入 AstypeContext 时,您的数据集的 ._local.astype 属性会更新为所需的新类型,而当您退出上下文时,它会更改回其原始值。

因此,您可以或多或少地获得您正在寻找的行为,如下所示:

def get_dataset_as_type(d, dtype='float32'):

    # creates a new Dataset instance that points to the same HDF5 identifier
    d_new = HDF.Dataset(d.id)

    # set the ._local.astype attribute to the desired output type
    d_new._local.astype = np.dtype(dtype)

    return d_new

当您现在从d_new 读取时,您将返回float32 numpy 数组而不是uint16

d = hf.create_dataset('data', data=intdata)
d_new = get_dataset_as_type(d, dtype='float32')

print(d[:])
# array([81, 65, 33, 22, 67, 57, 94, 63, 89, 68], dtype=uint16)
print(d_new[:])
# array([ 81.,  65.,  33.,  22.,  67.,  57.,  94.,  63.,  89.,  68.], dtype=float32)

print(d.dtype, d_new.dtype)
# uint16, uint16

请注意,这不会更新d_new.dtype 属性(这似乎是不可变的)。如果您还想更改 dtype 属性,您可能需要继承 h5py.Dataset 才能这样做。

【讨论】:

  • 有趣。我确实查看了 AsTypeContext,但不确定自己设置 dtype 是否会产生一些不良后果。将做一些测试并回到这个答案。谢谢。
  • @arjmage 我认为应该没问题。 d._local 是一个 threading.local 对象,因此您的更改应该是线程安全的。你可以看到here d._local.dtype 只是用来设置输出numpy 数组的dtype 数据被读入。 d.dtype actually points to d.id.dtype,这是实际 HDF5 对象的标识符。
【解决方案2】:

astype 的文档似乎暗示将其全部读入新位置是其目的。因此,如果您要在不同的场合重用具有许多功能的浮点转换,那么您的 return d[:] 是最合理的。

如果你知道你需要强制转换并且只需要一次,你可以换个方向做类似的事情:

def get_dataset_as_float(intdata, *funcs):
    with HDF.File('data.h5', 'w') as hf:
        d = hf.create_dataset('data', data=intdata)
        with d.astype('float32'):
            d2 = d[...]
            return tuple(f(d2) for f in funcs)

无论如何,您要确保在离开函数之前关闭hf,否则您以后会遇到问题。

一般来说,我建议将数据集的转换和加载/创建完全分开,并将数据集作为函数的参数之一传递。

上面可以这样调用:

In [16]: get_dataset_as_float(intdata, np.min, np.max, np.mean)
Out[16]: (9.0, 87.0, 42.299999)

【讨论】:

    猜你喜欢
    • 2021-01-02
    • 2018-01-05
    • 2018-12-01
    • 1970-01-01
    • 2020-08-25
    • 2017-08-26
    • 2015-10-29
    • 2017-12-20
    • 1970-01-01
    相关资源
    最近更新 更多