【问题标题】:how to compress lists/nested lists in hdf5如何在 hdf5 中压缩列表/嵌套列表
【发布时间】:2021-06-03 20:09:54
【问题描述】:

我最近了解了 hdf5 压缩并使用它。在处理巨大的文件时,它比 .npz/npy 有一些优势。 我设法尝试了一个小列表,因为我有时会使用具有以下字符串的列表;

def write():
    test_array = ['a1','a2','a1','a2','a1','a2', 'a1','a2', 'a1','a2','a1','a2','a1','a2', 'a1','a2', 'a1','a2','a1','a2','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', data=repr(test_array), dtype='S', compression='gzip', 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, in h5py.h5t.py_create
  File "h5py/h5t.pyx", line 1689, in h5py.h5t.py_create
  File "h5py/h5t.pyx", line 1508, in h5py.h5t._c_string
ValueError: Size must be positive (size must be positive)

在网上搜索了几个小时以找到更好的方法后,我无法获得。 有没有更好的方法来用 H5 压缩列表?

【问题讨论】:

    标签: arraylist compression hdf5 h5py pytables


    【解决方案1】:

    你很接近。 data= 参数旨在与现有的 NumPy 数组一起使用。当您使用 List 时,它会在幕后转换为 Array。它适用于数字列表。 (请注意,列表和数组是不同的 Python 对象类。)

    您在转换字符串列表时遇到了问题。默认情况下,dtype 设置为 NumPy 的 Unicode 类型(在您的情况下为“HDF5 不支持宽字符。如果您尝试存储这种类型的数据,h5py 将引发错误,而不是试图解决这个问题并“假装”支持它。" 有关 NumPy 和字符串的完整详细信息,请访问此链接:h5py doc: Strings in HDF5

    我稍微修改了您的示例以展示如何使其工作。请注意,我明确创建了 NumPy 字符串数组,并声明了 dtype='S2' 以获取所需的字符串 dtype。我添加了一个使用整数列表的示例,以显示列表如何处理数字。 然而,NumPy 数组是首选的数据对象。

    我删除了f.close() 语句,因为在使用上下文管理器(with / as: 结构)时不需要这样做

    另外,请注意压缩级别。与compression_opts=1 相比,compression_opts=9 将获得(稍微)更多的压缩,但每次访问数据集时都会支付 I/O 处理时间。我建议从 1 开始。

    import h5py
    import numpy as np
    
    test_array = np.array(['a1','a2','a1','a2','a1','a2', 'a1','a2', 
                           'a1','a2','a1','a2','a1','a2', 'a1','a2', 
                           'a1','a2','a1','a2','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='gzip', compression_opts=1) 
    

    【讨论】:

    • 哇。我喜欢这个。你也尝试过嵌套列表吗?尽管我也对嵌套列表感兴趣,但我会接受这一点。感谢您的努力!!!!
    • HDF5 支持嵌套数组。它更复杂,但可以完成。你能举个例子吗?警告:最大的复杂性是检查嵌套列表的大小。通常,HDF5 数据集使用固定的形状(大小),因此您必须在创建它们之前了解每个数据集的形状。
    • 我列出了它们都是相等的 len(): pp =my_ list, chunks = [pp[x:x+700] for x in range(0, len(pp), 700 )],那么 data_list 将是我的“块”
    • 我注意到在读取h5文件时; hf = h5py.File('drugrx_nested.h5', 'r') data = hf['test3'][:],列表带有字节字符串:[b'a1',b'a2',b'a1 ',b'a2',b'a1',b...']。有什么方法可以代替生成字符串?
    • 你有一个字节串数组。你必须解码它们。有几种方法可以做到这一点。最简单的方法是将.astype('U') 添加到您的数据语句中(这会将它们转换为Unicode)——例如data = hf['test3'][:].astype('U')。有关其他方法,请参阅此 SO 答案:How to decode a numpy array of encoded strings
    【解决方案2】:

    这是嵌套列表的更通用答案,其中每个嵌套列表的长度不同。当嵌套列表长度相等时,它也适用于更简单的情况。有两种解决方案:一种使用 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', 'w') as f:
         f.create_dataset('test3', data=test_array, compression='gzip')
    

    PyTables 示例
    PyTables 支持参差不齐的二维数组作为 VLArrays(可变长度)。这避免了为“短”子字符串添加“无”值的复杂性。此外,您不必提前确定数组长度,因为创建 VLArray 时未定义行数(创建后添加行)。同样,请注意dtype= 条目。这使用与上述相同的方法。

    import tables as tb
    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']]
       
    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))
    

    【讨论】:

    • 非常感谢您的帮助!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    相关资源
    最近更新 更多