将2D numpy数组转换为结构化数组

2024-09-28 22:41:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试将二维数组转换为具有命名字段的结构化数组。我希望2D数组中的每一行都是结构化数组中的新记录。不幸的是,我所做的一切都没有达到我的预期。

我先说:

>>> myarray = numpy.array([("Hello",2.5,3),("World",3.6,2)])
>>> print myarray
[['Hello' '2.5' '3']
 ['World' '3.6' '2']]

我想转换成这样:

>>> newarray = numpy.array([("Hello",2.5,3),("World",3.6,2)], dtype=[("Col1","S8"),("Col2","f8"),("Col3","i8")])
>>> print newarray
[('Hello', 2.5, 3L) ('World', 3.6000000000000001, 2L)]

我试过的:

>>> newarray = myarray.astype([("Col1","S8"),("Col2","f8"),("Col3","i8")])
>>> print newarray
[[('Hello', 0.0, 0L) ('2.5', 0.0, 0L) ('3', 0.0, 0L)]
 [('World', 0.0, 0L) ('3.6', 0.0, 0L) ('2', 0.0, 0L)]]

>>> newarray = numpy.array(myarray, dtype=[("Col1","S8"),("Col2","f8"),("Col3","i8")])
>>> print newarray
[[('Hello', 0.0, 0L) ('2.5', 0.0, 0L) ('3', 0.0, 0L)]
 [('World', 0.0, 0L) ('3.6', 0.0, 0L) ('2', 0.0, 0L)]]

这两种方法都试图将myarray中的每个条目转换为具有给定数据类型的记录,因此会插入额外的零。我不知道如何使它把每一行转换成一个记录。

另一次尝试:

>>> newarray = myarray.copy()
>>> newarray.dtype = [("Col1","S8"),("Col2","f8"),("Col3","i8")]
>>> print newarray
[[('Hello', 1.7219343871178711e-317, 51L)]
 [('World', 1.7543139673493688e-317, 50L)]]

这次不执行实际转换。内存中现有的数据只是重新解释为新的数据类型。

我开始使用的数组是从文本文件读入的。数据类型不是提前知道的,所以我不能在创建时设置数据类型。我需要一个高性能和优雅的解决方案,这将很好地工作在一般情况下,因为我将做这种类型的转换很多,很多次为各种各样的应用程序。

谢谢!


Tags: numpyhelloworld记录数组col2col3col1
3条回答

您可以使用numpy.core.records.fromarrays从(平面)数组列表中“创建记录数组”,如下所示:

>>> import numpy as np
>>> myarray = np.array([("Hello",2.5,3),("World",3.6,2)])
>>> print myarray
[['Hello' '2.5' '3']
 ['World' '3.6' '2']]


>>> newrecarray = np.core.records.fromarrays(myarray.transpose(), 
                                             names='col1, col2, col3',
                                             formats = 'S8, f8, i8')

>>> print newrecarray
[('Hello', 2.5, 3) ('World', 3.5999999046325684, 2)]

我也在做类似的事情。我发现当numpy从现有的2D数组(使用np.core.records.fromarrays)创建结构化数组时,它将2D数组中的每一列(而不是每一行)视为一个记录。所以你必须转换它。努比的这种行为似乎不是很直观,但也许有一个很好的理由。

我想

new_array = np.core.records.fromrecords([("Hello",2.5,3),("World",3.6,2)],
                                        names='Col1,Col2,Col3',
                                        formats='S8,f8,i8')

是你想要的。

如果数据以元组列表的形式开始,则创建结构化数组是直接的:

In [228]: alist = [("Hello",2.5,3),("World",3.6,2)]
In [229]: dt = [("Col1","S8"),("Col2","f8"),("Col3","i8")]
In [230]: np.array(alist, dtype=dt)
Out[230]: 
array([(b'Hello',  2.5, 3), (b'World',  3.6, 2)], 
      dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')])

这里的复杂情况是,元组列表已转换为二维字符串数组:

In [231]: arr = np.array(alist)
In [232]: arr
Out[232]: 
array([['Hello', '2.5', '3'],
       ['World', '3.6', '2']], 
      dtype='<U5')

我们可以使用众所周知的zip*方法来“转置”这个数组-实际上我们需要一个双转置:

In [234]: list(zip(*arr.T))
Out[234]: [('Hello', '2.5', '3'), ('World', '3.6', '2')]

zip已经方便地给了我们一个元组列表。现在我们可以用所需的数据类型重新创建数组:

In [235]: np.array(_, dtype=dt)
Out[235]: 
array([(b'Hello',  2.5, 3), (b'World',  3.6, 2)], 
      dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')])

接受的答案使用fromarrays

In [236]: np.rec.fromarrays(arr.T, dtype=dt)
Out[236]: 
rec.array([(b'Hello',  2.5, 3), (b'World',  3.6, 2)], 
          dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')])

在内部,fromarrays采用一种常见的方法:创建目标数组,并按字段名复制值。有效地:

In [237]: newarr = np.empty(arr.shape[0], dtype=dt)
In [238]: for n, v in zip(newarr.dtype.names, arr.T):
     ...:     newarr[n] = v
     ...:     
In [239]: newarr
Out[239]: 
array([(b'Hello',  2.5, 3), (b'World',  3.6, 2)], 
      dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')])

相关问题 更多 >