在一个numpy数组中相乘


87

我试图将2D数组中的每个项乘以1D数组中的相应项。如果我想将每一列乘以一维数组,这非常容易,如numpy.multiply函数所示。但是我想相反,将行中的每一项相乘。换句话说,我想乘以:

[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]

有谁知道用numpy可以做到这一点吗?非常感谢Alex


3
嗯,我提交问题时就知道了。首先转置平方矩阵,相乘,然后转置答案。
Alex S

最好将行转置为列矩阵,然后不必重新转置答案。如果A * B需要通过添加新轴()来进行A * B[...,None]转置。BNone
askewchan

谢谢,是的。问题是当您有一维数组调用.transpose()或.T时,它不会将其转换为列数组,而是将其保留为一行,据我所知,您必须将其定义为列马上行动。喜欢x = [[1],[2],[3]]或类似的东西。
Alex S

Answers:


114

像您显示的正常乘法:

>>> 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]])

使用新的轴方法,可以将两个一维数组相乘并生成一个二维数组。例如[a,b] op [c,d] -> [[a*c, b*c], [a*d, b*d]]
kon psych

47

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

A * b[:, None]

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

在此处输入图片说明


复制剧情的代码:

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(14)],
    logx=True,
    logy=True,
    xlabel="len(A), len(b)",
)

2
很好的触摸提供了情节的代码。谢谢。
rockNwaves

17

您还可以使用矩阵乘法(又名点积):

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

numpy.dot(c,a)

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


2
不错,+ 1,没想到
jterrace 2013年

10
dot在这里真的太过分了。你只是在做不必要乘以0和补充为0
碧波多黎各

2
如果要将nx1向量乘以d大于n的nxd矩阵,这也可能触发内存问题。
乔纳森

降低投票速度因为这样做很慢,并且在创建密集diag矩阵时会占用大量内存。
NicoSchlömer18年

16

另一个技巧(从v1.6开始)

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

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

我精通numpy广播(newaxis),但仍可以在这个新einsum工具周围找到自己的出路。因此,我花了些力气找到了这个解决方案。

时间(使用Ipython timeit):

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

顺便说一句,将a更改ijnp.einsum('ij,j->ij',A,b)会生成Alex不需要的矩阵。并且np.einsum('ji,j->ji',A,b)实际上会进行双重转置。


1
如果您要在具有足够大阵列的计算机上进行计时,至少需要几毫秒的时间,并将结果与相关的系统信息一起发布到此处,将不胜感激。
丹尼尔(Daniel)

1
如果数组较大(100x100),则相对数大致相同。 einsumm(25 micro)的速度是其他速度的两倍(点diag的速度更慢)。这是NP 1.7,使用“ libatlas3gf-sse2”和“ libatlas-base-dev”(Ubuntu 10.4,单处理器)进行了最新编译。 timeit给出10000个循环中的最佳循环。
hpaulj

1
这是一个很好的答案,我认为这是应该接受的答案。但是,上面编写的代码实际上给出了Alex试图避免的矩阵(在我的机器上)。一个人说错了,实际上是正确的。
Yair Daon 2014年

在这里的时间是误导的。dot-diag确实比其他三个选项差很多,并且einsum也不比其他三个选项快。
NicoSchlömer,

@NicoSchlömer,我的回答已经有将近5年的历史了,并且有很多numpy版本。
hpaulj

1

对于那些在Google上迷失了灵魂的人,使用numpy.expand_dimsthennumpy.repeat将起作用,并且还将在更高维度的情况下起作用(即,将形状(10,12,3)乘以(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]])

-4

你为什么不做

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

??


6
确切的方法已经在接受的答案中显示,我看不到它如何添加任何内容。
Baum mit Augen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.