相互依赖的数组的numpy矢量化

时间:2016-09-08 13:42:10

标签: numpy vectorization

我需要根据它们之前的元素同时填充两个相互依赖的数组,如下所示:

import numpy as np
a = np.zeros(100)
b = np.zeros(100)
c = np.random.random(100)

for num in range(1, len(a)):
    a[num] = b[num-1] + c[num]
    b[num] = b[num-1] + a[num]

有没有办法真正使用numpy对它进行矢量化(即不使用numpy.vectorize)?请注意,这些是任意数组,而不是寻找这些特定值的解决方案。

3 个答案:

答案 0 :(得分:3)

正如@ Praveen的帖子中所提到的,我们可以编写那些表达式,用于尝试找到封闭形式的几次迭代,这当然是c的三角矩阵。然后,我们只需添加迭代缩放 b[0]即可获得完整b。要获得a,我们只需添加bc的移位版本。

因此,为了提高效率,使用一些NumPy broadcastingdot-product来实现这一点是不同的做法 -

p = 2**np.arange(a.size-1)
scale1 = p[:,None]//p
b_out = np.append(b[0],scale1.dot(c[1:]) + 2*p*b[0])
a_out = np.append(a[0],b_out[:-1] + c[1:])

如果ab始终以0开头,则最后两个步骤的代码将简化为 -

b_out = np.append(0,scale1.dot(c[1:]))
a_out = np.append(0,b_out[:-1] + c[1:])

答案 1 :(得分:2)

是的,有:

c = np.arange(100)
a = 2 ** c - 1
b = numpy.cumsum(a)

答案 2 :(得分:1)

显然,更新是:

a_i = b_i-1 + c_i
b_i = 2*b_i-1 + c_i

写出递归,

b_0 = c_0              # I'm not sure if c_0 is to be used
b_1 = 2*b_0 + c_1
    = 2*c_0 + c_1
b_2 = 2*b_1 + c_2
    = 2*(2*c_0 + c_1) + c_2
    = 4*c_0 + 2*c_1 + c_2
b_3 = 2*b_2 + c_3
    = 2*(4*c_0 + 2*c_1 + c_2) + c_3
    = 8*c_0 + 4*c_1 + 2*c_2 + c_3

所以看起来似乎

b_i = np.sum((2**np.arange(i+1))[::-1] * c[:i])
a_i = b_i-1 + c_i

这里不可能累积总和,因为c_i的系数不断变化。

完全矢量化的最简单方法是使用巨型矩阵。如果c的尺寸为N

t = np.zeros((N, N))
x, y = np.tril_indices(N)
t[x, y] = 2 ** (x - y)

这给了我们:

>>> t
array([[ 1.,  0.,  0.,  0.],
       [ 2.,  1.,  0.,  0.],
       [ 4.,  2.,  1.,  0.],
       [ 8.,  4.,  2.,  1.]])

现在你可以这样做:

b = np.sum(t * c, axis=1)
a = np.zeros(N)
a[1:] = b[:-1] + c[1:]

我可能不会推荐这个解决方案。从我对计算方法知之甚少,对于大N而言,这似乎在数值上不稳定。但我感觉这对于任何最终执行求和的矢量化解决方案都是如此。也许你应该尝试使用for-loop和这段代码,看看你的错误是否继续引发矢量化解决方案。