问题描述
我最近了解了 hdf5 压缩并使用它。在处理巨大文件时,它比 .npz/npy 有一些优势。 我设法尝试了一个小列表,因为我有时会使用具有如下字符串的列表;
def write():
test_array = ['a1','a2','a1','a2']
with h5py.File('example_file.h5','w') as f:
f.create_dataset('test3',data=repr(test_array),dtype='S',compression='gzip',compression_opts=9)
f.close()
但是我遇到了这个错误:
f.create_dataset('test3',compression_opts=9)
File "/usr/local/lib/python3.6/dist-packages/h5py/_hl/group.py",line 136,in create_dataset
dsid = dataset.make_new_dset(self,shape,dtype,data,**kwds)
File "/usr/local/lib/python3.6/dist-packages/h5py/_hl/dataset.py",line 118,in make_new_dset
tid = h5t.py_create(dtype,logical=1)
File "h5py/h5t.pyx",line 1634,in h5py.h5t.py_create
File "h5py/h5t.pyx",line 1656,line 1689,line 1508,in h5py.h5t._c_string
ValueError: Size must be positive (size must be positive)
在网上搜索了几个小时以寻找更好的方法后,我无法得到。 有没有更好的方法来用 H5 压缩列表?
解决方法
你很近。 data=
参数旨在处理现有的 NumPy 数组。当您使用 List 时,它会在幕后转换为 Array。它适用于数字列表。 (请注意,列表和数组是不同的 Python 对象类。)
您在转换字符串列表时遇到了问题。默认情况下,dtype 设置为 NumPy 的 Unicode 类型(在您的情况下为 '
我稍微修改了您的示例以展示如何使其工作。请注意,我显式创建了 NumPy 字符串数组,并声明了 dtype='S2'
以获得所需的字符串 dtype。我添加了一个使用整数列表的示例来展示列表如何处理数字。 然而,NumPy 数组是首选的数据对象。
我删除了 f.close()
语句,因为这在使用上下文管理器(with / as:
结构)时不是必需的
此外,请注意压缩级别。与 compression_opts=9
相比,compression_opts=1
将获得(稍微)更多的压缩,但每次访问数据集时,您都将支付 I/O 处理时间。我建议从 1 开始。
import h5py
import numpy as np
test_array = np.array(['a1','a2','a1','a2'],dtype='S2')
data_list = [ 1,2,3,4,5,6,7,8,9 ]
with h5py.File('example_file.h5','w') as f:
f.create_dataset('test3',data=test_array,compression='gzip',compression_opts=9)
f.create_dataset('test4',data=data_list,compression_opts=1)
,
这是嵌套列表的更一般的答案,其中每个嵌套列表的长度不同。当嵌套列表长度相等时,它也适用于更简单的情况。有两种解决方案:一种使用 h5py,一种使用 PyTables。
h5py 示例
h5py 不支持参差不齐的数组,因此您必须根据最长的子字符串创建一个数据集,并将元素添加到“短”子字符串中。
您将在嵌套列表中没有对应值的每个数组位置获得 'None'
(或子字符串)。请注意 dtype=
条目。这显示了如何找到列表中最长的字符串(如 slen=##)并使用它来创建 dtype='S##'
import h5py
import numpy as np
test_list = [['a01','a02','a03','a04','a05','a06'],['a11','a12','a13','a14','a15','a16','a17'],['a21','a22','a23','a24','a25','a26','a27','a28']]
# arrlen and test_array from answer to SO #10346336 - Option 3:
# Ref: https://stackoverflow.com/a/26224619/10462884
slen = max(len(item) for sublist in test_list for item in sublist)
arrlen = max(map(len,test_list))
test_array = np.array([tl+[None]*(arrlen-len(tl)) for tl in test_list],dtype='S'+str(slen))
with h5py.File('example_nested.h5',compression='gzip')
PyTable 示例
PyTables 支持不规则的二维数组作为 VLArrays(可变长度)。这避免了为“短”子字符串添加“无”值的复杂性。此外,您不必提前确定数组长度,因为在创建 VLArray 时未定义行数(创建后添加行)。再次注意 dtype=
条目。这使用与上面相同的方法。
import tables as tb
import numpy as np
test_list = [['a01','a28']]
slen = max(len(item) for sublist in test_list for item in sublist)
with tb.File('example_nested_tb.h5','w') as h5f:
vlarray = h5f.create_vlarray('/','vla_test',tb.StringAtom(slen) )
for slist in test_list:
arr = np.array(slist,dtype='S'+str(slen))
vlarray.append(arr)
print('-->',vlarray.name)
for row in vlarray:
print('%s[%d]--> %s' % (vlarray.name,vlarray.nrow,row))