2016-09-15 3 views
1

Насколько я понимаю, рекомендуемый способ преобразования массива NumPy в собственный список Python - использовать ndarray.tolist.Действительно рекурсивный `tolist()` для структурированных массивов NumPy

Увы, это не работает рекурсивно при использовании структурированных массивов. Действительно, некоторые ndarray объекты которые ссылаются в результирующий список, непрореагировавший:

>>> dtype = numpy.dtype([('position', numpy.int32, 3)]) 
>>> values = [([1, 2, 3],)] 
>>> a = numpy.array(values, dtype=dtype) 
>>> a.tolist() 
[(array([1, 2, 3], dtype=int32),)] 

я написал простую функцию, чтобы обойти эту проблему:

def array_to_list(array): 
    if isinstance(array, numpy.ndarray): 
     return array_to_list(array.tolist()) 
    elif isinstance(array, list): 
     return [array_to_list(item) for item in array] 
    elif isinstance(array, tuple): 
     return tuple(array_to_list(item) for item in array) 
    else: 
     return array 

Который, при использовании, обеспечивает ожидаемый результат:

>>> array_to_list(a) == values 
True 

проблема с этой функцией является то, что он дублирует работу ndarray.tolist воссоздавая каждый список/кортеж, который он выдает. Не оптимально.

Так вопросы:

  • является такое поведение ndarray.tolist следует ожидать?
  • есть ли лучший способ сделать это?
+0

Структурированный массив имеет больше смысла для меня как dict со значениями списка (или наоборот), чем список списков. – Evert

+0

Dict определенно имеет смысл, но также список списков, поскольку поля структурированного массива определены в dtype как упорядоченный список. Кроме того, NumPy понимает переменную 'values', которая используется для инициализации массива, даже если она определена в недискретном формате, поэтому список списков определенно является допустимой структурой. – ChristopherC

ответ

0

Просто обобщать это немного, я добавить еще одно поле для вашего DTYPE

In [234]: dt = numpy.dtype([('position', numpy.int32, 3),('id','U3')]) 

In [235]: a=np.ones((3,),dtype=dt) 

Дисплей repr делает списки использования и кортежи:

In [236]: a 
Out[236]: 
array([([1, 1, 1], '1'), ([1, 1, 1], '1'), ([1, 1, 1], '1')], 
    dtype=[('position', '<i4', (3,)), ('id', '<U3')]) 

, но, как вы заметили , tolist не расширяет элементы.

In [237]: a.tolist() 
Out[237]: [(array([1, 1, 1]), '1'), (array([1, 1, 1]), '1'), 
    (array([1, 1, 1]), '1')] 

Аналогично, такой массив может быть создан из полностью вложенных списков и кортежей.

In [238]: a=np.array([([1,2,3],'str')],dtype=dt) 
In [239]: a 
Out[239]: 
array([([1, 2, 3], 'str')], 
    dtype=[('position', '<i4', (3,)), ('id', '<U3')]) 
In [240]: a.tolist() 
Out[240]: [(array([1, 2, 3]), 'str')] 

Там нет никаких проблем воссоздавать массив из этого неполного рекурсии:

In [250]: np.array(a.tolist(),dtype=dt) 
Out[250]: 
array([([1, 2, 3], 'str')], 
     dtype=[('position', '<i4', (3,)), ('id', '<U3')]) 

Это первое, что я видел, чтобы кто использовать tolist со структурированным массивом, как это, но я тоже не удивлены. Я не знаю, будут ли разработчики считать эту ошибку или нет.

Зачем вам нужен чистый список/кортеж этого массива?

Интересно, есть ли функция в numpy/lib/recfunctions.py, которая обращается к этому.

+0

Я наткнулся на эту проблему при написании модульных тестов и хотел сравнить содержимое массива с соответствующим собственным списком Python, представляющим ожидаемые значения.Я знаю, что есть другие способы сделать это, но мне понравилась идея преобразования данных из NumPy в Python, чтобы я мог использовать тест 'assertIsEqual', с его реализацией, показывающей diff, если он не равен. В конце концов, 'ndarray.tolist', похоже, является действительным подходом к сериализации, поэтому я считаю удивительным, что здесь не работает. Возможно, я напишу о проблеме в репо, чтобы узнать, что они говорят об этом. – ChristopherC

+0

Для справки: https://github.com/numpy/numpy/issues/8052 – ChristopherC

Смежные вопросы