使用 h5py 读取 matlab .mat 文件

Read a matlab .mat file using h5py

我想使用 Python3 包 h5py 读取 7.3 版本的 matlab .mat 文件。

它包含一个matlab中的变量,名为results

里面包含一个1*1的cell,里面的struct里面的值就是我需要的

在matlab中,我可以通过以下代码获取这些数据:

load('.mat PATH');
results{1}.res

我应该如何在 h5py 中读取这些数据? 可以从 here

获得示例 .mat 文件

虽然 h5py 可以从 MATLAB 读取 h5 文件,但要弄清楚其中的内容需要一些探索 - 查看 keys groupsdatasets (可能还有 attr)。 scipy 中没有任何内容可以帮助您(scipy.io.loadmat 适用于旧的 MATLAB 垫格式)。

使用下载的文件:

In [61]: f = h5py.File('Downloads/Basketball_ECO_HC.mat','r')
In [62]: f
Out[62]: <HDF5 file "Basketball_ECO_HC.mat" (mode r)>
In [63]: f.keys()
Out[63]: <KeysViewHDF5 ['#refs#', 'results']>
In [65]: f['results']
Out[65]: <HDF5 dataset "results": shape (1, 1), type "|O">
In [66]: arr = f['results'][:]
In [67]: arr
Out[67]: array([[<HDF5 object reference>]], dtype=object)
In [68]: arr.item()
Out[68]: <HDF5 object reference>

我必须检查 h5py 文档以查看是否可以进一步检查该对象引用。我不熟悉。

但探索另一个 key:

In [69]: list(f.keys())[0]
Out[69]: '#refs#'
In [70]: f[list(f.keys())[0]]
Out[70]: <HDF5 group "/#refs#" (2 members)>
In [71]: f[list(f.keys())[0]].keys()
Out[71]: <KeysViewHDF5 ['a', 'b']>
In [72]: f[list(f.keys())[0]]['a']
Out[72]: <HDF5 dataset "a": shape (2,), type "<u8">
In [73]: _[:]
Out[73]: array([0, 0], dtype=uint64)
In [74]: f[list(f.keys())[0]]['b']
Out[74]: <HDF5 group "/#refs#/b" (7 members)>
In [75]: f[list(f.keys())[0]]['b'].keys()
Out[75]: <KeysViewHDF5 ['annoBegin', 'fps', 'fps_no_ftr', 'len', 'res', 'startFrame', 'type']>
In [76]: f[list(f.keys())[0]]['b']['fps']
Out[76]: <HDF5 dataset "fps": shape (1, 1), type "<f8">
In [77]: f[list(f.keys())[0]]['b']['fps'][:]
Out[77]: array([[22.36617883]])

在 OS shell 中,我可以用 h5dump 查看文件。由此看来 res 数据集的数据最多。数据集也有属性。这可能是获得概览的更好方法,并用它来指导 h5py 负载。

In [80]: f[list(f.keys())[0]]['b']['res'][:]
Out[80]: 
array([[198., 196., 195., ..., 330., 328., 326.],
       [214., 214., 216., ..., 197., 196., 192.],
       [ 34.,  34.,  34., ...,  34.,  34.,  34.],
       [ 81.,  81.,  81., ...,  81.,  80.,  80.]])
In [81]: f[list(f.keys())[0]]['b']['res'][:].shape
Out[81]: (4, 725)
In [82]: f[list(f.keys())[0]]['b']['res'][:].dtype
Out[82]: dtype('<f8')

如果您的问题是一般性询问如何读取在 Python 中使用 v7.3 保存的 matfile,hdf5storage 包提供了一些可能适合您的实用程序。对于您的文件(安装软件包后),您将 运行

In [0]: import hdf5storage as hdf5
In [1]: pyIn = LoadMatFile('Basketball_ECO_HC.mat')
In [2]: type(pyIn)                                                                                                                                             
Out[2]: dict
In [3]: pyIn.keys()                                                                                                                                             
Out[3]: dict_keys(['results'])
In [4]: type(pyIn['results'])                                                                                                                                   
Out[4]: numpy.ndarray
In [5]: pyIn['results'].shape                                                                                                                                   
Out[5]: (1, 1)
In [6]: pyIn['results'].dtype                                                                                                                                   
Out[6]: dtype('O')
In [7]: pyIn['results'][0,0].dtype                                                                                                                              
Out[7]: dtype([('type', '<U4', (1, 1)), ('res', '<f8', (725, 4)), ('fps', '<f8', (1, 1)), ('fps_no_ftr', '<f8', (1, 1)), ('len', '<f8', (1, 1)), ('annoBegin', '<f8', (1, 1)), ('startFrame', '<f8', (1, 1))])

你可以看到它在解析输入数组方面做得很好,尽管它做了一些事情,比如将你在 Matlab 中使用 results{1}{1} 访问的单元格折叠成一个二维 numpy 数组您改为使用 pyIn['results'][0,0] 访问。我 运行 对该数据进行的另一件奇怪的事情是在更深层次的结构字段中添加了一个维度,如下所示:

In [8]: pyIn['results'][0,0]['res'].shape                                                                                        
Out[8]: (1, 725, 4)
In [9]: pyIn['results'][0,0]['res'][0,0,:]                                                                                                                      
Out[9]: array([198., 214.,  34.,  81.])

不完全确定为什么会发生这种情况,但总的来说它应该运行良好。

就是说,我 运行 解决了这个包的最新版本 (0.2) 的问题,对于非常深的 array/cell/structure 组合,它变​​得非常慢。好消息是这个包仍在维护中,所以可能正在修复这个问题。尽管如此,这促使我为 matfiles 编写自己的 h5py reader,这在这些情况下更快,我将把它作为另一个答案进行讨论。

正如我在 hd5fstorage package, I have run into problems of it being far too slow when it comes to loading deep arrays. So I implemented my own matfile loader 上的其他 post 中提到的,如果您关心如何将 v7.3 matfile 读入的细节,其代码可能也更有用(因为它很紧凑) Python 有效。 (也就是说,代码目前的评论很少,所以可能没那么有用。)

对于我的图书馆,输出与 hdf5storage 非常相似,如此处所示。

In [0]: from MatFileMethods import LoadMatFile
In [1]: pyIn = LoadMatFile('/Users/emilio/Downloads/Basketball_ECO_HC.mat')
In [2]: type(pyIn)
Out[2]: dict
In [3]: pyIn.keys()
Out[3]: dict_keys(['results'])
In [4]: type(pyIn['results'])
Out[4]: numpy.ndarray
In [5]: pyIn['results'].shape
Out[5]: (1, 1)

请注意,与 hdf5storage 包一样,使用 results{1}{1} 调用的 Matlab 中的单元格中的单元格变为二维 numpy.ndarray 调用pyIn['results'][0,0],如下所示。

In [6]: type(pyIn['results'][0,0])
Out[6]: dict
In [7]: pyIn['results'][0,0].keys()
Out[7]: dict_keys(['annoBegin', 'fps', 'fps_no_ftr', 'len', 'res', 'startFrame', 'type'])
In [8]: pyIn['results'][0,0]['res'].shape
Out[8]: (725, 4)
In [9]: pyIn['results'][0,0]['res'][0,:]
Out[9]: array([198., 214.,  34.,  81.])

hdf5storage相比,我选择将Matlab结构做成Python字典,这样结构的字段就是字典的键。

在任何情况下,这个模块都没有经过全面测试,但已经很好地加载了 ~500Mb 和更大的 mat 文件,hdf5storage0.2 版本似乎无法处理(我自己的加载器大约需要 1.5 分钟,而 hdf5storage 的加载时间超过 10 分钟(它在 10 分钟内还没有完成加载))。 (我会注意到,与 Matlab 自己的 <15 秒加载时间相比,1.5 分钟仍然相形见绌,因此仍有改进的空间...)