我有两个非结构化的NumPy数组a
和b
,分别具有形状(N,)
和(N, 256, 2)
和dtype np.float
。我希望将它们组合成具有形状(N,)
和dtype [('field1', np.float), ('field2', np.float, (256, 2))]
的单个结构化数组。
令人惊讶地缺少有关此问题的文档。我找到了np.lib.recfunctions.merge_arrays
之类的方法,但无法找到执行此操作所需的功能的精确组合。
为了避免使用the XY problem,我将陈述更广泛的目标。
我有一个布局为{"field1": tables.FloatCol(), "field2": tables.FloatCol(shape = (256, 2))}
的PyTables表。这两个NumPy数组表示要添加到这些字段中的每个字段的N个新行。 N很大,所以我希望通过一个有效的table.append(rows)
调用来完成此操作,而不是通过table.row['field'] = ...
循环的缓慢过程。
The table.append
documentation说
rows参数可以是任何可以转换为与表结构兼容的结构化数组的对象(否则会引发ValueError)。这包括NumPy结构化的数组,元组或数组记录的列表以及字符串或Python缓冲区。
将数组转换为适当的结构化数组似乎是我在这里应该做的。我正在寻找速度,并且我预计其他选择会更慢。
答案 0 :(得分:1)
定义dtype,并创建一个空/零数组:
In [163]: dt = np.dtype([('field1', np.float), ('field2', np.float, (4, 2))])
In [164]: arr = np.zeros(3, dt) # float display is prettier
In [165]: arr
Out[165]:
array([(0., [[0., 0.], [0., 0.], [0., 0.], [0., 0.]]),
(0., [[0., 0.], [0., 0.], [0., 0.], [0., 0.]]),
(0., [[0., 0.], [0., 0.], [0., 0.], [0., 0.]])],
dtype=[('field1', '<f8'), ('field2', '<f8', (4, 2))])
逐字段分配值:
In [166]: arr['field1'] = np.arange(3)
In [167]: arr['field2'].shape
Out[167]: (3, 4, 2)
In [168]: arr['field2'] = np.arange(24).reshape(3,4,2)
In [169]: arr
Out[169]:
array([(0., [[ 0., 1.], [ 2., 3.], [ 4., 5.], [ 6., 7.]]),
(1., [[ 8., 9.], [10., 11.], [12., 13.], [14., 15.]]),
(2., [[16., 17.], [18., 19.], [20., 21.], [22., 23.]])],
dtype=[('field1', '<f8'), ('field2', '<f8', (4, 2))])
np.rec
确实具有类似的功能:
In [174]: np.rec.fromarrays([np.arange(3.), np.arange(24).reshape(3,4,2)], dtype=dt)
Out[174]:
rec.array([(0., [[ 0., 1.], [ 2., 3.], [ 4., 5.], [ 6., 7.]]),
(1., [[ 8., 9.], [10., 11.], [12., 13.], [14., 15.]]),
(2., [[16., 17.], [18., 19.], [20., 21.], [22., 23.]])],
dtype=[('field1', '<f8'), ('field2', '<f8', (4, 2))])
相同,除了字段也可以作为属性访问。在幕后,它执行相同的按领域分配。
numpy.lib.recfunctions
是结构化数组函数的另一个集合。这些大多都遵循按字段分配方法。
答案 1 :(得分:0)
为了获得合适尺寸的测试打印输出,我的解决方案假定:
要生成结果,请按照下列步骤操作:
从import numpy.lib.recfunctions as rfn
开始(很快将需要)。
创建源数组:
a = np.array([10, 20, 30, 40, 50])
b = np.arange(1, 41).reshape(5, 4, 2)
创建结果:
result = rfn.unstructured_to_structured(
np.hstack((a[:,np.newaxis], b.reshape(-1,8))),
np.dtype([('field1', 'f4'), ('field2', 'f4', (4,2))]))
生成的数组包含:
array([(10., [[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.]]),
(20., [[ 9., 10.], [11., 12.], [13., 14.], [15., 16.]]),
(30., [[17., 18.], [19., 20.], [21., 22.], [23., 24.]]),
(40., [[25., 26.], [27., 28.], [29., 30.], [31., 32.]]),
(50., [[33., 34.], [35., 36.], [37., 38.], [39., 40.]])],
dtype=[('field1', '<f4'), ('field2', '<f4', (4, 2))])
请注意,创建了 unstructured_to_structured 的源数组 通过以下方式:
在上述实验中,我假设 f4 的类型,也许您应该更改 到 f8 (您的决定)。
在代码的目标版本中:
答案 2 :(得分:0)
此答案以@hpualj的答案为基础。他的第一个方法将obj
参数创建为结构化数组,第二个方法创建一个记录数组。 (追加时,该数组将是rows
参数。)当我已经将数据存储在结构化(或记录)数组中时,我喜欢这两种方法来创建或追加到表。但是,如果数据位于单独的数组中,则不必执行此操作(如“ 避免XY问题'中所述”)。如table.append()
的PyTables文档中所述:< / p>
rows参数可以是任何可以转换为a的对象 与表结构兼容的结构化数组。...包括 NumPy结构化数组, 元组列表或数组记录...
换句话说,您可以在列表中追加引用数组的列表,只要它们与示例中用description=dt
创建的表结构匹配即可。 (我认为您在创建时仅限于结构化数组。)这可能会简化您的代码。
我写了一个基于@hpaulj代码的示例。它使用不同的方法创建2个相同的HDF5文件。
_1.h5
),我使用结构化数组方法创建表。然后,我使用table.append([list of arrays])
_2.h5
),我创建了引用
使用description=dt
的结构化数组dtype,但不要使用obj=arr
添加数据。然后,我使用table.append([list of arrays])
将数据的前3行添加到表中,并重复添加另外3行。以下示例:
import numpy as np
import tables as tb
dt = np.dtype([('field1', np.float), ('field2', np.float, (4, 2))])
arr = np.zeros(3, dt) # float display is prettier
arr['field1'] = np.arange(3)
arr['field2'] = np.arange(24).reshape(3,4,2)
with tb.File('SO_62104084_1.h5','w') as h5f1:
test_tb = h5f1.create_table('/','test',obj=arr)
arr1 = np.arange(13.,16.,1.)
arr2 = np.arange(124.,148.,1.).reshape(3,4,2)
# add rows of data referencing list of arrays:
test_tb.append([arr1,arr2])
with tb.File('SO_62104084_2.h5','w') as h5f2:
test_tb=h5f2.create_table('/','test', description=dt)
# add data rows 0-2:
arr1 = np.arange(3)
arr2 = np.arange(24).reshape(3,4,2)
test_tb.append([arr1,arr2])
# add data rows 3-5:
arr1 = np.arange(13.,16.,1.)
arr2 = np.arange(124.,148.,1.).reshape(3,4,2)
test_tb.append([arr1,arr2])