将numpy数组转换为numpy记录数组。

3

我尝试将一个10x2的数组转换为记录,通过给每列命名。

我是这样尝试的:

t = arange (10)
>>> n = dstack([t,
                roll (t, 1),
                roll (t, -1)])[0]
... ... >>> 
>>> n = n[:,1:3]
>>> n
array([[9, 1],
       [0, 2],
       [1, 3],
       [2, 4],
       [3, 5],
       [4, 6],
       [5, 7],
       [6, 8],
       [7, 9],
       [8, 0]])
>>> nt = [('left', int), ('right', int)]
>>> array (n, nt)
array([[(9, 9), (1, 1)],
       [(0, 0), (2, 2)],
       [(1, 1), (3, 3)],
       [(2, 2), (4, 4)],
       [(3, 3), (5, 5)],
       [(4, 4), (6, 6)],
       [(5, 5), (7, 7)],
       [(6, 6), (8, 8)],
       [(7, 7), (9, 9)],
       [(8, 8), (0, 0)]], 
      dtype=[('left', '<i8'), ('right', '<i8')])
>>> 

令我惊讶的是,每行的元素都是元组而不是int类型的数字。

我该如何纠正这个问题,并使n的每一行看起来像[9,1]而不是[(9, 9), (1, 1)]?


我阅读了这篇文章,尽管我努力理解并按照自己的意愿进行转换,但我在那里找不到答案。另一方面,迄今为止在这里收到的答案是有效的。 - alinsoar
是的,从现有数组构建recarrays有点奇怪,因为您正在将曾经分开的元素变成一个元组。 - askewchan
3个回答

3

您可以使用新的数据类型创建视图,它会显示相同的数据:

In [150]: nt = [('left',np.int),('right',np.int)]

In [151]: n
Out[151]: 
array([[9, 1],
       [0, 2],
       [1, 3],
       [2, 4],
       [3, 5],
       [4, 6],
       [5, 7],
       [6, 8],
       [7, 9],
       [8, 0]])

In [152]: n.view(nt)
Out[152]: 
array([[(9, 1)],
       [(0, 2)],
       [(1, 3)],
       [(2, 4)],
       [(3, 5)],
       [(4, 6)],
       [(5, 7)],
       [(6, 8)],
       [(7, 9)],
       [(8, 0)]], 
      dtype=[('left', '<i8'), ('right', '<i8')])

这会保持2D形状,但:
In [160]: n_struct = n.view(nt)

In [161]: n_struct.shape
Out[161]: (10, 1)

In [162]: n_struct = n.view(nt).reshape(n.shape[0])

In [163]: n_struct
Out[163]: 
array([(9, 1), (0, 2), (1, 3), (2, 4), (3, 5), (4, 6), (5, 7), (6, 8),
       (7, 9), (8, 0)], 
      dtype=[('left', '<i8'), ('right', '<i8')])

如您所请求的,访问方式如下:

In [170]: n_struct['left']
Out[170]: array([9, 0, 1, 2, 3, 4, 5, 6, 7, 8])

In [171]: n_struct['right']
Out[171]: array([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])

@Ophion提醒,此方法仅在数据类型兼容时才有效,因为ndarray.view(dtype)将原始数据解释为给定的dtype,而不是将数据转换为新的dtype。 换句话说,(根据文档),a.view(some_dtype)构造一个具有不同数据类型的数组内存视图。这可能会导致内存字节的重新解释。

听起来很有趣,但现在数组是元组的。我需要经常执行此操作,并且需要非常快的速度。另一方面,“left”如何从元组数组中提取第一个元素? - alinsoar
1
这就是record数组的含义:一个元组数组(因为你的dtype是由两个整数组成的元组)。 - askewchan
我正在使用Python 2.7。但对我来说它不起作用。n.view(nt) => ValueError: 新类型与数组不兼容。 - alinsoar
这是一种非常好的方法,我想提醒大家要非常小心 dtype。如果 dtypes 不匹配,就会出现错误或者奇怪的结果,因为没有检查。@alinsoar 我建议你检查一下数组的 dtype,很可能是问题所在。 - Daniel
我进行了一项优化,并为清理代码而命名列,以便在具有多个节点的动态循环缓冲区中区分它们的含义。我没有直接采用这两个答案中的任何一个,但我从中汲取了灵感。 - alinsoar
显示剩余3条评论

2

希望有更好的方式在纯numpy中实现,但以下代码可以帮助您入门:

>>> nt = [('left', int), ('right', int)]
>>> n
array([[9, 1],
       [0, 2],
       [1, 3],
       [2, 4],
       [3, 5],
       [4, 6],
       [5, 7],
       [6, 8],
       [7, 9],
       [8, 0]])

>>> out = np.array(np.zeros(n.shape[0]),nt)
>>> out
array([(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0),
       (0, 0), (0, 0)],
      dtype=[('left', '<i8'), ('right', '<i8')])

>>> out['left']=n[:,0]
>>> out['right']=n[:,1]

>>> out
array([(9, 1), (0, 2), (1, 3), (2, 4), (3, 5), (4, 6), (5, 7), (6, 8),
       (7, 9), (8, 0)],
      dtype=[('left', '<i8'), ('right', '<i8')])

>>> out['left']
array([9, 0, 1, 2, 3, 4, 5, 6, 7, 8])

当然,有pandas的解决方案:
>>> import pandas as pd
>>> df = pd.DataFrame(n,columns=['left','right'])
>>> df
   left  right
0     9      1
1     0      2
2     1      3
3     2      4
4     3      5
5     4      6
6     5      7
7     6      8
8     7      9
9     8      0

关于pandas数据框的一些有趣之处:

>>> df.values
array([[9, 1],
       [0, 2],
       [1, 3],
       [2, 4],
       [3, 5],
       [4, 6],
       [5, 7],
       [6, 8],
       [7, 9],
       [8, 0]])

1
如果底层数据类型不兼容,则“view”方法无法使用。备选方案是使用元组列表填充记录数组:
In [128]: x=np.arange(12).reshape(4,3)

In [129]: y=np.zeros((4,),dtype=[('x','f'),('y','f'),('z','f')])

In [130]: y
Out[130]: 
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)], 
      dtype=[('x', '<f4'), ('y', '<f4'), ('z', '<f4')])

In [131]: y[:]=[tuple(row) for row in x]

In [132]: y
Out[132]: 
array([(0.0, 1.0, 2.0), (3.0, 4.0, 5.0), (6.0, 7.0, 8.0), (9.0, 10.0, 11.0)], 
      dtype=[('x', '<f4'), ('y', '<f4'), ('z', '<f4')])

这个元组列表可以用于初始构建:
In [135]: np.array([tuple(row) for row in x],y.dtype)
Out[135]: 
array([(0.0, 1.0, 2.0), (3.0, 4.0, 5.0), (6.0, 7.0, 8.0), (9.0, 10.0, 11.0)], 
      dtype=[('x', '<f4'), ('y', '<f4'), ('z', '<f4')])

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