Запись numpy.array () из списка именованных кортежей - PullRequest
0 голосов
/ 02 декабря 2018

У меня есть список именованных кортежей, которые я хотел бы записать в массив numpy.Кортежи имеют атрибуты 'colors', набор из двух цветов и 'number', целое число и имеют вид:

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]

дает мне массив кортежей, а не именованных, которые не имеют 'атрибутов' цветов ''
Хуже, если япопытаться преобразовать массив в 2x2. Я обнаружил, что каждый атрибут моих именованных кортежей был записан как отдельный объект в массиве.

numpy.reshape(Array,(2,2))
>>>...error...
>>>'ValueError: cannot reshape array of size 8 into shape (2,2)'

Я бы подумал, что указанный выше массив имеет размер 4?

Как я могу получить массив именованных кортежей без изменения именованных кортежей, чтобы я мог вызывать разные атрибуты для каждого элемента в массиве?

Причина, по которой я хотел бы использовать именованные кортежи в качестве моей структуры данных, заключается в том, чтопоэтому легко и читабельно вызывать атрибуты каждого объекта .color или .number.
Причина, по которой я хотел бы использовать пустой массив вместо стандартного вложенного списка, заключается в том, что этот массив будет динамическим объектом.Примерный проект, который будет часто просматриваться и изменяться, и я знаю, как стандартные списки плохого Python для этих вещей.
Для контекста, я в конечном счете пытаюсь создать программу, которая играет в карточную игру моего собственного изобретения.Именованные кортежи представляют карты с их цветами и номерами.Массив представляет собой карточную карту, которую игроки могут менять и перемещать.Эти именованные кортежи будут немного перемешаны, и я не хочу беспокоиться об изменении их структур данных.

1 Ответ

0 голосов
/ 02 декабря 2018

Becauuse 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 является наиболее удобным инструментом (иСамый быстрый) для доступа к элементам такого массива.

Наиболее эффективный способ установить атрибуты для объектов в массиве

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])

Инициализациямассив 1d и присвоение элементов работают:

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)
...