카테고리 보관물: scicomp

scicomp

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

파이썬에서

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

엑스나는=∑제이=1나는−1케이나는−제이,제이ㅏ나는−제이ㅏ제이,

엑스

와이

케이

엔×엔

이상적으로는 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 개발자 중 한 명입니다.


답변

여기에 시작이 있습니다. 첫째, 실수에 대해 사과드립니다.

나는 두 가지 다른 접근 방식으로 실험했습니다. 나는 합계에 대한 한계에 약간 혼란 스러웠다. 아니라 상한이 이어야 하는가?

나는

나는−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 코드와 비슷한 것으로 보였습니다.


답변

당신이 원하는 것은 컨볼 루션 인 것 같습니다. 그것을 달성하는 가장 빠른 방법은 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])

답변