矩阵乘法:将矩阵的每一行乘以 Python 中的另一个二维矩阵
Matrix Multiplication: Multiply each row of matrix by another 2D matrix in Python
我正在尝试从此矩阵乘法中删除循环(并了解有关优化代码的更多信息),我想我需要某种形式的 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 matrix by each row of another matrix in Numpy,但我不知道它是否真的和我的问题一样。
您可以将对 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 数组的对角线。这可能会带来一些性能提升(根据 docs)
>>> np.diag(np.linalg.multi_dot([A.T, B, A]))
array([436, 534, 644, 766, 900])
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
维度成为 3d 数组的第一个维度。这是 'passive' 结转结果:
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]
atTo 添加到答案中。如果你想使矩阵相乘,你可以使用广播。编辑:注意这是按元素乘法,不是点积。为此,您可以使用点方法。
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]]])
我正在尝试从此矩阵乘法中删除循环(并了解有关优化代码的更多信息),我想我需要某种形式的 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 matrix by each row of another matrix in Numpy,但我不知道它是否真的和我的问题一样。
您可以将对 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 数组的对角线。这可能会带来一些性能提升(根据 docs)
>>> np.diag(np.linalg.multi_dot([A.T, B, A]))
array([436, 534, 644, 766, 900])
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
维度成为 3d 数组的第一个维度。这是 'passive' 结转结果:
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]
atTo 添加到答案中。如果你想使矩阵相乘,你可以使用广播。编辑:注意这是按元素乘法,不是点积。为此,您可以使用点方法。
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]]])