Умножение матриц: умножение каждой строки матрицы на другую двумерную матрицу в Python - PullRequest
0 голосов
/ 07 декабря 2018

Я пытаюсь удалить цикл из этого умножения матриц (и узнать больше об оптимизации кода в целом), и я думаю, что мне нужна некоторая форма np.broadcasting или np.einsum, но после прочтения их яЯ до сих пор не уверен, как использовать их для моей проблемы.

A = np.array([[1, 2, 3, 4, 5],
         [6, 7, 8, 9, 10],
         [11,12,13,14,15]])
#A is a 3x5 matrix, such that the shape of A is (3, 5) (and A[0] is (5,))

B = np.array([[1,0,0],
         [0,2,0],
         [0,0,3]])
#B is a 3x3 (diagonal) matrix, with a shape of (3, 3)

C = np.zeros(5)
for i in range(5):
    C[i] = np.linalg.multi_dot([A[:,i].T, B, A[:,i]])

#Each row of matrix math is [1x3]*[3x3]*[3x1] to become a scaler value in each row
#C becomes a [5x1] matrix with a shape of (5,)

Я знаю, что не могу просто сделать np.multidot сам по себе, потому что это приводит к массиву (5,5).

Я также нашел это: Multiplyматрица каждой строкой другой матрицы в Numpy , но я не могу сказать, действительно ли это та же проблема, что и у меня.

Ответы [ 3 ]

0 голосов
/ 07 декабря 2018
In [601]: C
Out[601]: array([436., 534., 644., 766., 900.])

Это естественно для einsum.Я использую i, как вы, чтобы обозначить индекс, который влияет на результат.j и k - это индексы, которые используются в сумме произведений.

In [602]: np.einsum('ji,jk,ki->i',A,B,A)
Out[602]: array([436, 534, 644, 766, 900])

Возможно, это также можно сделать с помощью mutmul, хотя для этого может потребоваться добавление размера и последующее сжатие.

dot подходы, использующие diag, выполняют намного больше работы, чем необходимо.diag выбрасывает много значений.

Чтобы использовать matmul, мы должны сделать измерение i первым из трехмерных массивов.Это «пассивный» результат, который переносится на результат:

In [603]: A.T[:,None,:]@B@A.T[:,:,None]
Out[603]: 
array([[[436]],     # (5,1,1) result

       [[534]],

       [[644]],

       [[766]],

       [[900]]])
In [604]: (A.T[:,None,:]@B@A.T[:,:,None]).squeeze()
Out[604]: array([436, 534, 644, 766, 900])

Или индексировать дополнительные измерения: (A.T[:,None,:]@B@A.T[:,:,None])[:,0,0]

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

при добавлении к ответам.Если вы хотите умножить матрицы, вы можете использовать вещание.Изменить: Обратите внимание, что это умножение элементов, не точечные продукты.Для этого вы можете использовать точечные методы.

 B [...,None] * A

Дает:

array([[[ 1,  2,  3,  4,  5],
        [ 0,  0,  0,  0,  0],
        [ 0,  0,  0,  0,  0]],

       [[ 0,  0,  0,  0,  0],
        [12, 14, 16, 18, 20],
        [ 0,  0,  0,  0,  0]],

       [[ 0,  0,  0,  0,  0],
        [ 0,  0,  0,  0,  0],
        [33, 36, 39, 42, 45]]])
0 голосов
/ 07 декабря 2018

Вы можете объединить вызовы в dot вместе, а затем получить диагональ:

# your original output:
# >>> C
# array([436., 534., 644., 766., 900.])

>>> np.diag(np.dot(np.dot(A.T,B), A))
array([436, 534, 644, 766, 900])

Или, эквивалентно, использовать исходный ход мысли multi_dot, но взять диагональ полученного массива 5x5,Это может иметь некоторое повышение производительности (согласно документам )

>>> np.diag(np.linalg.multi_dot([A.T, B, A]))
array([436, 534, 644, 766, 900])
...