我正在尝试构建一个在python中读取复杂HDF5数据文件的库。
我遇到了一个问题,HDF5 Dataset
以某种方式实现了默认的数组协议(有时),这样当从它创建一个numpy数组时,它会转换为特定的数组类型。
In [8]: ds
Out[8]: <HDF5 dataset "two_by_zero_empty_matrix": shape (2,), type "<u8">
In [9]: ds.value
Out[9]: array([2, 0], dtype=uint64)
此Dataset
对象实现numpy数组协议,当数据集由数字组成时,它提供默认数组类型。
In [10]: np.array(ds)
Out[10]: array([2, 0], dtype=uint64)
但是,如果数据集不是数字,而是一些其他对象,正如您所期望的那样,它只使用类型为np.object
的numpy数组:
In [43]: ds2
Out[43]: <HDF5 dataset "somecells": shape (2, 3), type "|O8">
In [44]: np.array(ds2)
Out[44]:
array([[<HDF5 object reference>, <HDF5 object reference>,
<HDF5 object reference>],
[<HDF5 object reference>, <HDF5 object reference>,
<HDF5 object reference>]], dtype=object)
这种行为看起来很方便但在我的情况下它实际上很不方便,因为它干扰了我对数据文件的递归遍历。解决这个问题确实很困难,因为有很多不同的可能数据类型必须根据它们是对象的子项还是数组而有所不同。
我的问题是:有没有办法抑制默认数组创建协议,这样我就可以从想要转换为自然鸭类型的数据集对象中创建一个对象数组? / p>
也就是说,我想要这样的内容:np.array(ds, dtype=object)
,它会产生一个[<Dataset object of type int>, dtype=object]
而不是[3 4 5, dtype=int]
的数组。
但np.array(ds, dtype=np.object)
会引发IOError: Can't read data (No appropriate function for conversion path)
我认真地尝试了一些关于numpy数组协议工作的文档,并发现了很多,但我并不认为有人认为有人可能会想要这种行为。
答案 0 :(得分:1)
我可以理解Out[44]
的来源。它是一个包含指向对象的指针的数组,在这种情况下h5py
引用文件中的对象(我认为)。
np.array(ds, dtype=object)
你试图创造更像这样的东西,而不是正常的&#39;使用np.array(ds)
获得的数组? array([2, 0], dtype=uint64)
。
但什么是并行数组?带有指向ds
的指针的单个元素数组?或者是一个2元素数组,在文件的某处有指向2
和0
的指针?如果他们不是<HDF5 object reference>
怎么办?
在numpy
中,没有任何h5py
内容,我可以从值列表中创建一个对象数组:
In [104]: np.array([2,0], dtype=object)
Out[104]: array([2, 0], dtype=object)
或者我可以从一个空数组开始(填充None
)并分配值:
In [105]: x=np.empty((2,), dtype=object)
In [106]: x[0]=2
In [107]: x[1]=0
In [108]: x
Out[108]: array([2, 0], dtype=object)
我想你可以试试:
x[0] = ds[0]
or
x[:] = ds[:]
或制作单个元素对象数组
x = np.empty((), dtype=object)
x[()] = ds
我没有在我的Ipython会话中打开h5py
测试文件来测试它。
但我可以做一些奇怪的事情,比如制作一个包含自身的对象数组。我可以使用,但我无法显示它而不会出现递归错误。
In [118]: x=np.empty((),dtype=object)
In [119]: x[()]=x
In [120]: x1=x[()]
In [121]: x1==x
Out[121]: True
我在另一个终端上打开了一个小h5py
文件:
In [315]: list(f.keys())
Out[315]: ['d', 'x', 'y']
In [317]: f['d'] # the group
Out[317]: <HDF5 group "/d" (2 members)>
x
是一个字符串:
In [318]: f['x'] # a single element (a string)
Out[318]: <HDF5 dataset "x": shape (), type "|O4">
In [330]: f['x'].value
Out[330]: 'astring'
In [331]: np.array(f['x'])
Out[331]: array('astring', dtype=object)
y
是一个数组:
In [320]: f['y'][:]
Out[320]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [321]: f['y'].value
Out[321]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [322]: np.array(f['y'])
Out[322]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [323]: timeit np.array(f['y'])
1000 loops, best of 3: 364 µs per loop
In [324]: timeit f['y'].value
1000 loops, best of 3: 380 µs per loop
因此value
和array
的访问权限相同。
作为object
数组访问会产生与您相同的错误。
In [325]: np.array(f['y'],dtype=object)
...
OSError: can't read data (Dataset: Read failed)
转换为float工作正常:
In [326]: np.array(f['y'],dtype=float)
Out[326]: array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
对预定义对象数组的赋值有效:
In [327]: x=np.empty((),dtype=object)
In [328]: x[()]=f['y']
In [329]: x
Out[329]: array(<HDF5 dataset "y": shape (10,), type "<i4">, dtype=object)
尝试创建一个10元素数组来取y
:
In [332]: y1=np.empty((10,),dtype=object)
In [333]: y1[:]=f['y']
...
OSError: can't read data (Dataset: Read failed)
In [334]: y1[:]=f['y'].value
In [335]: y1
Out[335]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=object)
y1[:]=f['y'][:]
也有效
我无法将数据集分配给y1
(与我尝试np.array(f['y'],dtype=object)
时的错误相同。但我可以分配其值。我甚至可以将数据集分配给{{1}的一个元素}}
y1
我一直回到基本思想,即对象数组只是指针的集合,本质上是数组包装器中的列表。