如何通过h5py读取v7.3 mat文件?

时间:2013-10-11 05:24:28

标签: python matlab hdf5 mat h5py

我有一个由matlab创建的结构数组,并以v7.3格式存储在mat文件中:

struArray = struct('name', {'one', 'two', 'three'}, 
                   'id', {1,2,3}, 
                   'data', {[1:10], [3:9], [0]})
save('test.mat', 'struArray', '-v7.3')

现在我想通过python使用h5py来读取这个文件:

data = h5py.File('test.mat')
struArray = data['/struArray']

我不知道如何从struArray逐个获取结构数据:

for index in range(<the size of struArray>):
    elem = <the index th struct in struArray>
    name = <the name of elem>
    id = <the id of elem>
    data = <the data of elem>

5 个答案:

答案 0 :(得分:4)

Matlab 7.3文件格式使用h5py并不是非常容易。它依赖于HDF5参考,参见h5py documentation on references

>>> import h5py
>>> f = h5py.File('test.mat')
>>> list(f.keys())
['#refs#', 'struArray']
>>> struArray = f['struArray']
>>> struArray['name'][0, 0]  # this is the HDF5 reference
<HDF5 object reference>
>>> f[struArray['name'][0, 0]].value  # this is the actual data
array([[111],
       [110],
       [101]], dtype=uint16)

阅读struArray(i).id

>>> f[struArray['id'][0, 0]][0, 0]
1.0
>>> f[struArray['id'][1, 0]][0, 0]
2.0
>>> f[struArray['id'][2, 0]][0, 0]
3.0

请注意,Matlab将数字存储为大小(1,1)的数组,因此最终[0, 0]来获取数字。

阅读struArray(i).data

>>> f[struArray['data'][0, 0]].value
array([[  1.],
       [  2.],
       [  3.],
       [  4.],
       [  5.],
       [  6.],
       [  7.],
       [  8.],
       [  9.],
       [ 10.]])

要读取struArray(i).name,必须将整数数组转换为字符串:

>>> f[struArray['name'][0, 0]].value.tobytes()[::2].decode()
'one'
>>> f[struArray['name'][1, 0]].value.tobytes()[::2].decode()
'two'
>>> f[struArray['name'][2, 0]].value.tobytes()[::2].decode()
'three'

答案 1 :(得分:3)

visitvisititems是查看h5py文件整体结构的快捷方式:

fs['struArray'].visititems(lambda n,o:print(n, o))

当我在Octave save -hdf5生成的文件上运行时,我得到:

type <HDF5 dataset "type": shape (), type "|S7">
value <HDF5 group "/struArray/value" (3 members)>
value/data <HDF5 group "/struArray/value/data" (2 members)>
value/data/type <HDF5 dataset "type": shape (), type "|S5">
value/data/value <HDF5 group "/struArray/value/data/value" (4 members)>
value/data/value/_0 <HDF5 group "/struArray/value/data/value/_0" (2 members)>
value/data/value/_0/type <HDF5 dataset "type": shape (), type "|S7">
value/data/value/_0/value <HDF5 dataset "value": shape (10, 1), type "<f8">
value/data/value/_1 <HDF5 group "/struArray/value/data/value/_1" (2 members)>
...
value/data/value/dims <HDF5 dataset "dims": shape (2,), type "<i4">
value/id <HDF5 group "/struArray/value/id" (2 members)>
value/id/type <HDF5 dataset "type": shape (), type "|S5">
value/id/value <HDF5 group "/struArray/value/id/value" (4 members)>
value/id/value/_0 <HDF5 group "/struArray/value/id/value/_0" (2 members)>
...
value/id/value/_2/value <HDF5 dataset "value": shape (), type "<f8">
value/id/value/dims <HDF5 dataset "dims": shape (2,), type "<i4">
value/name <HDF5 group "/struArray/value/name" (2 members)>
...
value/name/value/dims <HDF5 dataset "dims": shape (2,), type "<i4">

这可能与MATLAB 7.3产生的不同,但它给出了结构复杂性的概念。

更精细的回调可以显示值,并且可以是重新创建Python对象(字典,列表等)的起点。

def callback(name, obj):
    if name.endswith('type'):
        print('type:', obj.value)
    elif name.endswith('value'):
        if type(obj).__name__=='Dataset':
            print(obj.value.T)  # http://stackoverflow.com/questions/21624653
    elif name.endswith('dims'):
        print('dims:', obj.value)
    else:
        print('name:', name)

fs.visititems(callback)

产生:

name: struArray
type: b'struct'
name: struArray/value/data
type: b'cell'
name: struArray/value/data/value/_0
type: b'matrix'
[[  1.   2.   3.   4.   5.   6.   7.   8.   9.  10.]]
name: struArray/value/data/value/_1
type: b'matrix'
[[ 3.  4.  5.  6.  7.  8.  9.]]
name: struArray/value/data/value/_2
type: b'scalar'
0.0
dims: [3 1]
name: struArray/value/id
type: b'cell'
name: struArray/value/id/value/_0
type: b'scalar'
1.0
...
dims: [3 1]
name: struArray/value/name
type: b'cell'
name: struArray/value/name/value/_0
type: b'sq_string'
[[111 110 101]]
...
dims: [3 1]

答案 2 :(得分:0)

我首先启动解释器并在help上运行struarray。它应该为您提供足够的信息来帮助您入门。如果不这样做,您可以通过print __dict__属性转储任何Python对象的属性。

答案 3 :(得分:0)

我很抱歉,但我认为从Matlab外部获取单元格/结构的内容将非常具有挑战性。如果您查看生成的文件(例如使用HDFView),您会看到有很多交叉引用,没有明显的方法可以继续。

如果你坚持使用简单的数值数组就可以了。如果你有包含数值数组的小单元格数组,你可以将它们转换为单独的变量(即cellcontents1,cellcontents2等),这些变量通常只有几行,并允许它们直接保存和加载。因此,在您的示例中,我将使用变量name1, name2, name3, id1, id2, id3 ...等保存文件。

编辑:你在问题中指定了h5py,这就是我所回答的,但值得一提的是,使用scipy.io.loadmat你应该能够将原始变量转换为numpy等价物(例如对象数组)。

答案 4 :(得分:-1)

Matlab 7.3和h5py确实存在问题。 我的诀窍是将h5py._hl.dataset.Dataset类型转换为numpy数组。 例如,

np.array(data['data'])

将使用'data'字段解决您​​的问题。