将一个数组的每个元素乘以另一个数组的每个元素

时间:2015-06-02 04:00:59

标签: python arrays numpy vectorization cartesian-product

说我有两个数组,

import numpy as np


x = np.array([1, 2, 3, 4])
y = np.array([5, 6, 7, 8])

获得新数组z的最快,最Pythonic等方法是什么,其中包含许多等于x.size * y.size的元素,其中元素是每个元素的产物来自两个输入数组的元素对(x_i, y_j)

要改写,我正在寻找zz[k]的数组x[i] * y[j]

一种简单但效率低下的方法如下:

z = np.empty(x.size * y.size)
counter = 0
for i in x:
    for j in y:
        z[counter] = i * j
        counter += 1

运行上面的代码显示此示例中的z

In [3]: z
Out[3]: 
array([  5.,   6.,   7.,   8.,  10.,  12.,  14.,  16.,  15.,  18.,  21.,
        24.,  20.,  24.,  28.,  32.])

5 个答案:

答案 0 :(得分:4)

嗯,我对numpy有很多经验,但快速搜索给了我这个: http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.outer.html

>>> np.multiply.outer([1, 2, 3], [4, 5, 6])
array([[ 4,  5,  6],
   [ 8, 10, 12],
   [12, 15, 18]])

然后,您可以展平该数组以获得您请求的相同输出: http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.flatten.html

编辑:@Divakar的答案向我们表明,ravel会做与flatten相同的事情,除了更快o.O所以请使用它。

所以在你的情况下,它看起来像这样:

>>> np.multiply.outer(x, y).ravel()

奖励:你可以用这个来多维度!

答案 1 :(得分:2)

这是一种方法:

import itertools


z = np.empty(x.size * y.size)
counter = 0
for i, j in itertools.product(x, y):
    z[counter] = i * j
    counter += 1

尽管摆脱那个计数器,以及for循环(但至少我摆脱了其中一个循环),这很好。

更新

作为一个单行,其他提供的答案比这个更好(根据我的标准,它重视简洁)。下面的时间结果表明,@ BilalAkil的答案比@TimLeathart的答案要快:

In [10]: %timeit np.array([x * j for j in y]).flatten()
The slowest run took 4.37 times longer than the fastest. This could mean that an intermediate result is being cached 
10000 loops, best of 3: 24.2 µs per loop

In [11]: %timeit np.multiply.outer(x, y).flatten()
The slowest run took 5.59 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 10.5 µs per loop

答案 2 :(得分:2)

这是一种方法:

import numpy as np

x = np.array([1, 2, 3, 4])
y = np.array([5, 6, 7, 8])
z = np.array([y * a for a in x]).flatten()

答案 3 :(得分:1)

这里可以提出另外两种方法。

使用matrix-multiplication with np.dot

np.dot(x[:,None],y[None]).ravel()

使用np.einsum

np.einsum('i,j->ij',x,y).ravel()

运行时测试

In [31]: N = 10000
    ...: x = np.random.rand(N)
    ...: y = np.random.rand(N)
    ...: 

In [32]: %timeit np.dot(x[:,None],y[None]).ravel()
1 loops, best of 3: 302 ms per loop

In [33]: %timeit np.einsum('i,j->ij',x,y).ravel()
1 loops, best of 3: 274 ms per loop

@BilalAkil's answer相同,但使用ravel()代替flatten()作为更快的替代方案 -

In [34]: %timeit np.multiply.outer(x, y).ravel() 
1 loops, best of 3: 211 ms per loop

@BilalAkil's answer

In [35]: %timeit np.multiply.outer(x, y).flatten()
1 loops, best of 3: 451 ms per loop

@Tim Leathart's answer

In [36]: %timeit np.array([y * a for a in x]).flatten()
1 loops, best of 3: 766 ms per loop

答案 4 :(得分:0)

我知道我在这里参加聚会迟到了,但是我认为以后对阅读此问题的任何人都应该戴上帽子。使用与@Divakar相同的度量标准,我在列表中添加了我认为是更直观的解决方案(测量的第一个代码段):

import numpy as np
N = 10000
x = np.random.rand(N)
y = np.random.rand(N)

%timeit np.ravel(x[:,None] * y[None])
635 ms ± 19.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit np.outer(x, y).ravel()
640 ms ± 16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit np.dot(x[:,None],y[None]).ravel()
853 ms ± 57.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit np.einsum('i,j->ij',x,y).ravel()
754 ms ± 19.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

基于执行时间的相似性,numpy.outer的内部功能似乎与我的解决方案完全相同,尽管您应该使用大量的盐进行此类观察。

我觉得它更直观的原因是,与所有其他解决方案不同,它的语法并不严格限于乘法。例如,np.ravel(x[:,None] / y[None])将为x中的每个a和y中的b都给您一个a / b。