使用 h5py 读取 matlab .mat 文件

Posted

技术标签:

【中文标题】使用 h5py 读取 matlab .mat 文件【英文标题】:Read a matlab .mat file using h5py 【发布时间】:2021-02-23 04:19:55 【问题描述】:

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

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

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

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

load('.mat PATH');
results1.res

我应该如何在 h5py 中读取这些数据? 示例.mat文件可以从here获取

【问题讨论】:

【参考方案1】:

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

使用下载的文件:

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')

【讨论】:

【参考方案2】:

如果您的问题一般是询问如何在 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 中使用 results11 访问的单元格中的单元格折叠成您使用 @ 访问的二维 numpy 数组987654324@ 代替。我遇到的另一个奇怪的事情是在更深的结构字段中添加了一个维度,如下所示:

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) 的问题,对于真正深的数组/单元格/结构组合,它变​​得异常缓慢。好消息是该软件包仍在维护中,因此可能正在对此进行修复。尽管如此,这促使我为 matfiles 编写自己的 h5py 阅读器,这在这些情况下更快,我将作为另一个答案讨论它。

【讨论】:

【参考方案3】:

正如我在关于 hd5fstorage 包的另一篇文章中提到的,我遇到了加载深度数组时速度太慢的问题。所以我实现了my own matfile loader,如果您关心如何将 v7.3 matfile 读入 Python 工作的细节,它的代码也可能更有用(因为它很紧凑)。 (也就是说,代码目前只有很少的 cmets,所以可能没那么有用。)

对于我的库,输出与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 包一样,Matlab 中使用results11 调用的cell-within-a-cell 变成了使用pyIn['results'][0,0] 调用的二维numpy.ndarray,如下所示。

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 dicts,这样结构的字段就是字典的键。

在任何情况下,这个模块都没有经过全面测试,但对于加载 ~500Mb 和 hdf5storage 版本 0.2 似乎无法处理的更大 mat 文件(我的自己的装载机与hdf5storage 的 >10 分钟加载时间(它在 10 分钟时还没有完成加载))。 (我会注意到,与 Matlab 自己的

【讨论】:

以上是关于使用 h5py 读取 matlab .mat 文件的主要内容,如果未能解决你的问题,请参考以下文章

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

python写入和读取h5、pkl、mat 文件

matlab中如何读取mat文件的矩阵

matlab如何批量读取mat文件中的矩阵?

matlab,怎样读取多个mat文件再保存为一整个矩阵mat文件?

matlab读取.mat文件中的指定数据