用python读写.mat文件——使用scipy库的scipy.io和h5py库

python 中的scipy库和h5py库

1 读.mat文件:

1.1 用scipy.io读取

在用python处理matlab的mat文件时,发现数据量较小的文件可以直接通过scipy库的scipy.io读取:

import scipy.io as scio 
data = scio.loadmat(path)

通过type(data)可以看到,读取出来的data是字典类型。由于最近在做ECG(心电图)和EEG(脑电图),原始信号均以.mat文件储存。所以这里的data就以一段ECG信号为例(大小为30M),用print大法一探究竟:

print('data:\n',data)     		    #大致看一下data的结构
print('datatype:\n',type(data)) 	#看一下data的类型
print('keys:\n',data.keys)  		#查看data的键,这里验证一下是否需要加括号
print('keys:\n',data.keys())		#当然也可以用data.values查看值
print(data['EKG'])      		    #查看数据集
print('target shape\n',data['EKG'].shape)

输出结果:

data:
{'__header__': b'MATLAB 5.0 MAT-file, Platform: PCWIN64, Created on: Wed Feb 19 20:44:08 2020', 
'__version__': '1.0', '__globals__': [], 
'EKG': array([[0.],
       [0.],
       [0.],
       ...,
       [0.],
       [0.],
       [0.]])}

datatype:
 <class 'dict'>

keys:
 <built-in method keys of dict object at 0x000001F1B0791EA8>

keys:
 dict_keys(['__header__', '__version__', '__globals__', 'EKG'])

[[0.]
 [0.]
 [0.]
 ...
 [0.]
 [0.]
 [0.]]

target shape 
(8642000, 1)

上面的输出结果可以看到,原始的EKG信号是以列保存的。若要转换成行,我的做法是结合强大的numpy进行转置(data[‘ECG’].T),处理的效率很高。

所以如果需要用python提取原始信号,只要知道变量的名字,就可以通过键-值对的方式索引得到。其他数据信息做法相同。

1.2 用h5py库读取

这里尝试读取一个比较大的文件(1G多),包含111人的EEG信号(signal),每个人的数字代号,以及各信号所属的睡眠时期(labels),用h5py.File读取:

import h5py
data = h5py.File()

查看一下类型等信息:

print('data\n',data)
print('datatype\n',type(data))
print('keys\n',data.keys())
print(data['ipeo'])
print(data['labels'])
print(data['signal'])

输出结果:

data
 <HDF5 file "DeepLearn_all_4.mat" (mode r+)>

datatype
 <class 'h5py._hl.files.File'>

keys
 <KeysViewHDF5 ['ipeo', 'labels', 'signal']>

<HDF5 dataset "ipeo": shape (97014, 1), type ">
<HDF5 dataset "labels": shape (97014, 1), type ">
<HDF5 dataset "signal": shape (3750, 97014), type ">

可以看到,data中的3个k键,以dataset储存数据。111人的数据加起来总共有97014条信息,通常来说应该是按行表示的,在matlab中也确实是按行来表示,像变量ipeo,labels都是一维向量,而signal则是97014 × 3750 的矩阵。而用h5py读取出来,就自动转置了(这里我理解成进行了一次压缩),所以如果读取后要对其做相应的处理,则需要再转置回来,用numpy高效且简洁:

signal = np.array(load_data["signal"],dtype =').T
labels = np.array(load_data["labels"],dtype ='uint8').T[0]
ipeo = np.array(load_data["ipeo"],dtype ='uint8').T[0]

因为labels和ipeo转置后,数据储存于两层列表中,所以选外层列表的第0项,以去掉外层列表。

1.3 小节

在读取.mat文件时,我发现h5py库是和scipy.io互补的。当.mat文件比较大,或是在matlab储存的方法不同时,尝试用scipy.io读取会报错,这时用h5py通常可以读取成功。反之,如果用h5py能成功读取的文件(通常比较大),则用scipy.io无法读取成功。

ps:目前遇到的情况就是这样的耐人寻味,可能和电脑的内存有关。具体原因,以后慢慢研究

2 写.mat

2.1 用scipy.io写入

这里用到了scio的savemat方法:

import scipy.io as scio 

scio.savemat(save_path,{'EKG':split_EKG}) 

一般情况下的写入,对scio.savemat传入两个参数:保存路径,要保存的变量就可以保存了。要保存的变量同样是以字典的形式传入的,可以用键-值对的形式传入多个变量。

2.2 用h5py写入

原本尝试了用h5py创建数据集,并保存的方法:

h5file = h5py.File(save_path,'w')
h5file.create_dataset('labels', data=labels)
h5file.create_dataset('signal', data=signal)
h5file.close()

之后发现用matlab无法打开,报错显示没有用二进制写入。因为如果只是’w’的话,h5file写入的是.h5文件而非.mat文件。所以试着将第一行改写为:

h5f = h5py.File(save_path,'wb')

保存说只能是’r’,‘w’,'a’这种,不能以二进制写。所以就先保存成.h5文件,即,将save_path中的文件后缀写成.h5,然后用matlab对.h5处理,转成.mat文件。

这里参照这篇博文:用matlab处理.h5尾缀的数据集并转化为.mat(.h5转.mat)
因为之前读取后对数据进行了一次转置,所以在后面用matlab读取h5文件时,会发现数据是又被转置过的,应该是保存的时候自动进行的转置。对于matlab,需要在变量后加" ’ "号重新转置。

最后附上h5文件的简介:h5文件简介

你可能感兴趣的:(用python读写.mat文件——使用scipy库的scipy.io和h5py库)