如何高效地将一个运算符应用于两个数组的笛卡尔积?

5

我有a = array([1, 2, 3, 4, 5])b = array([10, 20, 30, 40, 50])。我想要:

array([[ -9, -19, -29, -39, -49],
       [ -8, -18, -28, -38, -48],
       [ -7, -17, -27, -37, -47],
       [ -6, -16, -26, -36, -46],
       [ -5, -15, -25, -35, -45]])

什么是最有效的做法?我有...
np.transpose([a]) - np.tile(b, (len(a), 1))

然而,如果a非常大,我想知道是否有比这更有效的方法,这种方法不需要经常复制b(或反之亦然)。

2个回答

10

一些NumPy函数例如np.subtractnp.addnp.multiplynp.dividenp.logical_andnp.bitwise_and等,有一个“outer”方法可以用来创建相当于“乘法表”的等效形式:

In [76]: np.subtract.outer(a, b)
Out[76]: 
array([[ -9, -19, -29, -39, -49],
       [ -8, -18, -28, -38, -48],
       [ -7, -17, -27, -37, -47],
       [ -6, -16, -26, -36, -46],
       [ -5, -15, -25, -35, -45]])

或者,使用广播:

In [96]: a[:, None] - b
Out[96]: 
array([[ -9, -19, -29, -39, -49],
       [ -8, -18, -28, -38, -48],
       [ -7, -17, -27, -37, -47],
       [ -6, -16, -26, -36, -46],
       [ -5, -15, -25, -35, -45]])

它们的性能大致相同:

In [98]: a = np.tile(a, 1000)

In [99]: b = np.tile(b, 1000)

In [100]: %timeit a[:, None] - b
10 loops, best of 3: 88.3 ms per loop

In [101]: %timeit np.subtract.outer(a, b)
10 loops, best of 3: 87.8 ms per loop

In [102]: %timeit np.transpose([a]) - np.tile(b, (len(a), 1))
10 loops, best of 3: 120 ms per loop

第二个会给出不同的结果,正如你所看到的。 - Claudiu
哦,看起来 a[:, None]np.transpose([a]) 是一样的.. 所以这和我的代码是一样的,只不过我不需要显式地使用 .tile - Claudiu
@Claudiu:是的,我认为主要是由于广播的原因造成的差异。 - unutbu
@unutbu:明白了,谢谢!我问这个问题是为了帮助我回答这个问题 - 你能否看一下并告诉我为什么非循环版本即使在应用了这里的答案后也不比循环版本快? - Claudiu
1
@Claudiu:我添加了一个名为optfunc3的函数,比optfunc2稍微快一点。它用1个调用替换了5个对np.transpose的调用。 - unutbu
显示剩余4条评论

0

你也可以使用np.vstack进行广播,但在其他答案之后没有任何新的想法:

np.vstack(a)-b

然而我喜欢这个,因为它非常简短。

此外,如果ab是基本的Python列表(不像上面评论中非常方便的a[:, None] - b),它也可以工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接