11

我正在使用带有 Python 2.6 的 PyTables 2.2.1,我想创建一个包含可变长度嵌套数组的表。

我已经搜索了 PyTables 文档,教程示例(PyTables Tutorial 3.8)展示了如何创建一个长度为 1 的嵌套数组。但是对于这个示例,我如何将可变数量的行添加到 data 'info2/info3/x '和'info2/info3/y'?

为了更容易理解表结构,这是我自己开发的示例:

"""Desired Pytable output:

DIEM    TEMPUS  Temperature             Data
5       0       100         Category1 <--||-->  Category2
                         x <--| |--> y          z <--|
                        0           0           0
                        2           1           1
                        4           1.33        2.67
                        6           1.5         4.5
                        8           1.6         6.4
5       1       99
                        2           2           0   
                        4           2           2
                        6           2           4
                        8           2           6
5       2       96
                        4           4           0
                        6           3           3
                        8           2.67        5.33


Note that nested arrays have variable length.
"""

import tables as ts

tableDef =      {'DIEM': ts.Int32Col(pos=0),
                'TEMPUS': ts.Int32Col(pos=1), 
                'Temperature' : ts.Float32Col(pos=2),
                'Data': 
                    {'Category1': 
                        {
                        'x': ts.Float32Col(), 
                        'y': ts.Float32Col()
                        }, 
                    'Category2': 
                        {
                        'z': ts.Float32Col(), 
                        }
                    }
                }

# create output file
fpath = 'TestDb.h5'
fh = ts.openFile(fpath, 'w')
# define my table
tableName = 'MyData'
fh.createTable('/', tableName, tableDef)
tablePath = '/'+tableName
table = fh.getNode(tablePath)

# get row iterator
row = table.row
for i in xrange(3):
    print '\ni=', i
    # calc some fake data
    row['DIEM'] = 5
    row['TEMPUS'] = i
    row['Temperature'] = 100-i**2

    for j in xrange(5-i):
        # Note that nested array has variable number of rows
        print 'j=', j,
        # calc some fake nested data
        val1 = 2.0*(i+j)
        val2 = val1/(j+1.0)
        val3 = val1 - val2

        ''' Magic happens here...
        How do I write 'j' rows of data to the elements of 
        Category1 and/or Category2?

        In bastardized pseudo-code, I want to do:

        row['Data/Category1/x'][j] = val1
        row['Data/Category1/y'][j] = val2
        row['Data/Category2/z'][j] = val3
        '''

    row.append()
table.flush()

fh.close()

我在 PyTables 文档中没有发现任何迹象表明这种结构是不可能的......但如果这种结构实际上是不可能的,我有什么替代可变长度嵌套列的方法?

  • 阵列?VL阵列?如果是这样,如何将这些数据类型集成到上述结构中?
  • 其他想法?

非常感谢任何帮助!

带有附加信息的编辑:PyTables 专家似乎已经解决了“这样的结构是否可能”的问题:

PyTables 邮件论坛 - 分层数据集

那么有没有人想出一种方法来创建一个类似的 PyTable 数据结构?

再次感谢!

4

3 回答 3

9

我有一个类似的任务:用可变长度的数组转储固定大小的数据。

我首先尝试使用固定大小的 StringCol(64*1024) 字段来存储我的可变长度数据(它们总是 < 64K)。但是,尽管 blosc 压缩,它还是相当慢并且浪费了大量的磁盘空间。

经过几天的调查,我以以下解决方案结束:

(剧透:我们将数组字段存储在单独的 EArray 实例中,每个数组字段一个 EArray)

  1. 我将固定大小的数据存储在常规的 pytables 表中。
  2. 我在这些表中添加了 2 个附加字段:arrFieldName_OffsetarrFieldName_Length

    class Particle(IsDescription):
       idnumber  = Int64Col()
       ADCcount  = UInt16Col()
       TDCcount  = UInt8Col()
       grid_i    = Int32Col()
       grid_j    = Int32Col()
       pressure  = Float32Col()
       energy    = FloatCol()
       buffer_Offset = UInt32() # note this field!
       buffer_Length = UInt32() # and this one too!
    
  3. 我还为每个数组字段创建一个 EArray 实例:

    datatype = StringAtom(1)
    buffer = h5file.createEArray('/detector', 'arr', datatype, (0,), "")
    
  4. 然后我添加对应于固定大小数据的行:

    row['idnumber'] = ...
    ...
    row['energy'] = ...
    row['buffer_Offset'] = buffer.nrows
    # my_buf is a string (I get it from a stream)
    row['buffer_Length'] = len(my_buf)
    table.append(row)
    
  5. 达达!将缓冲区添加到数组中。

    buffer.append(np.ndarray((len(my_buf),), buffer=my_buf, dtype=datatype))
    
  6. 这就是诀窍。在我的实验中,这种方法比存储参差不齐的固定大小数组(如 StringAtom(HUGE_NUMBER))快 2-10 倍,并且生成的 DB 小几倍(2-5x)

  7. 获取缓冲区数据很容易。假设该是您从数据库中读取的单行:

    # Open array for reading
    buffer = h5file.createEArray('/detector', 'Particle.buffer', datatype, (0,), "")
    ...
    row = ...
    ...
    bufferDataYouNeed = buffer[ row['buffer_Offset'] : row['buffer_Offset'] + row['buffer_Length']]
    
于 2012-03-26T17:01:19.817 回答
4

这是开始使用 PyTables 的人们想要做的常见事情。当然,这是尝试做的第一件事。截至 2009 年,我认为不支持此功能。您可以在此处查找“我总是推荐”的一种解决方案:

http://www.mail-archive.com/pytables-users@lists.sourceforge.net/msg01207.html

简而言之,只需将每个 VLArray 放在单独的位置即可。如果你这样做,也许你最终不需要 VLArrays。如果您为每个试验(或其他)存储单独的 VLArray,您可以在这些 VLArray 上保留元数据(保证在重命名、移动等过程中与数组保持同步)或将其放在表中(更易于搜索)。

但是你也可以为你的列原子选择任何一个时间点,然后简单地为时间戳添加另一列。这将允许“参差不齐”的数组在内存中仍然具有规则的、重复的(表格)结构。例如:

Trial Data
1     0.4, 0.5, 0.45
2     0.3, 0.4, 0.45, 0.56

变成

Trial Timepoint Data
1     1         0.4
1     2         0.5
...
2     4         0.56

上面的数据是一个单一的数字,但也可以是一个 4x5x3 的原子。

如果 PyTables 现在支持嵌套的 VLArrays,我当然很想知道!

或者,我认为 h5py 确实支持完整的 HDF5 功能集,所以如果你真的致力于嵌套数据布局,那么你可能会有更多的运气。但是,您将失去许多不错的功能!根据我的经验,天真的神经科学家最终会表现得非常糟糕,因为他们没有 pytables 对数据布局、分块等进行智能选择。如果你走那条路,请报告!

于 2011-06-23T00:50:21.380 回答
0

我也遇到了这个问题,我最终使用了一个固定的数组大小。我试图存储的数组是可变 len 所以我从具有正确固定长度的

我做了一些类似的事情

def filled_list(src_list, targ_len):
    """takes a varible len() list and creates a new one with a fixed len()"""
    for i in range(targ_len):
        try:
            yield src_list[i]
        except IndexError:
            yield 0

src_list = [1,2,3,4,5,6,7,8,9,10,11]
new_list = [x for x in filled_list(src_list, 100)]

这对我有用。

于 2012-03-16T15:39:57.587 回答