将两个 NumPy 数组组合成一个结构化数组以附加到 PyTables table
Combine two NumPy arrays into one structured array for appending to a PyTables table
我有两个非结构化 NumPy 数组 a
和 b
,形状分别为 (N,)
和 (N, 256, 2)
,数据类型为 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 table。两个 NumPy 数组表示要附加到每个字段的 N 个新行。 N 很大,所以我希望通过一次高效的 table.append(rows)
调用来完成此操作,而不是通过 table.row['field'] = ...
.
的缓慢循环过程
The table.append
documentation 说
The rows argument may be any object which can be converted to a structured array compliant with the table structure (otherwise, a ValueError is raised). This includes NumPy structured arrays, lists of tuples or array records, and a string or Python buffer.
将我的数组转换为适当的结构化数组似乎是我应该在这里做的事情。我正在寻找速度,我预计其他选项会更慢。
定义数据类型,并创建一个empty/zeros数组:
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
是结构化数组函数的另一个集合。这些也大多遵循按字段分配方法。
为了获得大小合适的测试打印输出,我的解决方案假定:
- N = 5,
- 第二维度 - 只有 4(而不是你的 256)。
要生成结果,请执行以下操作:
从 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的源数组被创建
以下方式:
- 列 0 - 来自 a(转换为列),
- 剩余的列 - 来自 b 的重塑方式使得所有元素
各自的 4 * 2 切片被转换为单行。数据
从每一行(从这些列)转换回“4 * 2”
通过这个函数塑造。
- 以上两个组件都是用hstack组装的。
在上面的实验中,我假定类型为 f4,也许你应该更改
f8(您的决定)。
在代码的目标版本中:
- 将field2第一维的4改为256,
- 将b.reshape中的8改为512(=2*256 ).
这个答案建立在@hpualj 的答案之上。他的第一个方法将 obj
参数创建为结构化数组,第二个方法创建一个记录数组。 (当您追加时,该数组将是 rows
参数。)当我的数据已经在结构化(或记录)数组中时,我喜欢这两种方法来创建或追加到 tables。但是,如果您的数据位于单独的数组中(如“避免 X-Y 问题”中所述),则不必执行此操作。如 PyTables 文档中所述 table.append()
:
The rows argument may be any object which can be converted to a
structured array compliant with the table structure.... This includes
NumPy structured arrays, lists of tuples or array records...
换句话说,您可以附加引用数组的列表,只要它们与示例中使用 description=dt
创建的 table 结构相匹配即可。 (我认为您在创建时仅限于结构化数组。)这可能会简化您的代码。
我写了一个基于@hpaulj 代码的示例。它使用不同的方法创建 2 个相同的 HDF5 文件。
- 对于第一个文件 (
_1.h5
),我使用结构化数组方法创建 table。然后我使用 table.append([list of arrays])
将 3 行数据添加到 table
- 对于第二个文件 (
_2.h5
),我创建 table 引用
使用 description=dt
的结构化数组 dtype,但不要使用 obj=arr
添加数据。然后我使用 table.append([list of arrays])
将前 3 行数据添加到 table 并重复添加 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])
我有两个非结构化 NumPy 数组 a
和 b
,形状分别为 (N,)
和 (N, 256, 2)
,数据类型为 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 table。两个 NumPy 数组表示要附加到每个字段的 N 个新行。 N 很大,所以我希望通过一次高效的 table.append(rows)
调用来完成此操作,而不是通过 table.row['field'] = ...
.
The table.append
documentation 说
The rows argument may be any object which can be converted to a structured array compliant with the table structure (otherwise, a ValueError is raised). This includes NumPy structured arrays, lists of tuples or array records, and a string or Python buffer.
将我的数组转换为适当的结构化数组似乎是我应该在这里做的事情。我正在寻找速度,我预计其他选项会更慢。
定义数据类型,并创建一个empty/zeros数组:
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
是结构化数组函数的另一个集合。这些也大多遵循按字段分配方法。
为了获得大小合适的测试打印输出,我的解决方案假定:
- N = 5,
- 第二维度 - 只有 4(而不是你的 256)。
要生成结果,请执行以下操作:
从
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的源数组被创建 以下方式:
- 列 0 - 来自 a(转换为列),
- 剩余的列 - 来自 b 的重塑方式使得所有元素 各自的 4 * 2 切片被转换为单行。数据 从每一行(从这些列)转换回“4 * 2” 通过这个函数塑造。
- 以上两个组件都是用hstack组装的。
在上面的实验中,我假定类型为 f4,也许你应该更改 f8(您的决定)。
在代码的目标版本中:
- 将field2第一维的4改为256,
- 将b.reshape中的8改为512(=2*256 ).
这个答案建立在@hpualj 的答案之上。他的第一个方法将 obj
参数创建为结构化数组,第二个方法创建一个记录数组。 (当您追加时,该数组将是 rows
参数。)当我的数据已经在结构化(或记录)数组中时,我喜欢这两种方法来创建或追加到 tables。但是,如果您的数据位于单独的数组中(如“避免 X-Y 问题”中所述),则不必执行此操作。如 PyTables 文档中所述 table.append()
:
The rows argument may be any object which can be converted to a structured array compliant with the table structure.... This includes NumPy structured arrays, lists of tuples or array records...
换句话说,您可以附加引用数组的列表,只要它们与示例中使用 description=dt
创建的 table 结构相匹配即可。 (我认为您在创建时仅限于结构化数组。)这可能会简化您的代码。
我写了一个基于@hpaulj 代码的示例。它使用不同的方法创建 2 个相同的 HDF5 文件。
- 对于第一个文件 (
_1.h5
),我使用结构化数组方法创建 table。然后我使用table.append([list of arrays])
将 3 行数据添加到 table
- 对于第二个文件 (
_2.h5
),我创建 table 引用 使用description=dt
的结构化数组 dtype,但不要使用obj=arr
添加数据。然后我使用table.append([list of arrays])
将前 3 行数据添加到 table 并重复添加 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])