pytables 添加重复子类作为列

pytables add repetitive subclass as column

我正在创建一个具有严格参数的 HDF5 文件。它有 1 table 个由可变列组成的。在某一时刻,这些列随着附加的不同数据而变得重复。显然,我无法在 IsDescription class 内添加循环。目前 class 段已在 class Summary_data 下添加了两次。我需要调用 segments_k 70 次。最好的方法是什么?谢谢。

class Header(IsDescription):
    _v_pos    = 1
    id        = Int16Col(dflt=1, pos = 0)
    timestamp = Int16Col(dflt=1, pos = 1)

class Segments(IsDescription):
    segment_id      = Int16Col(dflt=1, pos = 0)
    segment_quality = Float32Col(dflt=1, pos = 1)
    segment_length  = Float32Col(dflt=1, pos = 2)

class Summary_data(IsDescription):
    latency     = Float32Col(dflt=1, pos = 2)
    segments_k  = Int16Col(dflt=1, pos = 4)
    segments_k0 = Segments()
    segments_k1 = Segments()

class Everything(IsDescription):
    header       = Header()
    summary_data = Summary_data()
    
def write_new_file():
    h5file = "results.hdf5"
    with open_file(h5file, mode = "w") as f:
        root    = f.root
        table1  = f.create_table(root, "Table1", Everything)
        row     = table1.row
        length  = [[23.5, 16.3], [8, 6]]
        quality = [[0.9, 0.7], [0.6, 0.4]]
        for i in range(2):
            row['header/id'] = i
            row['header/timestamp'] = i * 2.
            row['summary_data/latency'] = 0.0
            row['summary_data/segments_k'] = 0

            for data in range(2):
                row['summary_data/segments_k'+str(data)+'/segment_id'] = data
                row['summary_data/segments_k'+str(data)+'/segment_quality'] = quality[data][i]
                row['summary_data/segments_k'+str(data)+'/segment_length'] = length[data][i]
            row.append()

抱歉,我没有听懂您在评论中的解释。下面是来自 HDFView 的屏幕截图,显示了 schema/table 布局。在我看来,segments_k0{0}segments_k1{0} 嵌套在 summary_data 下。 查看它如何显示 summary_data->segments_k0{0}。那是你要的吗? 70 个嵌套列,每个列有 3 个嵌套列(segment_idsegment_qualitysegment_length)?

或者,您只想将 segments_k0{0} 嵌套在 0 行下。? 我使用该架构创建了第二个 table (Table2)。请参阅下面的屏幕截图。 请注意 segments_k0{0} 前面没有 summary_data->(它不是嵌套的)。

当您使用 np.dtype() 输入描述时,这两种情况都可能发生。您可以使用字典定义数据类型并以编程方式填充字段名称和格式。第二个 table 更容易定义。在向您展示如何创建 np.dtype().

之前,我想确定您想要哪个

好的,我想我明白了,我将尝试解释我是如何做到这一点的(以及如何扩展以处理所有 70 个段)。顺便说一句,您的嵌套字段非常复杂,比我见过的任何东西都复杂得多。您确定需要这么多级别的嵌套字段吗?

关键是使用 np.dtype() 来定义 table 描述。我总是使用它们来定义我的 tables,而不是 IsDescription 方法。 (我使用 NumPy 来处理我的 HDF5 数据,所以我对这个模块很满意table。)在你的情况下,你需要一个 dytpe,因为这是我知道的创建复杂 table 的唯一方法结构与代码。否则,您将花费数小时创建 IsDescription 个整体。 :-)

下面的代码使用 3 种不同的方法来创建 3 个 table(每个 table 中的架构和数据应该相同)。每个的解释:

  1. Table 1:是用您的代码创建的。它使用 IsDescription 方法创建 3 summary_data/segments_k# 个条目。 (我将 segments_k2 = Segments() 添加到 class Summary_data() )。注意这行代码: print (tb.description.dtype_from_descr(Everything) )。它打印 Table1 使用的 Everything 描述的等效 np.dtype。 我在下面的 Tables 2 和 3 中引用了这个。
  2. Table 2 描述引用 np.dtype tb2_dt。我 copied/pasted 这来自之前的输出。我可以引用为变量, 但我希望您看到它以了解我为 Table 所做的工作 3. 填充 table 的代码与 Table 1.
  3. 相同
  4. Table 3 描述引用 np.dtype tb3_dt。这就是事情变得棘手的地方。 np.dtype 结构很复杂:它是元组的列表和列表的元组。 dtype 是从 seg_kn_listtb3_dt_list 构建的。填充 table 的代码与 Table 1 和 2.
  5. 相同

要使其适用于 70 个段,您“所有”要做的就是更改创建 seg_kn_tlist 的 2 个 range(3) 参数并填充数据行。 (当然,你也需要提供数据。)

代码如下:

    import tables as tb
    import numpy as np

    h5file = "SO_64449277np.h5"
    with tb.open_file(h5file, mode = "w") as h5f:
        length  = [[23.5, 16.3], [8, 6], [11.0, 7.7]]
        quality = [[0.9, 0.7], [0.6, 0.4], [0.8, 0.5]]

        root    = h5f.root
        table1  = h5f.create_table(root, "Table1", Everything)
        print (tb.description.dtype_from_descr(Everything) )

        row     = table1.row
        for i in range(2):
            row['header/id'] = i
            row['header/timestamp'] = i * 2.
            row['summary_data/latency'] = 0.0
            row['summary_data/segments_k'] = 0

            for data in range(3):
                row['summary_data/segments_k'+str(data)+'/segment_id'] = data
                row['summary_data/segments_k'+str(data)+'/segment_quality'] = quality[data][i]
                row['summary_data/segments_k'+str(data)+'/segment_length'] = length[data][i]
            row.append()

        tb2_dt = np.dtype([('header', [('id', '<i2'), ('timestamp', '<i2')]), 
                           ('summary_data', [('latency', '<f4'), ('segments_k', '<i2'), 
                           ('segments_k0', [('segment_id', '<i2'), ('segment_quality', '<f4'), ('segment_length', '<f4')]), 
                           ('segments_k1', [('segment_id', '<i2'), ('segment_quality', '<f4'), ('segment_length', '<f4')]),
                           ('segments_k2', [('segment_id', '<i2'), ('segment_quality', '<f4'), ('segment_length', '<f4')]),
                           ])] )

        table2  = h5f.create_table(root, "Table2", tb2_dt)
        row     = table2.row
        for i in range(2):
            row['header/id'] = i
            row['header/timestamp'] = i * 2.
            row['summary_data/latency'] = 0.0
            row['summary_data/segments_k'] = 0

            for data in range(3):
                row['summary_data/segments_k'+str(data)+'/segment_id'] = data
                row['summary_data/segments_k'+str(data)+'/segment_quality'] = quality[data][i]
                row['summary_data/segments_k'+str(data)+'/segment_length'] = length[data][i]
            row.append()

# Create np.dtype() iteratively
# Start with laency and segments_k, and use a loop to add segments_k# id, quality and length
            
        seg_kn_tlist = [('latency', '<f4'), ('segments_k', '<i2') ]
        for cnt in range(3) :            
            seg_kn_tlist.append( ('segments_k'+str(cnt), 
                                [('segment_id', '<i2'), ('segment_quality', '<f4'), ('segment_length', '<f4')] ) ) 
 
# Finish np.dtype() definition with fileds for header, timestamp and summary_data, followed by tuple with list above         
        tb3_dt_list = [ ('header', [('id', '<i2'), ('timestamp', '<i2')]), ('summary_data', seg_kn_tlist) ]
        
        tb3_dt = np.dtype( tb3_dt_list ) 

        table3  = h5f.create_table(root, "Table3", tb3_dt)
        row     = table3.row
        for i in range(2):
            row['header/id'] = i
            row['header/timestamp'] = i * 2.
            row['summary_data/latency'] = 0.0
            row['summary_data/segments_k'] = 0

            for data in range(3):
                row['summary_data/segments_k'+str(data)+'/segment_id'] = data
                row['summary_data/segments_k'+str(data)+'/segment_quality'] = quality[data][i]
                row['summary_data/segments_k'+str(data)+'/segment_length'] = length[data][i]
            row.append()