我有一个namedtuple列表,我想将其写入numpy数组。 元组具有属性“颜色”(一组两种颜色)和“数字”(整数),格式为:
from collections import namedtuple
import numpy as np
NamedTuple = namedtuple('tuple',['colors','number'])
L = [NamedTuple({'violet', 'blue'}, 4),
NamedTuple({'orange', 'blue'}, 1),
NamedTuple({'green', 'blue'}, 3),
NamedTuple({'orange', 'red'}, 2)]
L
>>>[tuple(colors={'blue', 'violet'}, number=4)...]
L[3].colors
>>>{'orange', 'red'}
我想从L中编写一个2x2数组,例如:
Array[1][1].colors
>>>{'orange', 'red'}
做
Array = numpy.array(L)
>>>[[{'blue', 'violet'} 4]
[{'blue', 'orange'} 1]
[{'blue', 'green'} 3]
[{'red', 'orange'} 2]
给我一个元组数组,而不是namedtuple,它们具有'no attribute'colors'
更糟糕的是,如果我尝试将Array整形为2x2,我发现我的namedtuple的每个属性都被写为数组中的不同对象。
numpy.reshape(Array,(2,2))
>>>...error...
>>>'ValueError: cannot reshape array of size 8 into shape (2,2)'
我会以为上面的数组是4号?
如何在不更改namedtuple的情况下获取namedtuple数组,以便可以从数组的每个元素中调用不同的属性?
我想使用namedtuples作为数据结构的原因是,这样可以轻松且易读地调用每个对象的.color或.number属性。
我之所以要使用numpy数组而不是标准的嵌套列表,是因为此数组将成为整个项目中的动态对象,并且经常会对其进行搜索和更改,而且我知道python的标准列表对于这些对象的可怜性东西。
就上下文而言,我最终试图构建一个程序来玩我自己发明的纸牌游戏。 namedtuple用颜色和数字表示卡。数组代表牌桌,玩家可以随意更改和移动。这些命名元组将被大量改组,我不想担心它们的数据结构被更改。
答案 0 :(得分:1)
因为NamedTuple
是tuple
的子类,所以根据L
构造对象数组会导致(n,2)数组,就像我们将其作为元组列表或列表清单:
In [4]: np.array(L, object)
Out[4]:
array([[{'violet', 'blue'}, 4],
[{'blue', 'orange'}, 1],
[{'blue', 'green'}, 3],
[{'red', 'orange'}, 2]], dtype=object)
In [5]: _.shape
Out[5]: (4, 2)
这是一个窍门-首先向列表中添加一个None
对象:
In [13]: arr = np.array(L+[None], object)[:-1]
In [14]: arr
Out[14]:
array([tuple(colors={'violet', 'blue'}, number=4),
tuple(colors={'blue', 'orange'}, number=1),
tuple(colors={'blue', 'green'}, number=3),
tuple(colors={'red', 'orange'}, number=2)], dtype=object)
In [15]: arr.shape
Out[15]: (4,)
In [16]: arr = np.reshape(arr,(2,2))
In [17]: arr
Out[17]:
array([[tuple(colors={'violet', 'blue'}, number=4),
tuple(colors={'blue', 'orange'}, number=1)],
[tuple(colors={'blue', 'green'}, number=3),
tuple(colors={'red', 'orange'}, number=2)]], dtype=object)
在先前的问题中,我发现frompyfunc
是访问此类数组元素的最便捷工具(也是最快的工具)。
Most efficient way to set attributes on objects in array
In [18]: np.frompyfunc(lambda x: x.colors, 1,1)(arr)
Out[18]:
array([[{'violet', 'blue'}, {'blue', 'orange'}],
[{'blue', 'green'}, {'red', 'orange'}]], dtype=object)
要构建结构化数组,我们可以这样做:
In [19]: arr1 = np.array(L, dtype=[('colors', object), ('number', int)])
In [20]: arr1
Out[20]:
array([({'violet', 'blue'}, 4), ({'blue', 'orange'}, 1),
({'blue', 'green'}, 3), ({'red', 'orange'}, 2)],
dtype=[('colors', 'O'), ('number', '<i8')])
NamedTuple
是tuple
的子类,因此它可用作数据输入(例如元组列表)。
In [22]: arr1['colors']
Out[22]:
array([{'violet', 'blue'}, {'blue', 'orange'}, {'blue', 'green'},
{'red', 'orange'}], dtype=object)
In [23]: arr1['number']
Out[23]: array([4, 1, 3, 2])
初始化一维数组并分配元素的工作原理是
In [30]: arr2 = np.empty(4, object)
In [31]: arr2[:] = L
In [32]: arr2
Out[32]:
array([tuple(colors={'violet', 'blue'}, number=4),
tuple(colors={'blue', 'orange'}, number=1),
tuple(colors={'blue', 'green'}, number=3),
tuple(colors={'red', 'orange'}, number=2)], dtype=object)
填写np.empty((2,2), object)
会比较棘手。
我可以使用以下方法从结构化数组的字段(或任何其他输入对列表)构造对象数组:
In [44]: np.frompyfunc(NamedTuple, 2,1)(arr1['colors'], arr1['number'])
Out[44]:
array([tuple(colors={'violet', 'blue'}, number=4),
tuple(colors={'blue', 'orange'}, number=1),
tuple(colors={'blue', 'green'}, number=3),
tuple(colors={'red', 'orange'}, number=2)], dtype=object)