2011-03-20 90 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']]