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

时间:2013-12-17 18:51:07

标签: performance numpy differential-equations difference-equations

我有一个m x n数组:a,其中整数为m > 1E6n <= 5

我的功能 F G ,其组成如下: F G ,t))。 1 x n数组,t是标量, F G 返回1 x n数组。

我需要评估 F row的每个a,并使用以前评估的行作为 u - 阵列进行下一次评估。我需要进行m这样的评估。

这一定非常快。我以前对整个数组的scitools.std StringFunction评估印象深刻,但是这个问题需要使用先前计算的数组作为计算下一个数组的参数。我不知道StringFunction是否可以做到这一点。

例如:

a = zeros((1000000, 4))
a[0] = asarray([1.,69.,3.,4.1])

# A is a float defined elsewhere, h is a function which accepts a float as its argument and returns an arbitrary float. h is defined elsewhere.

def G(u, t):
  return asarray([u[0], u[1]*A, cos(u[2]), t*h(u[3])])

def F(u, t):
  return u + G(u, t)


dt = 1E-6

for i in range(1, 1000000):
  a[i] = F(a[i-1], i*dt)
  i += 1

上面代码的问题在于它很慢。我需要通过numpy毫秒来完成这些计算。

我怎样才能做我想做的事?

感谢您抽出时间。

亲切的问候,

的Marius

2 个答案:

答案 0 :(得分:1)

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

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的使用情况,这会给你几种不同的选择:

  1. 前两列使用cumprod
  2. 使用第3列(和可能的4)的近似值,其中只计算前几次迭代
  3. 使用autojit
  4. 在numba中实施第3列和第4列
  5. 将所有内容包装在autojit循环中(最佳选项)
  6. 您将所有行显示超过~200的方式可以是np.infnp.pi/2。利用它。

答案 1 :(得分:0)

稍快一些。你的第一列基本上是2n。计算n ^到1000000的2 ^ n会溢出。第二列甚至更糟。

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()]