Все vs все точечный продукт - PullRequest
2 голосов
/ 26 мая 2020

У меня есть два массива 2D numpy A и B со следующими размерами (row, cols)

A.shape = (3000, 128) и B.shape = (5000, 128)

I wi sh to возьмите скалярное произведение для каждой строки A на каждую строку B. Например;

np.dot(A[0], B[0])
np.dot(A[0], B[1]
np.dot(A[0], B[2]
 .   *  .
 .   *  .  
 .   *  .
np.dot(A[0], B[last]) # last row in B
np.dot(A[1], B[0]) # new row in A
np.dot(A[1], B[1])
np.dot(A[1], B[2])
 .   *  .
 .   *  .  
 .   *  .
np.dot(A[last], B[last]) # last operation

Есть конкретное название этой операции?

Прямо сейчас у меня есть два цикла for, которые, как мне кажется, довольно медленные.

all_dots = []
for i in range(0, len(A)):
    for j in range(0, len(B)):
        all_dots.append(np.dot(B[j], A[i]))

Я ищу, возможно, родную операцию в линейной алгебре, которая решает эту проблему более эффективно.

Заранее спасибо!

Ответы [ 2 ]

5 голосов
/ 26 мая 2020

Это матричный продукт. Количество столбцов первой матрицы должно быть равно количеству строк во второй

np.dot(A, B.transpose())

, что дает эквивалент того, что делает ваш код с двумя вложенными циклами. Другой способ - использовать оператор матричного умножения @ и ярлык .T для .transpose()

A @ B.T

или метод .dot() для numpy массива

A.dot(B.transpose())

Престижность Дэну!

3 голосов
/ 26 мая 2020

Вы также можете использовать пресловутый einsum :

np.einsum('ij,kj->ik', a,b)

Тест:

a, b = np.arange(12).reshape(3,4), np.arange(16).reshape(4,4)

np.einsum('ij,kj->ik', a,b)

Вывод:

array([[ 14,  38,  62,  86],
       [ 38, 126, 214, 302],
       [ 62, 214, 366, 518]])

Если вы хотите 1-D массив, соедините его с .flatten() или ravel():

np.einsum('ij,kj->ik', a,b).ravel()

Вывод:

array([ 14,  38,  62,  86,  38, 126, 214, 302,  62, 214, 366, 518])
...