Performance numpy:计算矩阵中的函数,在计算下一个数组时使用上一个数组作为参数

Performance numpy:计算矩阵中的函数,在计算下一个数组时使用上一个数组作为参数,performance,numpy,differential-equations,difference-equations,Performance,Numpy,Differential Equations,Difference Equations,我有一个mxn数组:a,其中整数m>1E6,而n稍快一些。您的第一列基本上是2^n。为n计算2^n(最多1000000个)将溢出。。第二列更糟 def calc(arr, t0=1E-6): u = arr[0] dt = 1E-6 h = lambda x: np.random.random(1)*50.0 def firstColGen(uStart): u = uStart while True: u

我有一个
mxn
数组:
a
,其中整数
m>1E6
,而
n稍快一些。您的第一列基本上是2^n。为n计算2^n(最多1000000个)将溢出。。第二列更糟

def calc(arr, t0=1E-6):
    u = arr[0]
    dt = 1E-6
    h = lambda x: np.random.random(1)*50.0

    def firstColGen(uStart):
        u = uStart
        while True:
            u += u
            yield u

    def secondColGen(uStart, A):
        u = uStart
        while True:
            u += u*A
            yield u

    def thirdColGen(uStart):
        u = uStart
        while True:
            u += np.cos(u)
            yield u

    def fourthColGen(uStart, h, t0, dt):
        u = uStart
        t = t0
        while True:
            u += h(u) * dt
            t += dt
            yield u

    first = firstColGen(u[0])
    second = secondColGen(u[1], A)
    third = thirdColGen(u[2])
    fourth = fourthColGen(u[3], h, t0, dt)

    for i in xrange(1, len(arr)):
        arr[i] = [first.next(), second.next(), third.next(), fourth.next()]

这种事情在努比很难做到。如果我们按列查看,我们会看到一些更简单的解决方案

a[:,0]
非常简单:

col0 = np.ones((1000))*2
col0[0] = 1                  #Or whatever start value.
np.cumprod(col0, out=col0)

np.allclose(col0, a[:1000,0])
True
如前所述,这将很快溢出
a[:,1]
可以按照同样的思路进行

我不相信有一种方法可以在numpy中单独快速完成接下来的两个专栏。我们可以求助于numba:

from numba import auotojit

def python_loop(start, count):
     out = np.zeros((count), dtype=np.double)
     out[0] = start
     for x in xrange(count-1):
         out[x+1] = out[x] + np.cos(out[x+1])
     return out

numba_loop = autojit(python_loop)

np.allclose(numba_loop(3,1000),a[:1000,2])
True

%timeit python_loop(3,1000000)
1 loops, best of 3: 4.14 s per loop

%timeit numba_loop(3,1000000)
1 loops, best of 3: 42.5 ms per loop
尽管值得指出的是,它收敛到pi/2的速度非常快,对于任何起始值,计算超过20个值的递归几乎没有意义。这将返回与双点精度完全相同的答案-我没有费心寻找截止点,但它远小于50:

%timeit tmp = np.empty((1000000)); 
        tmp[:50] = numba_loop(3,50);
        tmp[50:] = np.pi/2
100 loops, best of 3: 2.25 ms per loop
您可以对第四列执行类似的操作。当然,您可以
autojit
所有功能,但这会根据numba的使用情况提供几种不同的选项供您尝试:

  • 对前两列使用cumprod
  • 对第3列(和可能的第4列)使用近似值,其中仅计算前几次迭代
  • 使用
    autojit
  • 将所有内容包装在autojit循环中(最佳选项)
  • 您在~200之后的所有行中显示该值的方式将是
    np.inf
    np.pi/2
    。利用这一点

  • 你的问题不完全有道理。。。如果u是先前计算的行,则公式永远不会使用当前行。我猜您的意思是类似于F**(*v,G**(*u,t)),其中u是计算最后一行的结果,v是当前行,但请确认并定义如何处理第一行,其中没有“先前计算的行”。而且,更重要的是,在不知道F和G是做什么的情况下,我怀疑任何人都能给你一个满意的答案。不,据我所知,我键入的是我想做的。我将添加更多信息。您能为一个缓慢但正确的实现添加代码吗?第二列可以是np.cumprod([o0,a+1,a+1,…])。对于另外两个,您必须定制UFUNC。。。但是numba是一个很好的建议!使用numbapro,您甚至可以将其并行化:)
    %timeit tmp = np.empty((1000000)); 
            tmp[:50] = numba_loop(3,50);
            tmp[50:] = np.pi/2
    100 loops, best of 3: 2.25 ms per loop