数据集文件格式
1. 简介
文件格式 | 扩展名 | |
---|---|---|
HDF5 | .h5 | H5文件是层次数据格式第5代的版本, 以key-value 的方式组织数据的一个容器 |
mat | .m或.mat | mat文件是Matlab的数据存储的标准格式(二进制或ASCII) |
2. HDF5
-
HDF5定义:
- H5文件是层次数据格式第5代的版本(Hierarchical Data Format,HDF5)
- 支持
n
维数据集,且数据集中的每个元素可以是一个复杂对象 - 以
key-value
的方式组织数据的一个容器
-
开发者
- 它是由美国超级计算与应用中心研发的文件格式,用以存储和组织大规模数据
- 目前由非营利组织HDF小组提供支持
-
用途:
- 很多商业和非商业组织都支持这种文件格式,如Java,MATLAB,Python,R等
- 在内存占用、压缩、访问速度方面都有非常优秀的特性,在工业领域和科学领域都有很多运用。
-
特点:
- 易于共享:是一个自描述的文件,所有数据和元数据均可保存在同一文件中
- 跨平台+多语言(C, C++, Python,Java等)
- 快速I/O:访问速度快、存储空间小
- 大数据:对数据对象的数量和大小均没有限制
- 在数据中包含元数据:流水型生命周期和管道
2.1 HDF5(.h5)文件结构
- H5将文件结构简化成两个主要的对象类型:
- 数据集(dataset):就是同一类型数据的多维数组。
- 组(group):是一种容器结构,可以包含数据集和其他组,类似于文件夹
- H5文件是一种真正的层次结构、文件系统式的数据类型
- 元数据:是由用户定义的,以命名属性的形式附加到组和数据集中。更复杂的存储形式如图像和表格可以使用数据集、组和属性来构建。
- HDF5源码
2.2 API
2.2.1 打开或创建h5py文件
- 函数定义
class File(name, mode=None, driver=None, libver=None, userblock_size=None, **kwds)
- mode说明:
- r: 只读,文件必须存在
- r+:读写,文件必须存在
- w:创建新文件写,已经存在的文件会被覆盖掉
- w- / x:创建新文件写,文件如果已经存在则出错
- a:打开已经存在的文件进行读写,如果不存在则创建一个新文件读写,此为默认的 mode
2.2.2 创建dataset数据集
create_dataset(self, name, shape=None, dtype=None, data=None, **kwds)
# name: 数据集的名字
# shape:以一个tuple或list的形式指明创建dataset的shape
- 示例代码
import h5py
import numpy as np
# 创建一个新文件
f=h5py.File("myh5py-1.h5","w")
# 分别创建dset1,dset2,dset3这三个数据集
# dset1:有现成的numpy数组,可以在创建数据集的时候就赋值,不必指定数据的类型和形状了,只需要把数组名传给参数data。
a=np.arange(20)
d1=f.create_dataset("dset1",data=a)
# dset2: 是数据集的name,(3,4)代表数据集的shape,i代表的是数据集的元素类型
d2=f.create_dataset("dset2",(3,4),'i')
d2[...]=np.arange(12).reshape((3,4)) #赋值
#直接按照下面的方式创建数据集并赋值
f["dset3"]=np.arange(15)
for key in f.keys():
print(f[key].name)
print(f[key].shape)
print(f[key].value)
- 输出
/dset1
(20,)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
/dset2
(3, 4)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
/dset3
(15,)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
2.2.3 创建group组(类似于文件夹)
- 函数定义
create_group(self, name, track_order=False)
- 示例代码
import h5py
import numpy as np
f=h5py.File("myh5py-3.hdf5","w")
#创建一个名字为bar的组
g1=f.create_group("bar")
#在bar这个组里面分别创建name为dset1,dset2的数据集并赋值。
g1["dset1"]=np.arange(10)
g1["dset2"]=np.arange(12).reshape((3,4))
for key in f.keys():
print(f[key].name)
print('==============')
for key in g1.keys():
print(g1[key].name)
print(g1[key].shape)
print(g1[key].value)
- 输出
/bar
==============
/bar/dset1
(10,)
[0 1 2 3 4 5 6 7 8 9]
/bar/dset2
(3, 4)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
2.2.4 混合模式
- 示例代码
import h5py
import numpy as np
f=h5py.File("myh5py-2.hdf5","w")
#创建组bar1,组bar2,数据集dset
g1=f.create_group("bar1")
g2=f.create_group("bar2")
d=f.create_dataset("dset",data=np.arange(10))
#在bar1组里面创建一个组car1和一个数据集dset1。
c1=g1.create_group("car1")
d1=g1.create_dataset("dset1",data=np.arange(10))
#在bar2组里面创建一个组car2和一个数据集dset2
c2=g2.create_group("car2")
d2=g2.create_dataset("dset2",data=np.arange(10))
#根目录下的组和数据集
print(".............")
for key in f.keys():
print(f[key].name)
#bar1这个组下面的组和数据集
print(".............")
for key in g1.keys():
print(g1[key].name)
#bar2这个组下面的组和数据集
print(".............")
for key in g2.keys():
print(g2[key].name)
#顺便看下car1组和car2组下面都有什么,估计你都猜到了为空。
print(".............")
print(c1.keys())
print(c2.keys())
- 输出
.............
/bar1
/bar2
/dset
.............
/bar1/car1
/bar1/dset1
.............
/bar2/car2
/bar2/dset2
.............
<KeysViewHDF5 []>
<KeysViewHDF5 []>
3. MAT
- mat数据格式是Matlab的数据存储的标准格式
- mat文件是标准的二进制文件,还可以ASCII码形式保存和加载,在Matlab中打开显示类似于单行EXCEL表格
- 在Matlab中主要使用load()函数导入一个mat文件,使用save()函数保存一个mat文件
3.1 MAT文件格式
- 在matlab version 5中,MAT文件由一个128字节的文件头和若干个数据单元组成。每个数据单元有一个8个字节的tag,用于说明数据单元的占用的字节数(不包括tag的8个字节)和数据类型
3.2 文件 头
- 文件头header里有124字节的文本描述区域和4个字节的flag
- Header代码说明
char mat_data_fhead1[51] = {"MATLAB 5.0 MAT-file, Platform: PCWIN, Created on: "};
char mat_data_fhead2[51] = {" "};
char mat_data_fhead3[4] = {0, 0x01, 0x49, 0x4d};
char* datetime = NULL;
time_t ltime;
tm* today;
time(ltime);
today = localtime(ltime);
datetime = asctime(today);
fwrite(mat_data_fhead1, 1, 50, fp);
fwrite(datetime, 1, 24, fp);
fwrite(mat_data_fhead2, 1, 50, fp);
fwrite(mat_data_fhead3, 1, 4, fp); # flag (4字节)
- flag(4字节)
- flag中的前2个字节说明version,后两个字节是endian indicator
- 文本描述区域主要说明MAT文件的版本,创建于哪个平台,创建时间
- flag中的version说明的是创建这个MAT文件的matlab的版本
- edian indicator包括两个字符M和I
- 关于edian:endian: The ordering of bytes in a multi-byte number
- Little-Endian:就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端
- Big-Endian:就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端
- 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序
- 若edian indicator中的值为MI,则读取MAT数据时应该用IM的顺序。若对于16bit的数据,则要进行两个字节数据的交换。
3.3 数据单元的格式
- 每个数据单元开头都有8个字节的tag用于说明数据单元存储的数据类型(datatype)和字节数(不包括tag的8个字节)
- 接下来的就是存储的数据。数据需要64bit对齐,不够时要补齐到64bit。数据类型是miMATRIX时,数据单元tag中字节数包括矩阵中每个padding的数据个数
- datatype值为14的数据类型是:array data,包括了各种类型的array,如数值矩阵,字符矩阵,稀疏矩阵
3.4 Python接口
- 在python中可以使用scipy.io中的函数读写mat文件:
- loadmat():读取mat文件
- savemat():保存mat文件
- 写入和读取的数据都是字典格式
- 示例代码
import scipy.io as scio
# write mat file
dataFile = "test.m"
data = {}
data['A'] = 'I am A'
data['B'] = 'I am B'
#scio.savemat(dataFile, {'A':data['A'], 'B':data['B']})
scio.savemat(dataFile, data)
# read mat file
data_r = scio.loadmat(dataFile)
print(data_r)
print(type(data_r))
for key in data_r.keys():
print(key,':', data_r[key])
- 输出
{'__header__': b'MATLAB 5.0 MAT-file Platform: nt, Created on: Thu Oct 22 09:58:25 2020', '__version__': '1.0', '__globals__': [], 'A': array(['I am A'], dtype='<U6'), 'B': array(['I am B'], dtype='<U6')}
<class 'dict'>
__header__ : b'MATLAB 5.0 MAT-file Platform: nt, Created on: Thu Oct 22 09:58:25 2020'
__version__ : 1.0
__globals__ : []
A : ['I am A']
B : ['I am B']