2013-09-02 2 views
8

Рассмотрим следующий простой пример:питон: NumPy: конкатенация поименованных массивов

x = numpy.array([(1,2),(3,4)],dtype=[('a','<f4'),('b','<f4')]) 
y = numpy.array([(1,2),(3,4)],dtype=[('c','<f4'),('d','<f4')]) 
numpy.hstack((x,y)) 

One получит следующее сообщение об ошибке:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "C:\Python33\lib\site-packages\numpy\core\shape_base.py", line 226, in vstack 
    return _nx.concatenate(list(map(atleast_2d,tup)),0) 
TypeError: invalid type promotion 

Если массив не имел названия он работает

x = numpy.array([(1,2),(3,4)],dtype='<f4') 
y = numpy.array([(1,2),(3,4)],dtype='<f4') 
numpy.hstack((x,y)) 

Если я удалю имена из x и y, это тоже работает.

Вопрос: как конкатенировать, vstack или hstack с названием numpy array? Примечание: numpy.lib.recfunctions.stack_arrays также не работает

ответ

3

Проблема в том, что типы разные. «Title» является частью типа, а y использует разные имена от x, поэтому типы несовместимы. Если вы используете совместимые типы, все работает отлично:

>>> x = numpy.array([(1, 2), (3, 4)], dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> y = numpy.array([(5, 6), (7, 8)], dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> numpy.vstack((x, y)) 
array([[(1.0, 2.0), (3.0, 4.0)], 
     [(5.0, 6.0), (7.0, 8.0)]], 
     dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> numpy.hstack((x, y)) 
array([(1.0, 2.0), (3.0, 4.0), (5.0, 6.0), (7.0, 8.0)], 
     dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> numpy.dstack((x, y)) 
array([[[(1.0, 2.0), (5.0, 6.0)], 
     [(3.0, 4.0), (7.0, 8.0)]]], 
     dtype=[('a', '<f4'), ('b', '<f4')]) 

Иногда dstack и т.д., достаточно умен, чтобы принуждать типы в разумном пути, но numpy не имеет никакого способа узнать, как объединить записи массивов с различным определяемым пользователем имена полей.

Если вы хотите объединить типы данных , вам необходимо создать новый тип данных. Не делайте ошибку, думая, что последовательность имен (x['a'], x['b'] ...) представляет собой истинное измерение массива; x и y - 1-мерные массивы блоков памяти, каждый из которых содержит два 32-битных поплавка, к которым можно получить доступ, используя имена 'a' и 'b'. Но, как вы можете видеть, если вы получаете доступ к отдельному элементу в массиве, вы не получите другого массива, как если бы это было действительно второе измерение. Вы можете увидеть разницу здесь:

>>> x = numpy.array([(1, 2), (3, 4)], dtype=[('a', '<f4'), ('b', '<f4')]) 
>>> x[0] 
(1.0, 2.0) 
>>> type(x[0]) 
<type 'numpy.void'> 

>>> z = numpy.array([(1, 2), (3, 4)]) 
>>> z[0] 
array([1, 2]) 
>>> type(z[0]) 
<type 'numpy.ndarray'> 

Это то, что позволяет массивам записей содержать гетерогенные данные; записи могут содержать как строки, так и ints, но компромисс заключается в том, что вы не получаете полную мощность ndarray на уровне отдельных записей.

Результат состоит в том, чтобы объединить отдельные блоки памяти, вам действительно нужно изменить размер массива dtype. Есть несколько способов сделать это, но самый простой я мог бы найти включает малоизвестную numpy.lib.recfunctions библиотеку (которую я вижу, вы уже нашли!):

>>> numpy.lib.recfunctions.rec_append_fields(x, 
              y.dtype.names, 
              [y[n] for n in y.dtype.names]) 
rec.array([(1.0, 2.0, 1.0, 2.0), (3.0, 4.0, 3.0, 4.0)], 
     dtype=[('a', '<f4'), ('b', '<f4'), ('c', '<f4'), ('d', '<f4')]) 
+1

Но это не то, что я ищу .. Я хочу, чтобы у нового массива были заголовки, унаследованные от объединения ... например после hstack я хочу иметь заголовки: 'a', 'b', 'c', 'd'. Почему python заботится об именах, а не только о типе ?! Сводит меня с ума. Я думаю, что мне нужно использовать Панды, а не просто numpy. –

+0

@HananShteingart, вы используете неправильный подход, тогда вам нужно создать совершенно новый тип данных. Похоже, вы ошибочно полагаете, что 'x' и' y' являются 2-мя массивами. Они не. См. Мои правки выше. – senderle