在用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提取原始信号,只要知道变量的名字,就可以通过键-值对的方式索引得到。其他数据信息做法相同。
这里尝试读取一个比较大的文件(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项,以去掉外层列表。
在读取.mat文件时,我发现h5py库是和scipy.io互补的。当.mat文件比较大,或是在matlab储存的方法不同时,尝试用scipy.io读取会报错,这时用h5py通常可以读取成功。反之,如果用h5py能成功读取的文件(通常比较大),则用scipy.io无法读取成功。
ps:目前遇到的情况就是这样的耐人寻味,可能和电脑的内存有关。具体原因,以后慢慢研究
这里用到了scio的savemat方法:
import scipy.io as scio
scio.savemat(save_path,{'EKG':split_EKG})
一般情况下的写入,对scio.savemat传入两个参数:保存路径,要保存的变量就可以保存了。要保存的变量同样是以字典的形式传入的,可以用键-值对的形式传入多个变量。
原本尝试了用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文件简介