type
status
password
date
slug
summary
category
URL
tags
icon
1. HDF5简介
Hierarchical Data Format(HDF)是一种针对大量数据进行组织和存储的文件格式。它包含了数据模型,库,和文件格式标准。现在HDF5还支持了大数据技术和NoSQL技术,并广泛用于科研,金融,以及其他科学和工程领域。当然批评者也认为HDF5格式具有以下缺点:
- 设计古老,定制化设置冗长
- 尽管有150多页的公开标准,但HDF5的非官方实现非常少
- HDF5没有强制使用UTF8编码,因此客户为了兼容型只好采用ASCII编码
- 存储的数据不能没有外部工具(如h5repack)的情况下自由的提取和复制。
2. HDF5文件结构
2.1 group
为了方便数据的组织,HDF5文件通过group的方式组织成树状结构。每个group相当于一个文件夹,其中可以包含一个或多个 dataset 及其它的 group
2.2 dataset
每一个dataset包含Metadata和Data两部分。其中Metadata包含Data相关的信息,而Data则包含数据本身。
2.2.1 Metadata
用于描述的元数据包括,Dataspaces、Datatypes、Properties和Attributes(可选).
- Dataspaces:给出原始数据的秩 (Rank) 和维度 (dimension)
- Datatypes:数据类型,分为预定义数据类型和衍生数据类型
- 预定义数据类型:通过HDF5创建的数据,在所有支持的平台通用。
- 衍生数据类型:由预定义数据类型衍生而来,例如字符串和嵌套的数据类型。
- Properties:说明该 dataset 的分块储存以及压缩情况
- Attributes:为该 dataset 的其他自定义属性
3. H5PY实战
特别要注意的是,一定要在操作结束后关闭对象。因为之前的操作只是生成操作的流程,并不真正执行操作,只有关闭对象操作才会真正出发对对象进行的修改。
3.1 文件(Files)创建/打开/关闭
模式 | 操作 | 当文件不存在时 | 是否覆盖 |
r | 只能读 | 报错 | - |
r+ | 可读可写 | 报错 | - |
w | 只能写 | 创建 | 是 |
w+ | 可读可写 | 创建 | 是 |
a | 可读可写 | 创建 | 否,追加写 |
3.2 群(Group)的建立
Python中将文件树表述成一个dict,keys值是groups成员的名字,values是成员对象(groups或者datasets)本身。文件对象本身作为root group。
3.3 数据集(Dataset)的创建
新的数据集可以通过group.create_dateset()或者group.require_dateset()记性创建。已经存在的数据已可以通过群的所以语法进行访问dset = group[“dset_name”]。
3.4 数据集读取与子集索引(Subsetting)
3.4.1 Python部分
h5py库采用numpy的切片语法来读写文件中的数据集,因此熟悉numpy的索引规则用起HDF5的“hyperslab”选择是非常容易的,这也是快速读且HDF5文件中数据集的方法。
下面是四个能够被识别的用法
- 索引
- 切片(比如[:]或者[0:10])
- 域名,在符合数据中使用
- 最多一个省略(Ellipsis),即(…),对象
例如
花式索引(Fancy Indexing)
一部分numpy花式索引在HDF5中也支持,比如
单使用受到一些限制
- 选择列表不能为空
- 选择坐标必须要以升序方式给出
- 重复项忽略
- 长列表(>1k元素)将速度很慢
numpy的逻辑索引可以用来进行选择,比如
和numpy一样,*len()函数返回dataset中第一个轴的长度。但是如果在32位平台上第一个轴长度超过2^32时len(dataset)将失效,因此推荐使用dataset.len()*方法。
3.4.2 C/C++部分
在C语言中,访问原数据集子集的关键在于构造内存的dataspace,通过内存和文件中dataspace的配合实现访问选择子集的效果。在HDF5中,有两种选择,元素(element)选择和超块(hyperslab)选择,分别通过函数*H5Sselect_elements()和H5Sselect_hyperslab()*两个函数实现。这两个函数都会修改传入dataspace_id对应的dataspace空间性质,以此实现选择的子集。
和MPI的子集选择方法相同,HDF5的子集选择定义子集四大件:
- offset: 位置补偿
- stride: 间隙
- count: 块数
- block: 块大小
例如想要从一个(8,10)的dataspace中选择一个如图(7,4)的dataspace,需要定义的四大件如下。
C/C++代码
3.5 添加注释——创建属性(Attribute)
属性是一种dataset的元数据(metadata),它描述了数据的相关信息,可以把属性理解成注释,所有的group和datasets都支持属性。
h5py采用dataset.attrs方法访问属性,比如
C/C++代码
3.6 数据压缩(Compression)
HDF5的数据集默认是连续空间存储的。单可以通过设置让HDF5把数据进行分块(chunked)存储,也就是说将数据分割为固定大小的小块分开存储,再通过B-Tree进行索引。
分块存储的方式是的数据集可以改变大小,也可以进行压缩过滤。
块的分割大小大概在10KiB到1MiB之间,数据集越大,则块也相应越多。分块以后数据读取将整块郑块的进行,如果对分块干到困惑,python中允许可以直接使用h5py的自动大小(chunks=True)
有了分块的数据集,就可以对数据集进行压缩了,通过无损的压缩过滤器可以将数据集进行无损失的压缩,利用函数group.create_dateset(compression=“filter”)。
常见的无损压缩过滤器有
- GZIP过滤器(“gzip”): 每个HDF5的标配,中等速度高压缩率,具有参数compression_opts取值从0到9控制压缩等级,默认值为4
- LZF过滤器(“lzf”): 快速但压缩率中等的压缩器
- SZIP过滤器(“szip”): NASA开发的专利保护压缩器
pandas方法
项目 | 创建 | 添加 | 创建索引 | 查询 | 存储 |
put(index=False,data_columns=True)
append(data_columns=True) | 19.41 | 230.92 | ㅤ | 75.29 | 81MB |
put(index=False,data_columns=True)
append(data_columns=True) | 19.15 | 225.65 | ㅤ | 75.49 | 81MB |
put(index=False)
append(index=False,data_columns=False) | 18.64 | 18.62 | ㅤ | 失败 | 7.57MB |
put(index=False)
append(index=False,data_columns=False)
create_table_index(columns=True) | 18.82 | 18.95 | 27.03 | 失败 | 40.3MB |
put(index=False,data_columns=True)
append(index=False,data_columns=False) | 19.53 | 19.55 | ㅤ | 92.80 | 7.58MB |
put(index=False,data_columns=True)
append(index=False,data_columns=True) | 19.23 | 19.41 | ㅤ | 94.39 | 7.58MB |
put(index=False,data_columns=True)
append(index=False,data_columns=True)
create_table_index(columns=True) | 19.34 | 19.59 | 207.38 | 282.67 | 81MB |
经过测试发现添加数据的时候;如果设置
index=True
,写入速度会变慢。打开文件
- path:字符型输入,用于指定h5文件的名称
- mode:用于指定读写模式
模式 | 操作 | 当文件不存在时 | 是否覆盖 |
r | 只能读 | 报错 | - |
r+ | 可读可写 | 报错 | - |
w | 可读可写 | 创建 | 是 |
a | 可读可写 | 创建 | 否,追加写 |
- complevel:int型,用于控制h5文件的压缩水平,取值范围在0-9之间,越大则文件的压缩程度越大,占用的空间越小,但相对应的在读取文件时需要付出更多解压缩的时间成本,默认为0,代表不压缩
写文件
put函数
往HDF中添加一张数据表, 以key作为索引。如果有数据表,那么进行覆盖
- key:存储路径
- index:将index作为列
- append:是否可以添加数据,如果需要添加数据,那么format必须为table
- append:是否可以添加数据,如果需要添加数据,那么format必须为table
- data_columns:创建列名
append函数
- key:存储路径
- index:将index作为列
- append:是否可以添加数据,如果需要添加数据,那么format必须为table
- append:是否可以添加数据,如果需要添加数据,那么format必须为table
- data_columns:创建列名
创建索引
项目 | 创建 | 添加 | 创建索引 | 查询 | 存储 |
put(index=False,data_columns=True)
append(index=False,data_columns=True) | 10.59 | 10.54 | ㅤ | 11.91 | 161MB |
put(index=True,data_columns=True)
append(index=True,data_columns=True) | 152.21 | 190.63 | ㅤ | 12 | 892MB |
put(index=False,data_columns=True)
append(index=False,data_columns=True)
create_table_index(columns=True) | 10.69 | 10.67 | 257.03 | 12 | 928MB |
put(index=True,data_columns=True)
append(index=True,data_columns=True)
与上面所有测试不同。上述所有测试的index是数字,本项测试的index是datetime | 96.65 | 112.67 | ㅤ | 6.54 | 671MB |
经过测试发现添加数据的时候;如果设置
index=True
,写入速度会变慢。删除——remove函数
查询——select函数
要查询的列必须有索引
符号 | 描述 | 符号 | 描述 | 符号 |
= | == | > | ㅤ | < |
!= | ㅤ | >= | ㅤ | <= |
| | ㅤ | & | ㅤ | () |
- where:相当于sql里面的where
- cloumns:相当于sql里面的select
- chunksize:迭代器