如何使用numpy slices表达这种复杂的表达式


14

我希望在Python中实现以下表达式: 其中和是大小为 numpy数组,是一个大小为的numpy数组。大小可能最大约为10000,并且该函数是内部循环的一部分,该循环将被多次评估,因此速度非常重要。

X一世=Ĵ=1个一世-1个ķ一世-ĴĴ一种一世-Ĵ一种Ĵ
Xÿñķñ×ññ

理想情况下,我希望完全避免for循环,尽管我想如果有一个循环就不是世界末日了。问题是我很难在没有几个嵌套循环的情况下查看如何做到这一点,这可能会使它变得很慢。

有人可以看到如何使用numpy高效且容易理解的方式表达上述方程吗?更一般而言,解决此类问题的最佳方法是什么?


几天前我也有类似的问题。我在stackoverflow上询问了它。看看这个帖子。我使用scipy.weave而不是cython。有人知道这是否会带来(可观的)性能差异吗?
2013年

Answers:


17

这是Numba解决方案。在我的机器上,Numba版本比不带装饰器的python版本快1000倍以上(对于200x200矩阵,“ k”和200长度矢量“ a”)。您还可以使用@autojit装饰器,该装饰器每次调用会增加大约10微秒的时间,以便同一代码可用于多种类型。

from numba import jit, autojit

@jit('f8[:](f8[:,:],f8[:])')
#@autojit
def looped_ver(k, a):
    x = np.empty_like(a)
    for i in range(x.size):
        sm = 0.0
        for j in range(0, i+1):
            sm += k[i-j,j] * a[i-j] * a[j]
        x[i] = sm
    return x

披露:我是Numba开发人员之一。


谢谢,这看起来很简单。我什至不知道numba!Cython,PyPy,Numba……这是一个令人困惑的世界。
纳撒尼尔(Nathaniel)2013年

3
特拉维斯(Travis),非常酷,您介意在答案的底端添加一个声明,表明您是numba开发人员之一吗?
Aron Ahmadia 2013年

1
ñ=200

@NatWilson-如果您在scicomp上提出这个问题,我很乐意为您解决:)
Aron Ahmadia 2013年

4

这是一个开始。首先,对于任何错误,我深表歉意。

一世一世-1个

编辑:不,上限是正确的问题中提供。我将其保留为此处,因为另一个答案现在使用相同的代码,但是修复很简单。

首先是循环版本:

def looped_ver(k, a):
    x = np.empty_like(a)
    for i in range(x.size):
        sm = 0
        for j in range(0, i+1):
            sm += k[i-j,j] * a[i-j] * a[j]
        x[i] = sm
    return x

我用numpy slices使它成为一个循环:

def vectorized_ver(k, a):
    ktr = zeros_like(k)
    ar = zeros_like(k)
    sz = len(a)
    for i in range(sz):
        ktr[i,:i+1] = k[::-1].diagonal(-sz+i+1)
        a_ = a[:i+1]
        ar[i,:i+1] = a_[::-1] * a_
    return np.sum(ktr * ar, 1)

ñ=5000

然后,我编写了(更易理解的)循环代码的Cython版本。

import numpy as np
import cython
cimport numpy as np

@cython.boundscheck(False)
@cython.wraparound(False)
def cyth_ver(double [:, ::1] k not None,
              double [:] a not None):
    cdef double[:] x = np.empty_like(a)
    cdef double sm
    cdef int i, j

    for i in range(len(a)):
        sm = 0.0
        for j in range(i+1):
            sm = sm + k[i-j,j] * a[i-j] * a[j]
        x[i] = sm
    return x

在我的笔记本电脑上,这台笔记本电脑的速度比循环版本快200倍(比1循环矢量化版本快8倍)。我相信其他人可以做得更好。

我使用了Julia版本,并且(如果我正确地设定了时间的话)看起来与Cython代码相当。


X0一世-1个

知道了 我是从最初的总结中收集到的,但是不确定那是意图。
Nat Wilson

1

您想要的似乎是一个卷积;我认为实现此目标的最快方法就是numpy.convolve功能。

您可能必须根据自己的确切需求来固定索引,但是我认为您想尝试以下方法:

import numpy as np
a = [1, 2, 3, 4, 5]
k = [2, 4, 6, 8, 10]

result = np.convolve(a, k*a[::-1])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.