numpy slices를 사용하여이 복잡한 표현을 표현하는 방법


14

파이썬에서 여기서 와 는 크기의 numpy 배열 이며 크기의 numpy 배열입니다 . 크기 은 최대 약 10000 일 수 있으며이 함수는 여러 번 평가 될 내부 루프의 일부이므로 속도가 중요합니다.

엑스나는=제이=1나는1케이나는제이,제이나는제이제이,
엑스와이케이×

이상적으로는 for 루프를 피하고 싶지만 세상에 끝이 없다면 세계의 끝이 아니라고 생각합니다. 문제는 몇 개의 중첩 루프를 사용하지 않고 어떻게 해야하는지 알지 못한다는 것이므로 다소 느려질 수 있습니다.

누구든지 효율적이고 읽기 쉬운 방식으로 numpy를 사용하여 위의 방정식을 표현하는 방법을 볼 수 있습니까? 더 일반적으로, 이런 종류의 것에 접근하는 가장 좋은 방법은 무엇입니까?


며칠 전에 비슷한 질문이있었습니다. 나는 그것을 stackoverflow에서 물었다. 이 게시물을 확인하십시오 . cython 대신 scipy.weave를 사용합니다. 이것이 (상당한) 성능 차이를 일으키는 지 아는 사람이 있습니까?
seb

답변:


17

여기 Numba 솔루션이 있습니다. 내 컴퓨터에서 Numba 버전은 데코레이터가없는 파이썬 버전보다 1000 배 이상 빠릅니다 (200x200 매트릭스 'k'및 200 길이 벡터 'a'). 또한 호출 당 약 10 마이크로 초를 추가하는 @autojit 데코레이터를 사용하여 동일한 코드가 여러 유형에서 작동 할 수 있습니다.

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

3
Travis, 매우 멋지다, 당신은 당신이 numba 개발자 중 하나라는 답변의 맨 아래에 공개를 추가 하시겠습니까?
Aron Ahmadia

1
함께 의 사이 썬 버전은 훨씬 더 빨리 상대 루프 파이썬 (~ 700X, 나를 위해)입니다. 이 성능이 더 큰 행렬에 따라 어떻게 변하는 지, 그리고 동일한 (메모리?) 병목 현상이 발생하는지 궁금합니다. =200
Nat Wilson

@NatWilson-당신이 scicomp에 대한 질문으로 이것을 물으면, 나는 당신을 위해 그것을 시도하고 해결 드리겠습니다 :)
Aron Ahmadia

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 슬라이스로 단일 루프로 만들었습니다.

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)

때 명시 적 루프가 하나 인 numpy 버전은 내 컴퓨터에서 약 25 배 빠릅니다 .=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 코드와 비슷한 것으로 보였습니다.


엑스0나는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])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.