【问题标题】:Can I store my own class object into hdf5?我可以将自己的类对象存储到 hdf5 中吗?
【发布时间】:2016-08-24 13:39:21
【问题描述】:

我有这样的课:

class C:
     def __init__(self, id, user_id, photo):
         self.id = id
         self.user_id = user_id
         self.photo = photo

我需要创建数百万个这样的对象。 id 和 user_id 一样是整数,但 photo 是大小为 64 的 bool 数组。我的老板希望我将它们全部存储在 hdf5 文件中。我还需要能够根据他们的 user_id 属性进行查询,以获取所有具有相同 user_id 的照片。首先,我如何存储它们?甚至我可以吗?其次,一旦我存储(如果可以)它们,我该如何查询它们?谢谢。

【问题讨论】:

    标签: python hdf5


    【解决方案1】:

    虽然您可以将整个数据结构存储在单个 HDF5 表中,但将所描述的类存储为三个单独的变量可能要容易得多 - 两个 1D 整数数组和一个用于存储“照片”属性的数据结构。

    如果您关心文件大小和速度而不关心文件的人类可读性,您可以将 64 个布尔值建模为 UINT8 的 8 个 1D 数组或 UINT8 的 2D 数组 N x 8(或 CHAR) .然后,您可以实现一个简单的接口,将您的布尔值打包成 UINT8 位并返回(例如,How to convert a boolean array to an int array

    据了解,HDF5 中没有内置搜索功能,但您可以读取包含 user_ids 的变量,然后简单地使用 Python 查找与您的 user_id 匹配的所有元素的索引。

    获得索引后,您可以读取其他变量的相关切片。 HDF5 原生支持高效切片,但它适用于范围,因此您可能想考虑如何将具有相同 user_id 的记录存储在连续的块中,请参阅此处的讨论

    h5py: Correct way to slice array datasets

    您可能还想研究 pytables - 一种基于 hdf5 构建的 Python 接口,用于将数据存储在类似表的结构中。

    import numpy as np
    import h5py
    
    
    class C:
        def __init__(self, id, user_id, photo):
            self.id = id
            self.user_id = user_id
            self.photo = photo
    
    def write_records(records, file_out):
    
        f = h5py.File(file_out, "w")
    
        dset_id = f.create_dataset("id", (1000000,), dtype='i')
        dset_user_id = f.create_dataset("user_id", (1000000,), dtype='i')
        dset_photo = f.create_dataset("photo", (1000000,8), dtype='u8')
        dset_id[0:len(records)] = [r.id for r in records]
        dset_user_id[0:len(records)] = [r.user_id for r in records]
        dset_photo[0:len(records)] = [np.packbits(np.array(r.photo, dtype='bool').astype(int)) for r in records]
        f.close()
    
    def read_records_by_id(file_in, record_id):
        f = h5py.File(file_in, "r")
        dset_id = f["id"]
        data = dset_id[0:2]
        res = []
        for idx in np.where(data == record_id)[0]:
            record = C(f["id"][idx:idx+1][0], f["user_id"][idx:idx+1][0], np.unpackbits( np.array(f["photo"][idx:idx+1][0],  dtype='uint8') ).astype(bool))
            res.append(record)
        return res 
    
    m = [ True, False,  True,  True, False,  True,  True,  True]
    m = m+m+m+m+m+m+m+m
    records = [C(1, 3, m), C(34, 53, m)]
    
    # Write records to file
    write_records(records, "mytestfile.h5")
    
    # Read record from file
    res = read_records_by_id("mytestfile.h5", 34)
    
    print res[0].id
    print res[0].user_id
    print res[0].photo
    

    【讨论】:

    • 非常感谢您的帮助。尽管您提供的信息非常重要,但由于我们将进行写入操作,我无法将数据存储在连续的块中。我想我将不得不使用 mongodb 进行存储。
    • 你真的应该尝试填充一个 HDF5 文件,看看性能是否可以接受。对于您的数据类型,使用 mongo 可能确实有意义,请记住,您可以在单个集合中存储的内容有 16MB 的上限。
    • @Maksym 我有类似的用例,但是代替 photo 属性,我有形状的 numpy ndarray (1024, 768, 3) 并且这是可变的,我关心速度和时间但不关心可读性,你有什么建议?
    • @Avoid 您是否受到读取时间、写入时间或查询时间的限制?如果您有大量数据的恒定流,那么查看 parquet (parquet.apache.org/documentation/latest) 或其他支持流的格式可能是有意义的。此外,只要您的 shape(1024, 768, 3) 数组与 user_id 和其他属性的类型相同 - 您可以将完整记录存储为平面一维数组并在读取时重新整形。
    • 另外,为了更正我之前的评论 - Mongo 中集合中单个记录的 16MB 上限,而不是集合本身。
    猜你喜欢
    • 2018-06-25
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    • 2017-02-08
    • 1970-01-01
    • 2014-04-15
    • 1970-01-01
    相关资源
    最近更新 更多