복붙노트

[PYTHON] numpy 배열을 통해 함수를 매핑하는 가장 효율적인 방법

PYTHON

numpy 배열을 통해 함수를 매핑하는 가장 효율적인 방법

numpy 배열을 통해 함수를 매핑하는 가장 효율적인 방법은 무엇입니까? 현재 프로젝트에서 내가 해왔 던 방식은 다음과 같습니다.

import numpy as np 

x = np.array([1, 2, 3, 4, 5])

# Obtain array of square of each element in x
squarer = lambda t: t ** 2
squares = np.array([squarer(xi) for xi in x])

그러나 이것은 아마도 매우 비효율적 인 것처럼 보입니다. 왜냐하면 새로운 배열을 파이썬리스트로 생성하기 위해 목록 이해력을 사용하여 다시 numpy 배열로 변환하기 때문입니다.

더 잘할 수 있을까요?

해결법

  1. ==============================

    1.perfplot (내 작은 프로젝트)으로 np.array (map (f, x))와 제안 된 모든 메소드를 테스트했습니다.

    perfplot (내 작은 프로젝트)으로 np.array (map (f, x))와 제안 된 모든 메소드를 테스트했습니다.

    벡터화하려는 함수가 벡터화 된 경우 (예 : 원래 게시물의 x ** 2 예제),이를 사용하면 다른 어떤 것보다 훨씬 빠릅니다 (로그 스케일 참고).

    실제로 벡터화가 필요한 경우 어떤 변형을 사용 하느냐가 중요하지 않습니다.

    플롯을 재현하는 코드 :

    import numpy as np
    import perfplot
    import math
    
    
    def f(x):
        # return math.sqrt(x)
        return np.sqrt(x)
    
    
    vf = np.vectorize(f)
    
    
    def array_for(x):
        return np.array([f(xi) for xi in x])
    
    
    def array_map(x):
        return np.array(list(map(f, x)))
    
    
    def fromiter(x):
        return np.fromiter((f(xi) for xi in x), x.dtype)
    
    
    def vectorize(x):
        return np.vectorize(f)(x)
    
    
    def vectorize_without_init(x):
        return vf(x)
    
    
    perfplot.show(
        setup=lambda n: np.random.rand(n),
        n_range=[2**k for k in range(20)],
        kernels=[
            f,
            array_for, array_map, fromiter, vectorize, vectorize_without_init
            ],
        logx=True,
        logy=True,
        xlabel='len(x)',
        )
    
  2. ==============================

    2.numpy.vectorize를 사용하는 것은 어떻습니까?

    numpy.vectorize를 사용하는 것은 어떻습니까?

    >>> import numpy as np
    >>> x = np.array([1, 2, 3, 4, 5])
    >>> squarer = lambda t: t ** 2
    >>> vfunc = np.vectorize(squarer)
    >>> vfunc(x)
    array([ 1,  4,  9, 16, 25])
    

    http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.vectorize.html

  3. ==============================

    3.내 경험상, np.fromiter는 일반적으로 서로 다른 크기의 배열과 다른 컴파일러의 Python과 NumPy의 다른 버전에서 가장 빠릅니다. 다음은 간단한 예입니다.

    내 경험상, np.fromiter는 일반적으로 서로 다른 크기의 배열과 다른 컴파일러의 Python과 NumPy의 다른 버전에서 가장 빠릅니다. 다음은 간단한 예입니다.

    import numpy as np
    x = np.array([1, 2, 3, 4, 5])
    f = lambda x: x ** 2
    squares = np.fromiter((f(xi) for xi in x), x.dtype, count=len(x))
    

    count는 선택 사항입니다. 적어도 수백 개의 요소가있는 배열에 대해 np.vectorize를 사용하는 것이 좋습니다 (Nico의 답변에있는 플롯 참조).

    다음은 Python 2.7 및 NumPy 1.9를 사용하여 함수를 매핑하는 세 가지 방법을 비교하는 간단한 테스트입니다. 첫째, 테스트를위한 설정 기능 :

    import timeit
    import numpy as np
    
    f = lambda x: x ** 2
    vf = np.vectorize(f)
    
    def test_array(x, n):
        t = timeit.timeit(
            'np.array([f(xi) for xi in x])',
            'from __main__ import np, x, f', number=n)
        print('array: ' + str(t))
    
    def test_fromiter(x, n):
        t = timeit.timeit(
            'np.fromiter((f(xi) for xi in x), x.dtype, count=len(x))',
            'from __main__ import np, x, f', number=n)
        print('fromiter: ' + str(t))
    
    def test_vectorized(x, n):
        t = timeit.timeit(
            'vf(x)',
            'from __main__ import x, vf', number=n)
        print('vectorized: ' + str(t))
    

    다섯 가지 요소를 사용하면 np.fromiter가 가장 빠르며 np.vectorize는 설정 비용 때문에 훨씬 느립니다.

    x = np.array([1, 2, 3, 4, 5])
    n = 100000
    test_array(x, n)       # 0.616514921188
    test_fromiter(x, n)    # 0.585698843002
    test_vectorized(x, n)  # 2.6228120327
    

    요소가 100 개인 모든 메소드는 거의 동일합니다.

    x = np.arange(100)
    n = 10000
    test_array(x, n)       # 0.519502162933
    test_fromiter(x, n)    # 0.500586986542
    test_vectorized(x, n)  # 0.525988101959
    

    그러나 배열 요소가 1000 개 이상인 경우 벡터화 된 방식이 가장 효율적입니다.

    x = np.arange(1000)
    n = 1000
    test_array(x, n)       # 0.472352981567
    test_fromiter(x, n)    # 0.453316926956
    test_vectorized(x, n)  # 0.291934967041
    

    그러나 다른 버전의 Python / NumPy와 컴파일러 최적화는 다른 결과를 가지므로 사용자 환경에 대해 비슷한 테스트를 수행하십시오.

  4. ==============================

    4.

    squares = squarer(x)
    

    배열에 대한 산술 연산은 자동으로 요소 단위로 적용되며 효율적인 C 수준 루프는 Python 수준의 루프 나 이해에 적용되는 모든 인터프리터 오버 헤드를 피합니다.

    NumPy 배열에 elementwise를 적용하려는 대부분의 함수는 작동하지만 일부는 변경해야 할 수도 있습니다. 예를 들어, if 요소가 작동하지 않습니다. numpy와 같은 구문을 사용하도록 변환하려고합니다.

    def using_if(x):
        if x < 5:
            return x
        else:
            return x**2
    

    된다

    def using_where(x):
        return numpy.where(x < 5, x, x**2)
    
  5. ==============================

    5.나는 새로운 버전 (나는 1.13을 사용한다)을 numpy로 믿는다. numpy 배열을 넘겨서 스칼라 타입으로 작성한 함수를 호출하면 함수가 numpy 배열을 통해 자동으로 각 요소에 적용되어 반환된다. 또 다른 배열

    나는 새로운 버전 (나는 1.13을 사용한다)을 numpy로 믿는다. numpy 배열을 넘겨서 스칼라 타입으로 작성한 함수를 호출하면 함수가 numpy 배열을 통해 자동으로 각 요소에 적용되어 반환된다. 또 다른 배열

    >>> import numpy as np
    >>> squarer = lambda t: t ** 2
    >>> x = np.array([1, 2, 3, 4, 5])
    >>> squarer(x)
    array([ 1,  4,  9, 16, 25])
    
  6. ==============================

    6.이 게시물에서 언급했듯이 생성기 표현식을 다음과 같이 사용하십시오.

    이 게시물에서 언급했듯이 생성기 표현식을 다음과 같이 사용하십시오.

    numpy.fromiter((<some_func>(x) for x in <something>),<dtype>,<size of something>)
    
  7. ==============================

    7.어쩌면이 질문에 직접 대답하지 않을 수도 있지만 numba가 기존의 파이썬 코드를 병렬 기계 명령어로 컴파일 할 수 있다고 들었습니다. 나는 실제로 그것을 사용할 기회가있을 때이 게시물을 다시 읽고 개정 할 것입니다.

    어쩌면이 질문에 직접 대답하지 않을 수도 있지만 numba가 기존의 파이썬 코드를 병렬 기계 명령어로 컴파일 할 수 있다고 들었습니다. 나는 실제로 그것을 사용할 기회가있을 때이 게시물을 다시 읽고 개정 할 것입니다.

  8. ==============================

    8.아마 vectorize를 사용하는 것이 더 좋습니다.

    아마 vectorize를 사용하는 것이 더 좋습니다.

    def square(x):
       return x**2
    
    vfunc=vectorize(square)
    
    vfunc([1,2,3,4,5])
    
    output:array([ 1,  4,  9, 16, 25])
    
  9. from https://stackoverflow.com/questions/35215161/most-efficient-way-to-map-function-over-numpy-array by cc-by-sa and MIT license