在 numpy 数组中横向相乘?

我试图将二维数组中的每个术语与一维数组中的相应术语相乘。这是非常容易的,如果我想乘以1D 数组的每一列,如 笨蛋,乘法函数所示。但是我想做相反的事情,将每一行中的项相乘。 换句话说,我想乘以:

[1,2,3]   [0]
[4,5,6] * [1]
[7,8,9]   [2]

然后

[0,0,0]
[4,5,6]
[14,16,18]

但我却得到了

[0,2,6]
[0,5,12]
[0,8,18]

有没有人知道有没有一种优雅的方式来处理麻木? 非常感谢, Alex

147055 次浏览

正常的乘法:

>>> import numpy as np
>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> c = np.array([0,1,2])
>>> m * c
array([[ 0,  2,  6],
[ 0,  5, 12],
[ 0,  8, 18]])

如果你添加一个坐标轴,它会按照你想要的方式进行乘法:

>>> m * c[:, np.newaxis]
array([[ 0,  0,  0],
[ 4,  5,  6],
[14, 16, 18]])

你也可以换位两次:

>>> (m.T * c).T
array([[ 0,  0,  0],
[ 4,  5,  6],
[14, 16, 18]])

You could also use matrix multiplication (aka dot product):

a = [[1,2,3],[4,5,6],[7,8,9]]
b = [0,1,2]
c = numpy.diag(b)


numpy.dot(c,a)

哪个更优雅可能是品味的问题。

还有一个技巧(在 v1.6中)

A=np.arange(1,10).reshape(3,3)
b=np.arange(3)


np.einsum('ij,i->ij',A,b)

我精通的麻木广播(newaxis) ,但我仍然找到我的方式围绕这个新的 einsum工具。所以我花了一点时间来寻找这个解决方案。

时间(使用 Ipython timeit) :

einsum: 4.9 micro
transpose: 8.1 micro
newaxis: 8.35 micro
dot-diag: 10.5 micro

顺便说一句,把 i改成 jnp.einsum('ij,j->ij',A,b),会产生 Alex 不想要的矩阵。而 np.einsum('ji,j->ji',A,b)实际上做到了双转座。

你为什么不直接去做呢

>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> c = np.array([0,1,2])
>>> (m.T * c).T

??

我比较了不同的速度选项,发现——令我惊讶的是——所有的选项(除了 diag)都同样快。我个人使用

A * b[:, None]

(或 (A.T * b).T)因为它很短。

enter image description here


重现情节代码:

import numpy
import perfplot




def newaxis(data):
A, b = data
return A * b[:, numpy.newaxis]




def none(data):
A, b = data
return A * b[:, None]




def double_transpose(data):
A, b = data
return (A.T * b).T




def double_transpose_contiguous(data):
A, b = data
return numpy.ascontiguousarray((A.T * b).T)




def diag_dot(data):
A, b = data
return numpy.dot(numpy.diag(b), A)




def einsum(data):
A, b = data
return numpy.einsum("ij,i->ij", A, b)




perfplot.save(
"p.png",
setup=lambda n: (numpy.random.rand(n, n), numpy.random.rand(n)),
kernels=[
newaxis,
none,
double_transpose,
double_transpose_contiguous,
diag_dot,
einsum,
],
n_range=[2 ** k for k in range(13)],
xlabel="len(A), len(b)",
)

For those lost souls on google, using numpy.expand_dims then numpy.repeat will work, and will also work in higher dimensional cases (i.e. multiplying a shape (10, 12, 3) by a (10, 12)).

>>> import numpy
>>> a = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
>>> b = numpy.array([0,1,2])
>>> b0 = numpy.expand_dims(b, axis = 0)
>>> b0 = numpy.repeat(b0, a.shape[0], axis = 0)
>>> b1 = numpy.expand_dims(b, axis = 1)
>>> b1 = numpy.repeat(b1, a.shape[1], axis = 1)
>>> a*b0
array([[ 0,  2,  6],
[ 0,  5, 12],
[ 0,  8, 18]])
>>> a*b1
array([[ 0,  0,  0],
[ 4,  5,  6],
[14, 16, 18]])