2011-03-20 191 views
11

我使用PyTables 2.2.1 w/Python 2.6,我想创建一个包含可变长度嵌套数组的表。在PyTables中,如何创建可变长度的嵌套数组?

我已经搜索了PyTables文档,教程示例(PyTables Tutorial 3.8)显示了如何创建一个长度= 1的嵌套数组。但是对于这个示例,我将如何向数据'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文档,这样的结构是不可能的任何迹象...但在这种情况下,一个结构实际上是不可能的,我可以选择变长嵌套列吗?

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

任何援助非常感谢!

编辑瓦特/附加信息: 看来,PyTables大师们已经解决了“是这样的结构可能”的问题:

PyTables Mail Forum - Hierachical Datasets

所以有没有人想出一个办法来创建一个类似的PyTable数据结构?

再次感谢!

回答

4

这是一个普遍的事情,人们开始与PyTables想做的事情。当然,这是第一件事试图做。截至2009年,我不认为这个功能被支持。你可以看看这里的一个解决方案“我总是建议”:

http://www.mail-archive.com/[email protected]/msg01207.html

总之,只要把每个VLArray在一个单独的地方。如果你这样做,也许你最终不需要VLArrays。如果您为每个试验(或其他)存储单独的VLArrays,您可以保留这些VLArrays上的元数据(保证与阵列在重命名,移动等方面保持同步)或将其放在表格中(更易于搜索)。

但是,您也可以很好地选择您的列原子的任何一个时间点,然后为时间戳添加另一列。这将允许在存储器中仍然具有规则的,重复的(表格式)结构的“衣衫褴褛”数组。例如:

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数据布局,组块等智能选择。请报告回去,如果你走这条路线!

+0

感谢您的建议!此外,邮件列表链接还有来自Francesc的其他一些有趣的'掘金'智慧。最后,因为我关心速度和维护简单性,所以我选择了具有填充额外空间的固定数组大小。 – plmcw 2011-07-05 16:35:31

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)] 

行这奏效了,我的东西。

9

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

我第一次尝试使用固定大小的StringCol(64 * 1024)字段来存储我的可变长度数据(它们始终是< 64K)。但是这个过程非常缓慢,并且浪费了很多磁盘空间,尽管遭受了压缩。

经过调查我用以下溶液结束的天数:

(扰流:我们存储在单独的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. Ta-dah!将缓冲区添加到数组中。

    buffer.append(np.ndarray((len(my_buf),), buffer=my_buf, dtype=datatype)) 
    
  6. 这就是诀窍。在我的实验中,这种方法比存储参差不齐的固定大小的阵列(如StringAtom(HUGE_NUMBER))快2-10倍,并且生成的数据块几倍小(2-5x)。获取缓冲区数据非常简单。假设是您从您的数据库读取单个行:

    # Open array for reading 
    buffer = h5file.createEArray('/detector', 'Particle.buffer', datatype, (0,), "") 
    ... 
    row = ... 
    ... 
    bufferDataYouNeed = buffer[ row['buffer_Offset'] : row['buffer_Offset'] + row['buffer_Length']]