Как преобразовать кортеж глубины 2 в двумерный массив Numpy?

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

import numpy as np
a=np.asarray([[1,2,3],[2,3,4,5]])
print a

Вывод ошибки:

IndexError: too many indices 

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

Обновление: интересно, когда я пытаюсь что-то вроде:

a=np.asarray([np.asarray([1,2,3]),np.asarray([2,3,4,5])])
b=np.asarray([np.asarray([1,2,3]),np.asarray([2,3,4,5])])
print np.multiply(a,b)

Это создает желаемый результат! который является поэлементным умножением.

[array([1, 4, 9]) array([ 4,  9, 16, 25])]

2 ответа

Решение

Вы не можете преобразовать свой пример напрямую в массив NumPy, потому что у вас есть разные длины. В результате вы получаете массив 1d NumPy, который содержит объекты списка Python. Я видел, что вы пытаетесь сделать, называя его неровным массивом, но не уверен, что это какой-то официальный термин.

Вы можете заполнить элементы нулями или использовать разреженную матрицу, или просто не конвертировать в NumPy. Зависит от вашей общей цели.

Чтобы начать, вот как вы можете установить маскированный массив из зубчатого массива и вычислить сумму по оси. Кто-то, кто использует этот модуль больше меня, может предложить что-то более эффективное или идиоматическое:

>>> a = np.array([[[1,2,3],[2,3,4,5], [2, 2]],[[3,4,5,6,7],[1],[2,3,10]]])
>>> D = max(len(x) for x in y for y in a)
>>> padded = [[x + [0] * (D-len(x)) for x in y] for y in a]
>>> mask = [[[0] * len(x) + [1] * (D-len(x)) for x in y] for y in a]
>>> result = np.ma.masked_array(padded, np.array(mask, dtype=np.bool))
>>> result
masked_array(data =
 [[[1 2 3 -- --]
  [2 3 4 5 --]
  [2 2 -- -- --]]

 [[3 4 5 6 7]
  [1 -- -- -- --]
  [2 3 10 -- --]]],
             mask =
 [[[False False False  True  True]
  [False False False False  True]
  [False False  True  True  True]]

 [[False False False False False]
  [False  True  True  True  True]
  [False False False  True  True]]],
       fill_value = 999999)

>>> np.sum(result, axis=-1)
masked_array(data =
 [[6 14 4]
 [25 1 15]],
             mask =
 [[False False False]
 [False False False]],
       fill_value = 999999)

>>> 

Если я поменяю a а также b поэтому numpy создает 2d-массив вместо массива массивов:

In [5]: am=np.asarray([np.asarray([1,2,3,0]),np.asarray([2,3,4,5])])
#array([[1, 2, 3, 0],
#       [2, 3, 4, 5]])
In [7]: bm=np.asarray([np.asarray([1,2,3,0]),np.asarray([2,3,4,5])])

и делать время:

In [10]: timeit np.multiply(a,b)
100000 loops, best of 3: 7.94 us per loop

In [11]: timeit np.multiply(am,bm)
100000 loops, best of 3: 1.89 us per loop

Чистое умножение ndarray существенно быстрее. В одном случае он может перейти непосредственно к выполнению элемента путем умножения элемента (при быстром C уровень кода); в другом он выполняет итерацию общего назначения, работая с объектами, а не с простыми числами. Это делает что-то похожее на итерации в Python.

На самом деле, если я сделаю этот цикл явно, я получу что-то близкое к этому более длительному времени

al,bl=a.tolist(), b.tolist()
In [21]: timeit np.array([np.multiply(x,y) for x,y in zip(al,bl)])
100000 loops, best of 3: 8.99 us per loop

Теперь давайте посмотрим на вашу проблему "сумма по последнему измерению". Сначала обратите внимание, что sum (или же add.reduce) не был расширен для работы с этим типом массива.

In [37]: timeit am.sum(axis=1)
100000 loops, best of 3: 11.5 us per loop

In [38]: timeit [x.sum() for x in a]
10000 loops, best of 3: 21.5 us per loop

Преимущество в скорости ndarray sum не так хорошо sum можно ускорить, кодируя его как dot продукт (с np.dot или же einsum):

In [42]: timeit np.einsum('ij->i',am)
100000 loops, best of 3: 4.79 us per loop

In [50]: ones=np.array([1,1,1,1])
In [51]: timeit np.dot(am,ones)
100000 loops, best of 3: 2.37 us per loop

In [55]: timeit [np.einsum('j->',x) for x in a]
100000 loops, best of 3: 12.3 us per loop

In [64]: c=np.asarray([np.asarray([1,1,1]),np.asarray([1,1,1,1])])   
In [65]: timeit [np.dot(x,y) for x,y in zip(a,c)]
100000 loops, best of 3: 8.12 us per loop

Таким образом, хотя можно создавать рваные массивы (или массивы массивов), они не имеют существенного преимущества в скорости перед списками массивов. Быстро numpy Операции с массивами, как правило, не работают с элементами, которые являются объектами Python общего назначения (dtype=object).

Другие вопросы по тегам