迭代外部加法

时间:2019-12-07 16:05:37

标签: python numpy addition

我想对多个向量/矩阵进行外加。让我们说四遍:

import numpy as np 

x = np.arange(100)
B = np.add.outer(x,x)
B = np.add.outer(B,x)
B = np.add.outer(B,x)

如果加法的数量可以是一个变量,例如a=4->加法的4倍,我最好。这可能吗?

3 个答案:

答案 0 :(得分:3)

方法1

这里是带有数组初始化功能的一个-

n = 4 # number of iterations to add outer versions
l = len(x)
out = np.zeros([l]*n,dtype=x.dtype)
for i in range(n):
    out += x.reshape(np.insert([1]*(n-1),i,l))

为什么使用这种方法而不是迭代添加来在每次迭代时创建新数组?

在每次迭代中迭代创建新数组将需要更多的内存,因此需要那里的内存开销。使用array-initialization,我们将x中的元素添加到已经初始化的数组中。因此,它试图以此来提高内存效率。

替代#1

我们可以使用x进行初始化来删除一个迭代。因此,更改将是-

out = np.broadcast_to(x,[l]*n).copy()
for i in range(n-1):

方法2:使用np.add.reduce -

另一种方法是使用np.add.reduce,它也不会创建任何中间数组,但是在这里使用归约方法可能会更好,因为这是它实现的目的-

l = len(x); n = 4
np.add.reduce([x.reshape(np.insert([1]*(n-1),i,l)) for i in range(n)])

时间-

In [17]: x = np.arange(100)

In [18]: %%timeit
    ...: n = 4 # number of iterations to add outer versions
    ...: l = len(x)
    ...: out = np.zeros([l]*n,dtype=x.dtype)
    ...: for i in range(n):
    ...:     out += x.reshape(np.insert([1]*(n-1),i,l))
829 ms ± 28.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [19]: l = len(x); n = 4

In [20]: %timeit np.add.reduce([x.reshape(np.insert([1]*(n-1),i,l)) for i in range(n)])
183 ms ± 2.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

答案 1 :(得分:1)

我认为没有内置参数可以重复执行此过程多次,但是您可以轻松地为其定义自定义函数

def recursive_outer_add(arr, num):
    if num == 1:
        return arr

    x = np.add.outer(arr, arr)

    for i in range(num - 1):
        x = np.add.outer(x, arr)
    return x

只是警告:数组很快变得很大

答案 2 :(得分:1)

短而合理的速度:

n = 4
l = 10
x = np.arange(l)

sum(np.ix_(*n*(x,)))

timeit(lambda:sum(np.ix_(*n*(x,))),number=1000)
# 0.049082988989539444

我们可以回到最前面来加快速度:

timeit(lambda:sum(reversed(np.ix_(*n*(x,)))),number=1000)
# 0.03847671199764591

我们还可以构建自己的反向np.ix_

from operator import getitem
from itertools import accumulate,chain,repeat

sum(accumulate(chain((x,),repeat((slice(None),None),n-1)),getitem))

timeit(lambda:sum(accumulate(chain((x,),repeat((slice(None),None),n-1)),getitem)),number=1000)
# 0.02427654700295534