引:在使用TensorFlow,学习回调函数时,使用了ModelCheckpoint(),产生了.h5的文件。为了了解回调函数产生的信息,需要了解HDF5的相关内容,以及在python中的使用与相关问题解决。
文中一些叙述为了方便初次接触者理解,表述并不严谨,仅供简单参考。
HDF5(Hierarchical Data Formal)是用于存储大规模数值数据的较为理想的存储格式,文件后缀名为h5,存储读取速度非常快,且可在文件内部按照明确的层次存储数据,同一个HDF5可以看做一个高度整合的文件夹,其内部可存放不同类型的数据。
在Python中操纵HDF5文件的方式主要有两种
本篇主要介绍hdf5的基础内容和对应模块使用的快速入门。
一段小插曲
HDF是HDF(Hierarchical Data File)是美国国家高级计算应用中心(National Center for Supercomputing Application,NCSA)为了满足各种领域研究需求而研制的一种能高效存储和分发科学数据的新型数据格式 。阅读的文档中提到了到国家卫星气象中心(NSMC)曾经发布过一份《HDF5.0 使用简介》,抱着些许迷信权威的心态阅读后发现它涉及的信息就我目前来说价值不大,其中主要有讲HDF5文件的组织,API,创建,数据集数据空间,组群,属性等等,内容大而全,但似乎这篇教材发布的相对较早,所以产生了一定的局限性并且内部的相关URL都失效了,它本身也在国家卫星气象中心的官网上没有什么存在的痕迹。相关的API只涉及了C和FORTRAN的外壳包装函数。对于像我这样在使用python且第一次接触HDF5的使用者并不友好,索性只读了开头的基础内容并建立了更详细的认知后就放弃了继续阅读的打算。
首先从hdf5文件讲起。
HDF5文件具有两类存储对象,dataset和group。dataset是类似于数组的数据集,而group是类似文件夹一样的容器,存放dataset和其他group。
HDF本意即是层次数据格式,所以就其存储结构来说是类似与POSIX风格的。其实现的方式就是group。每层都用’/'分隔。我们创建的file object其实也可以看作一个group,是一个root group,其余的groups可以称为subgroups。
dataset与numpy中的array相似,比如都具有shape、dtype、以及一些切片操作等。虽然与Numpy的数组在接口上很相近,但是支持更多对外透明的存储特征,如数据压缩,误差检测,分块传输。
HDF5的一个很好的features就是可以在数据旁边存储元数据1。所有的group和dataset都支持叫做属性的数据形式。
想到python一定有对应的文件解析库,于是我开始了h5py的“快速”入门。
import h5py
# 读取
file = h5py.File('test.hdf5', 'r')# .hdf5与.h5意义相同
# 一下也可以完成读取
with h5py.File("mytestfile.hdf5", "w") as f:
# 我们需要注意的是group(包括File对象)与python中的字典相似
# 通过该方法可以获得对应group下的subgroups或datasets,返回包含字符串的列表
f.keys()
# 此时我们假设存在一个名为DataSet的dataset对象
# 利用对应键来索引值的方法可以获取该对象
dest = f['DataSet']
# dataset对象满足我们平时使用的numpy数组的一些操作,如下:
dest.shape
dest.dtype
dest[:]
# 创建HDF5文件
f = h5py.File('test.h5', 'w')
# 使用create_dataset创建给定形状和数据类型的空dataset
dataset = f.create_dataset('DS',(100,), dtype='i')
# 也可以使用numpy中数组来初始化
array = np.arange(100)
dataset = f.create_dataset('init', data=array)
# 分块存储
'''
在缺省设置下,HDF5数据集在内存中是连续布局的,也就是按照传统的C序。
Dataset也可以在HDF5的分块存储布局下创建。
也就是dataset被分为大小相同的若干块随意地分布在磁盘上,并使用B树建立索引。
'''
# 为了进行分块存储,将关键字设为一个元组来指示块的形状。
dset = f.create_dataset("chunked", (1000, 1000), chunks=(100, 100))
# 也可以自动分块,不必指定块的形状。
dset = f.create_dataset("autochunk", (1000, 1000), chunks=True)
# 分层结构
# 遍历subgroups
for name in f:
print(name)
# 递归遍历所有subgroups
def print_name(name):
print(name)
f.visit(print_name)
# 属性通过attrs成员访问,类似于python中词典格式。
dataset.attrs['bias'] = 60
'bias' in dataset.attrs
一些其他的特性
dset = f.create_dataset("zipped", (100, 100), compression="gzip")
更多信息
pandas中的HDFStore()用于生成管理HDF5文件IO操作的对象,其主要参数如下:
path:字符型输入,用于指定h5文件的名称(不在当前工作目录时需要带上完整路径信息)
mode:用于指定IO操作的模式,与Python内建的open()中的参数一致,默认为’a’,即当指定文件已存在时不影响原有数据写入,指定文件不存在时则新建文件;‘r’,只读模式;‘w’,创建新文件(会覆盖同名旧文件);‘r+’,与’a’作用相似,但要求文件必须已经存在;
complevel:int型,用于控制h5文件的压缩水平,取值范围在0-9之间,越大则文件的压缩程度越大,占用的空间越小,但相对应的在读取文件时需要付出更多解压缩的时间成本,默认为0,代表不压缩
下面我们创建一个HDF5 IO对象store:
import pandas as pd
store = pd.HDFStore('demo.h5')
'''查看store类型'''
print(store)
<class 'pandas.io.pytables.HDFStore'>
File path: demo.h5
可以看到store对象属于pandas的io类,通过上面的语句我们已经成功的初始化名为demo.h5的的文件,本地也相应的出现了对应文件。
接下来我们创建pandas中不同的两种对象,并将它们共同保存到store中,首先创建series对象:
import numpy as np
#创建一个series对象
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
#创建一个dataframe对象
df = pd.DataFrame(np.random.randn(8, 3),
columns=['A', 'B', 'C'])
第一种方式利用键值对将不同的数据存入store对象中,这里为了代码简洁使用了元组赋值法:
store['s'],store['df'] = s,df
第二种方式利用store对象的put()方法,其主要参数如下:
key:指定h5文件中待写入数据的key
value:指定与key对应的待写入的数据
format:字符型输入,用于指定写出的模式,'fixed’对应的模式速度快,但是不支持追加也不支持检索;'table’对应的模式以表格的模式写出,速度稍慢,但是支持直接通过store对象进行追加和表格查询操作
使用put()方法将数据存入store对象中:
store.put(key='s',value=s);store.put(key='df',value=df)
既然是键值对的格式,那么可以查看store的items属性(注意这里store对象只有items和keys属性,没有values属性):
store.items
调用store对象中的数据直接用对应的键名来索引即可:
store['df']
删除store对象中指定数据的方法有两种,一是使用remove()方法,传入要删除数据对应的键:
store.remove('s')
print(store.keys())
二是使用Python中的关键词del来删除指定数据:
del store['s']
print(store.keys())
这时若想将当前的store对象持久化到本地,只需要利用close()方法关闭store对象即可:
store.close()
'''查看store连接状况,False则代表已关闭'''
store.is_open
# 这时本地的h5文件也相应的存储进store对象关闭前包含的文件
除了通过定义一个确切的store对象的方式,还可以从pandas中的数据结构直接导出到本地h5文件中:
#创建新的数据框
df_ = pd.DataFrame(np.random.randn(5,5))
#导出到已存在的h5文件中,这里需要指定key
df_.to_hdf(path_or_buf='demo.h5',key='df_')
#创建于本地demo.h5进行IO连接的store对象
store = pd.HDFStore('demo.h5')
#查看指定h5对象中的所有键
print(store.keys())
store = pd.HDFStore('demo.h5')
'''方式1'''
df1 = store['df']
'''方式2'''
df2 = store.get('df')
df1 == df2
可以看出这两种方式都能顺利读取键对应的数据。
第二种读入h5格式文件中数据的方法是pandas中的read_hdf(),其主要参数如下:
path_or_buf:传入指定h5文件的名称
key:要提取数据的键
需要注意的是利用read_hdf()读取h5文件时对应文件不可以同时存在其他未关闭的IO对象,否则会报错,如下例:
print(store.is_open)
df = pd.read_hdf('demo.h5',key='df')
把IO对象关闭后再次提取:
store.close()
print(store.is_open)
df = pd.read_hdf('demo.h5',key='df')
df
参考:
https://blog.csdn.net/yudf2010/article/details/50353292
https://segmentfault.com/a/119000001667088
https://www.cnblogs.com/feffery/p/11135082.html
元数据是关于数据的组织、数据域及其关系的信息,简言之,元数据就是关于数据的数据。 ↩︎