我正在尝试重写以下例程(a,b,c,d和e都是数组):
def generate_a(b, c, e):
a = np.zeros_like(b)
d = np.zeros_like(b)
for i in range(a.size):
a[i] = (b[i] / c[i]) + d[i-1]
d[i] = a[i] * e[i]
return a
不使用'for'循环,因为例程需要运行数百万次。这是一个小技巧,因为d中任何给定单元格的值取决于为a中的单元格计算的结果,而该结果又取决于为d计算的最后一个值。关于如何在没有迭代的情况下完成这项工作的任何想法?
答案 0 :(得分:5)
受此solution
的启发,如果递归可以跟踪,则此帖子显示递归为vectorizable
。正如在链接解决方案中所述,同样不应该是现在的快速,但是要利用并行处理器,这种方法可以给出一个机会。因此,请将此帖作为如何跟踪和矢量化递归的指导。这是实施 -
def generate_a_vectorized(b, c, e):
K = (b/c)*e
N = e.size
mask = np.linspace(N,1,N,dtype=int)[:,None] <= np.arange(N)
Pn = np.tile(e[None],(N,1))
Pn[mask] = 1
En = Pn[:,::-1].cumprod(1)[:,::-1]
En[mask] = 0
An = np.append(0,K[:-1])
d_out = En.dot(An)[::-1] + K
return (b/c) + np.append(0,d_out[:-1])
样品运行&amp;验证输出 -
In [279]: M = 50
...: b = np.random.rand(M)
...: c = np.random.rand(M)
...: e = np.random.rand(M)
...:
In [280]: np.allclose(generate_a(b, c, e),generate_a_vectorized(b, c, e))
Out[280]: True
In [281]: %timeit generate_a(b,c,e)
10000 loops, best of 3: 79.4 µs per loop
In [282]: %timeit generate_a_vectorized(b,c,e)
10000 loops, best of 3: 157 µs per loop
答案 1 :(得分:3)
由于a[i]
取决于d[i-1]
而d[i-1]
取决于a[i-1]
,a[i]
也取决于a[0], a[1], ... a[i-1]
而你赢了能够并行计算并行化。您需要接受该循环或找出一种封闭的形式来进行计算。
答案 2 :(得分:1)
您可以使用map和lambda。
尝试:
import numpy as np
def func(i,l):
l[0][i] = (l[1][i] / l[2][i]) + l[3][i-1]
l[3][i] = l[0][i] * l[4][i]
return l[0][i]
def generate_a(b, c, e):
a = np.zeros_like(b)
d = np.zeros_like(b)
a = map(lambda i:func(i,[a, b, c, d, e]), xrange(a.size))
return a
print generate_a([5, 6, 7],[1,2,3],[8,9,12])
答案 3 :(得分:1)
使用Mathematica快速了解(因为b[i]/c[i]
与计算无关,我在下面称之为bc[i]
):
Wolfram Language (Raspberry Pi Pilot Release)
Copyright 1988-2015 Wolfram Research
Information & help: wolfram.com/raspi
In[1]:= RSolve[ { a[i]==bc[i] + a[i-1]*e[i-1], a[-1]==0 }, a[i], i]
Out[1]= {{a[i] ->
> Product[e[K[1]], {K[1], 1, -1 + i}]
bc[1 + K[2]]
> Sum[---------------------------------, {K[2], -1, -1 + i}]}}
Product[e[K[1]], {K[1], 1, K[2]}]
正如Randy C先前所说的那样,除非先前的计算会导致更简单的事情,否则我强烈怀疑你能比现有的更好。 您可以获得更好的代码,但可能没有更高效的代码。