Умножьте и суммируйте массивы numpy с формами (x, y, z) и (x,) - PullRequest
0 голосов
/ 31 марта 2020

Итак, у меня есть 3D-набор данных (x, y, z), и я хочу суммировать по одной из осей (x) с набором весов, w = w (x). Начальный и конечный индексы, по которым я суммирую, различен для каждого (y, z), я решил это, замаскировав 3D-массив. Веса постоянны по отношению к двум переменным, по которым я не суммирую. Оба ответа относительно реализации и математики приветствуются (есть ли умный способ сделать это?).

У меня есть массив 3D-маски (A) формы (x, y, z) и массив 1D (т) формы (х,). Есть ли хороший способ умножить каждый (y, z) элемент в A на соответствующее число в t, не расширяя t в трехмерный массив? Мое текущее решение заключается в использовании np.tensordot для создания трехмерного массива той же формы, что и A, который содержит все t-значения, но чувствует себя очень неудовлетворительно тратить во время выполнения на создание массива "new_t", который по сути просто y * z копии t.

Пример текущего решения:

a1 = np.array([[1,2,3,4],
               [5,6,7,8],
               [9,10,11,12]])

a2 = np.array([[0,1,2,3],
               [4,5,6,7],
               [8,9,10,11]])

#note: A is a masked array, mask is a 3D array of bools
A = np.ma.masked_array([a1,a2],mask)
t = np.array([10,11])

new_t = np.tensordot(t, np.ones(A[0].shape), axes = 0)
return np.sum(A*new_t, axis=0)

По сути, я хочу выполнить t * A [:, i, j] для всех i, j с максимально коротким временем выполнения желательно без использования слишком многих других библиотек, кроме numpy и scipy.

Другой способ получения желаемого результата (опять же, со слишком большим временем выполнения):

B = [[t*A[:,i,j] for j in range(A.shape[2])] for i in range(A.shape[1])]
return np.sum(B,axis=2)

Ответы [ 2 ]

1 голос
/ 31 марта 2020

Спасибо за хорошие ответы! Использовать тензорот, как предложенный @alyhosny, сработало, но замена маскированных значений на нули с помощью

A = np.ma.MaskedArray.filled(A,0)

перед суммированием с помощью einsum (спасибо @phipsgabler) дала половину времени выполнения. Конечный код:

A = np.ma.MaskedArray(A,mask)
A = np.ma.MaskedArray.filled(A,0)
return np.einsum('ijk,i->jk',A,t)
1 голос
/ 31 марта 2020

вдохновлено комментарием @phipsgabler

arr1 = np.tensordot(A.T,t,axes=1).T
arr1
array([[ 10,  31,  52,  73],
       [ 94, 115, 136, 157],
       [178, 199, 220, 241]])
...