파이썬에서
여기서 와 는 크기의 numpy 배열 이며 크기의 numpy 배열입니다 . 크기 은 최대 약 10000 일 수 있으며이 함수는 여러 번 평가 될 내부 루프의 일부이므로 속도가 중요합니다.
이상적으로는 for 루프를 피하고 싶지만 세상에 끝이 없다면 세계의 끝이 아니라고 생각합니다. 문제는 몇 개의 중첩 루프를 사용하지 않고 어떻게 해야하는지 알지 못한다는 것이므로 다소 느려질 수 있습니다.
누구든지 효율적이고 읽기 쉬운 방식으로 numpy를 사용하여 위의 방정식을 표현하는 방법을 볼 수 있습니까? 더 일반적으로, 이런 종류의 것에 접근하는 가장 좋은 방법은 무엇입니까?
답변
여기 Numba 솔루션이 있습니다. 내 컴퓨터에서 Numba 버전은 데코레이터가없는 파이썬 버전보다 1000 배 이상 빠릅니다 (200×200 매트릭스 ‘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 개발자 중 한 명입니다.
답변
여기에 시작이 있습니다. 첫째, 실수에 대해 사과드립니다.
나는 두 가지 다른 접근 방식으로 실험했습니다. 나는 합계에 대한 한계에 약간 혼란 스러웠다. 아니라 상한이 이어야 하는가?
편집 : 아니오, 질문에 제공된 상한이 정확했습니다. 다른 답변이 동일한 코드를 사용하기 때문에 여기에 그대로 두었지만 해결 방법은 간단합니다.
먼저 반복 버전 :
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 배 빠릅니다 .
그런 다음 (더 읽기 쉬운) 반복 코드의 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 코드와 비슷한 것으로 보였습니다.
답변
당신이 원하는 것은 컨볼 루션 인 것 같습니다. 그것을 달성하는 가장 빠른 방법은 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])