我正在使用PyTables 2.2.1 w / Python 2.6,我想创建一个包含可变长度嵌套数组的表。
我搜索过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文档中发现任何迹象表明这样的结构是不可能的......但是如果这样的结构实际上是不可能的,那么我对可变长度嵌套列的替代方法是什么?
非常感谢任何帮助!
编辑附加信息: 似乎PyTables专家已经解决了“这样一个可能的结构”的问题:
PyTables Mail Forum - Hierachical Datasets
那么有没有人想出一种创建类似PyTable数据结构的方法?
再次感谢!
答案 0 :(得分:9)
我有类似的任务:使用可变长度的数组转储固定大小的数据。
我首先尝试使用固定大小的StringCol(64 * 1024)字段来存储我的可变长度数据(它们总是<64K)。但它很慢并且浪费了大量的磁盘空间,尽管有blosc压缩。
经过数天的调查后,我结束了以下解决方案:
(剧透:我们将数组字段存储在单独的EArray实例中,每个数组字段一个EArray)
我在这些表中添加了2个附加字段: arrFieldName_Offset 和 arrFieldName_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!
我还为每个数组字段创建一个EArray实例:
datatype = StringAtom(1)
buffer = h5file.createEArray('/detector', 'arr', datatype, (0,), "")
然后我添加对应于固定大小数据的行:
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)
钽DAH!将缓冲区添加到数组中。
buffer.append(np.ndarray((len(my_buf),), buffer=my_buf, dtype=datatype))
这就是诀窍。在我的实验中,这种方法比存储不规则的固定大小的数组(如StringAtom(HUGE_NUMBER))快2-10倍,并且得到的数据库小了几倍(2-5x)
获取缓冲区数据非常简单。假设 row 是您从数据库中读取的一行:
# Open array for reading
buffer = h5file.createEArray('/detector', 'Particle.buffer', datatype, (0,), "")
...
row = ...
...
bufferDataYouNeed = buffer[ row['buffer_Offset'] : row['buffer_Offset'] + row['buffer_Length']]
答案 1 :(得分:4)
这是人们开始使用PyTables时常见的事情。当然,这是 我 尝试做的第一件事。截至2009年,我认为此功能不受支持。你可以在这里寻找一个解决方案“我总是推荐”:
http://www.mail-archive.com/pytables-users@lists.sourceforge.net/msg01207.html
简而言之,只需将每个VLArray放在一个单独的位置即可。如果你这样做,也许你最终不需要VLArrays。如果为每个试验(或其他)存储单独的VLArray,则可以在这些VLArray上保留元数据(保证在重命名,移动等方面与数组保持同步)或将其放在表格中(更容易搜索)。 / p>
但是你也可以为你的列原子选择任何一个时间点,然后简单地为时间戳添加另一列。这将允许“ragged”数组在内存中仍然具有规则的,重复的(表格式)结构。例如:
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数据布局,分块等的明智选择。请报告你是否走这条路!
答案 2 :(得分: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)]
这对我有用。