将一个2维数组(field)添加到一个numpy recarray中。

4

我想使用 numpy.lib.recfunctions.append_fields 将一个2D字段添加到现有的记录数组中。 假设我已经创建了一个记录数组。

> arr = np.recarray(10, [("afield", "<f8"), ('pos', '<f8', (3,))])
> arr.dtype
dtype((numpy.record, [('afield', '<f8'), ('pos', '<f8', (3,))]))

我希望添加一个字段,使得arr看起来像这样:

> arr.dtype
dtype((numpy.record, [('afield', '<f8'), ('pos', '<f8', (3,)), ('vel', '<f8', (3,))]))

我不确定应该传递什么给dtypes=参数。 我尝试使用dtypes =np.dtype("f8",(3,)),但没有成功。

> from numpy.lib.recfunctions import append_fields
> data = arr["pos"][:]
> new_arr = append_fields(arr, 'vel', data, dtypes =np.dtype("f8",(3,)),usemask=False)
ValueError: could not broadcast input array from shape (10,3) into shape (10)

如果我传递一个只有一个元素的列表,那么会得到另一种错误。

> new_arr = append_fields(arr, 'vel', data, dtypes =[("f8",(3,))],usemask=False)
ValueError: could not broadcast input array from shape (10,3) into shape (10,3,3)

我希望得到一个形状为(10,3)的数组,但我只能获得(10,)(10,3,3)的数组。

你可能走错了方向,append_fields 不适合这个目的。可能需要对 numpy 进行补丁。 - Eric
感谢 @Eric 指出这一点。希望更多的功能能够很快实现。在那之前,也许我会想出自己的方法来解决它。 - Hoseung Choi
2个回答

2
append_fields 函数以及其他大多数 recarray 函数会创建一个新的 dtype 和一个 empty 数组,并通过字段名称从原始数组复制字段到结果数组中。
下面将使用一个结构化数组进行说明:
原始的 dtype 和数组如下:
In [102]: dt=np.dtype([('afield','f'),('pos','f',(3,))])
In [103]: dt
Out[103]: dtype([('afield', '<f4'), ('pos', '<f4', (3,))])
In [104]: arr = np.ones((3,),dtype=dt)
In [105]: arr
Out[105]: 
array([(1.0, [1.0, 1.0, 1.0]), (1.0, [1.0, 1.0, 1.0]),
       (1.0, [1.0, 1.0, 1.0])], 
      dtype=[('afield', '<f4'), ('pos', '<f4', (3,))])

修改数据类型:

In [106]: dt1=np.dtype([('afield','f'),('pos','f',(3,)),('vel','f',(2,))])
In [107]: arr1 = np.empty((3,),dtype=dt1)
In [108]: arr1
Out[108]: 
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.0, 0.0, 0.0], [0.0, 0.0])], 
      dtype=[('afield', '<f4'), ('pos', '<f4', (3,)), ('vel', '<f4', (2,))])
In [109]: for name in dt.names:
   .....:     arr1[name] = arr[name]

In [110]: arr1
Out[110]: 
array([(1.0, [1.0, 1.0, 1.0], [0.0, 0.0]),
       (1.0, [1.0, 1.0, 1.0], [0.0, 0.0]),
       (1.0, [1.0, 1.0, 1.0], [0.0, 0.0])], 
      dtype=[('afield', '<f4'), ('pos', '<f4', (3,)), ('vel', '<f4', (2,))])

recarray 是同样的东西,但有能力将字段作为属性进行访问(arr.pos)。

添加一个简单的整数字段:

In [118]: rf.append_fields(arr, 'vel', np.arange(3),usemask=False)
Out[118]: 
array([(1.0, [1.0, 1.0, 1.0], 0), (1.0, [1.0, 1.0, 1.0], 1),
       (1.0, [1.0, 1.0, 1.0], 2)], 
      dtype=[('afield', '<f4'), ('pos', '<f4', (3,)), ('vel', '<i4')])

当我使用(2,)字段时,在recursive_fill步骤中会出现错误。有了正确的输入,我可以使用它来填充我的dt1数组:

In [206]: arr = np.ones((3,),dtype=dt)
In [207]: arr1 = np.zeros((3,),dtype=dt1)
In [208]: rf.recursive_fill_fields(arr,arr1)
Out[208]: 
array([(1.0, [1.0, 1.0, 1.0], [0.0, 0.0]),
       (1.0, [1.0, 1.0, 1.0], [0.0, 0.0]),
       (1.0, [1.0, 1.0, 1.0], [0.0, 0.0])], 
      dtype=[('afield', '<f4'), ('pos', '<f4', (3,)), ('vel', '<f4', (2,))])

In [210]: x = np.ones((3,),dtype=[('vel','f',(2,))])
In [211]: x['vel'] *= 2
In [212]: rf.recursive_fill_fields(x,arr1)
Out[212]: 
array([(1.0, [1.0, 1.0, 1.0], [2.0, 2.0]),
       (1.0, [1.0, 1.0, 1.0], [2.0, 2.0]),
       (1.0, [1.0, 1.0, 1.0], [2.0, 2.0])], 
      dtype=[('afield', '<f4'), ('pos', '<f4', (3,)), ('vel', '<f4', (2,))])

现在尝试在`append_fields`中使用`x`:
In [213]: rf.append_fields(arr, 'vel', x, usemask=False)
Out[213]: 
array([(1.0, [1.0, 1.0, 1.0], ([2.0, 2.0],)),
       (1.0, [1.0, 1.0, 1.0], ([2.0, 2.0],)),
       (1.0, [1.0, 1.0, 1.0], ([2.0, 2.0],))], 
      dtype=[('afield', '<f4'), ('pos', '<f4', (3,)), ('vel', [('vel', '<f4', (2,))])])

糟糕 - 我得到了一个嵌套字段。回到我的原始示例 - 通过名称创建目标并填充它。

merge_arrays 更好 - 使用 flatten 功能。

In [247]: rf.merge_arrays((arr,x),flatten=True)
Out[247]: 
array([(1.0, [1.0, 1.0, 1.0], [2.0, 2.0]),
       (1.0, [1.0, 1.0, 1.0], [2.0, 2.0]),
       (1.0, [1.0, 1.0, 1.0], [2.0, 2.0])], 
      dtype=[('afield', '<f4'), ('pos', '<f4', (3,)), ('vel', '<f4', (2,))])

为新字段创建一个合适的数组的另一种方法

In [248]: dx = [('f0','f',(2,))]
In [250]: y=np.zeros((3,), dtype=dx)
In [251]: y['f0'] = np.arange(6.).reshape(3,2)

创建并填充常常是制作这些复杂结构数组的最佳方式。

0

这是朝着正确方向迈出的一步:

data = arr['pos']
data = np.ascontiguousarray(data)  # next line fails otherwise - bug?
data = data.view([('vel', (np.float, 3))])
data = data.reshape(data.shape[:-1])  # view doesn't ever remove a dimension
assert data.shape == (10,)

不幸的是,当你现在执行以下操作时:

new_arr = append_fields(arr, 'vel', data,usemask=False)

你最终得到的是 new_arr['vel']['vel']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接