IT

기존 값보다 큰 값이 처음으로 나타남

lottoking 2020. 7. 14. 07:54
반응형

기존 값보다 큰 값이 처음으로 나타남


numpy에 1D 배열이 있고 값이 numpy 배열의 값을 초과하는 배치의 위치를 ​​찾고 싶습니다.

예 :

aa = range(-10,10)

aa5이 초과 되는 위치를 찾으십시오 .


이것은 조금 더 빠르며 더 멋지게 보입니다.

np.argmax(aa>5)

argmax보기 처음보기 부터 멈추 므로 True( "최대 값이 여러 번 발생하는 경우 첫 번째 발생에 해당하는 인덱스가 반환됩니다 .") 다른 목록을 저장하지 않습니다.

In [2]: N = 10000

In [3]: aa = np.arange(-N,N)

In [4]: timeit np.argmax(aa>N/2)
100000 loops, best of 3: 52.3 us per loop

In [5]: timeit np.where(aa>N/2)[0][0]
10000 loops, best of 3: 141 us per loop

In [6]: timeit np.nonzero(aa>N/2)[0][0]
10000 loops, best of 3: 142 us per loop

배열의 정렬 된 내용이 주어지면 더 빠른 방법이 있습니다 : searchsorted .

import time
N = 10000
aa = np.arange(-N,N)
%timeit np.searchsorted(aa, N/2)+1
%timeit np.argmax(aa>N/2)
%timeit np.where(aa>N/2)[0][0]
%timeit np.nonzero(aa>N/2)[0][0]

# Output
100000 loops, best of 3: 5.97 µs per loop
10000 loops, best of 3: 46.3 µs per loop
10000 loops, best of 3: 154 µs per loop
10000 loops, best of 3: 154 µs per loop

In [34]: a=np.arange(-10,10)

In [35]: a
Out[35]:
array([-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2,
         3,   4,   5,   6,   7,   8,   9])

In [36]: np.where(a>5)
Out[36]: (array([16, 17, 18, 19]),)

In [37]: np.where(a>5)[0][0]
Out[37]: 16

나는 이것에 관심이있는 제안 된 모든 답변을 perfplot비교했습니다 . (면책 조항 : 저는 perfplot의 저자입니다.)

은 당신을 당신을 통해 찾고있는 배열되는 것을 알고 난 웬지- 이미 정렬 한 다음

numpy.searchsorted(a, alpha)

당신을위한 것입니다. 시간 작동입니다. 즉, 속도는 어레이의 크기에 의존 하지 않습니다 . 당신은 그것보다 빨리 얻을 수 없습니다.

배열에 대해 아무것도 모르면 문제가 없습니다.

numpy.argmax(a > alpha)

이미 정렬 :

여기에 이미지 설명을 입력하십시오

분류되지 않은 :

여기에 이미지 설명을 입력하십시오

줄거리를 재현하는 코드 :

import numpy
import perfplot


alpha = 0.5

def argmax(data):
    return numpy.argmax(data > alpha)

def where(data):
    return numpy.where(data > alpha)[0][0]

def nonzero(data):
    return numpy.nonzero(data > alpha)[0][0]

def searchsorted(data):
    return numpy.searchsorted(data, alpha)

out = perfplot.show(
    # setup=numpy.random.rand,
    setup=lambda n: numpy.sort(numpy.random.rand(n)),
    kernels=[
        argmax, where,
        nonzero,
        searchsorted
        ],
    n_range=[2**k for k in range(2, 20)],
    logx=True,
    logy=True,
    xlabel='len(array)'
    )

요소 사이에 단계가있는 배열

(A)의 경우 range나 다른 선형 적으로 증가 배열 당신은 모두의 배열을 통해 실제로 반복, 프로그래밍 필요를 선택할 수 있습니다.

def first_index_calculate_range_like(val, arr):
    if len(arr) == 0:
        raise ValueError('no value greater than {}'.format(val))
    elif len(arr) == 1:
        if arr[0] > val:
            return 0
        else:
            raise ValueError('no value greater than {}'.format(val))

    first_value = arr[0]
    step = arr[1] - first_value
    # For linearly decreasing arrays or constant arrays we only need to check
    # the first element, because if that does not satisfy the condition
    # no other element will.
    if step <= 0:
        if first_value > val:
            return 0
        else:
            raise ValueError('no value greater than {}'.format(val))

    calculated_position = (val - first_value) / step

    if calculated_position < 0:
        return 0
    elif calculated_position > len(arr) - 1:
        raise ValueError('no value greater than {}'.format(val))

    return int(calculated_position) + 1

아마 조금 향상시킬 수 있습니다. 몇 가지 배열과 값을 사용하는 것이 아니라는 것을 의미합니다. 특히 플로트를 사용하는 생각하면 ...

>>> import numpy as np
>>> first_index_calculate_range_like(5, np.arange(-10, 10))
16
>>> np.arange(-10, 10)[16]  # double check
6

>>> first_index_calculate_range_like(4.8, np.arange(-10, 10))
15

반복없이 위치를 계산할 수있는 가정하면 항상 시간 ( O(1))이 될 수도 있고 계산할 수 있습니다. 그러나 배열에서 단계가 필요합니다. 무효화 된 결과가 생성됩니다.

Numba를 사용하는 일반적인 솔루션

보다 일반적인 접근 방식은 numba 함수를 사용하는 것입니다.

@nb.njit
def first_index_numba(val, arr):
    for idx in range(len(arr)):
        if arr[idx] > val:
            return idx
    return -1

그것은 모든 배열에서 작동하지만 배열을 반복해야하는 경우에는 다음과 같다 O(n).

>>> first_index_numba(4.8, np.arange(-10, 10))
15
>>> first_index_numba(5, np.arange(-10, 10))
16

기준

Nico Schlömer는 이미 몇 가지 벤치 마크를 제공했지만 새로운 솔루션을 포함하고 다른 "값"솔루션을 테스트하는 것이 유용 할 것이라고 생각했습니다.

테스트 설정 :

import numpy as np
import math
import numba as nb

def first_index_using_argmax(val, arr):
    return np.argmax(arr > val)

def first_index_using_where(val, arr):
    return np.where(arr > val)[0][0]

def first_index_using_nonzero(val, arr):
    return np.nonzero(arr > val)[0][0]

def first_index_using_searchsorted(val, arr):
    return np.searchsorted(arr, val) + 1

def first_index_using_min(val, arr):
    return np.min(np.where(arr > val))

def first_index_calculate_range_like(val, arr):
    if len(arr) == 0:
        raise ValueError('empty array')
    elif len(arr) == 1:
        if arr[0] > val:
            return 0
        else:
            raise ValueError('no value greater than {}'.format(val))

    first_value = arr[0]
    step = arr[1] - first_value
    if step <= 0:
        if first_value > val:
            return 0
        else:
            raise ValueError('no value greater than {}'.format(val))

    calculated_position = (val - first_value) / step

    if calculated_position < 0:
        return 0
    elif calculated_position > len(arr) - 1:
        raise ValueError('no value greater than {}'.format(val))

    return int(calculated_position) + 1

@nb.njit
def first_index_numba(val, arr):
    for idx in range(len(arr)):
        if arr[idx] > val:
            return idx
    return -1

funcs = [
    first_index_using_argmax, 
    first_index_using_min, 
    first_index_using_nonzero,
    first_index_calculate_range_like, 
    first_index_numba, 
    first_index_using_searchsorted, 
    first_index_using_where
]

from simple_benchmark import benchmark, MultiArgument

그리고 다음을 사용하여 생성합니다.

%matplotlib notebook
b.plot()

항목이 시작됩니다.

b = benchmark(
    funcs,
    {2**i: MultiArgument([0, np.arange(2**i)]) for i in range(2, 20)},
    argument_name="array size")

여기에 이미지 설명을 입력하십시오

numba 기능은 가장 잘 수행 된 다음 계산 기능과 검색된 기능을 수행합니다. 다른 솔루션은 훨씬 나빠가 처리합니다.

항목이 끝났습니다

b = benchmark(
    funcs,
    {2**i: MultiArgument([2**i-2, np.arange(2**i)]) for i in range(2, 20)},
    argument_name="array size")

여기에 이미지 설명을 입력하십시오

작은 배열의 경우 numba 함수가 놀랍도록 빠른 수행 수행 더 큰 배열의 경우 계산 함수 및 검색 정렬 함수보다 성능이 뛰어납니다.

항목이 sqrt (len)에 있습니다.

b = benchmark(
    funcs,
    {2**i: MultiArgument([np.sqrt(2**i), np.arange(2**i)]) for i in range(2, 20)},
    argument_name="array size")

여기에 이미지 설명을 입력하십시오

이 더 흥미 롭습니다. 다시 numba와 계산 기능이 훌륭하게 작동하지 않는 경우 작동하지 않는 작동이 트리거됩니다.

조건에 맞는 값이 없을 때의 기능 비교

또 다른 흥미로운 점은 업그레이드를 반환해야하는 값이없는 경우 함수의 작동 방식입니다.

arr = np.ones(100)
value = 2

for func in funcs:
    print(func.__name__)
    try:
        print('-->', func(value, arr))
    except Exception as e:
        print('-->', e)

이 결과로 :

first_index_using_argmax
--> 0
first_index_using_min
--> zero-size array to reduction operation minimum which has no identity
first_index_using_nonzero
--> index 0 is out of bounds for axis 0 with size 0
first_index_calculate_range_like
--> no value greater than 2
first_index_numba
--> -1
first_index_using_searchsorted
--> 101
first_index_using_where
--> index 0 is out of bounds for axis 0 with size 0

검색 정렬 됨, argmax 및 numba는 잘못된 값을 반환합니다. 그러나 searchsortednumba배열에, 대한 올바른 인덱스가 아닌 인덱스를 돌려줍니다.

기능은 where, min, nonzerocalculate예외를합니다 던져. 그러나 calculate실제로 도움이되는 [해석] 예외입니다 .

즉, 배열 값이 적절한 경우, 오류가있는 배열 값이 있고 호출을 처리하는 배열 값이 있습니다.


참고 : 계산 및 searchsorted옵션은 특수 조건에서만 작동합니다. "계산"기능은 단계를 필요로하고 검색 정렬이 정렬 될 배열을 요구합니다. 이는 적절한 상황 따라서에서 유용 할 수 있지만 이 문제에, 대한 일반적인 해결책 은 아닙니다 . 정렬 된 Python 목록을 다루는 경우 Numpys searchsorted를 사용하는 대신 bisect 모듈을 살펴볼 수 있습니다.


나는 제안하고 싶다

np.min(np.append(np.where(aa>5)[0],np.inf))

이는 조건이 결과를 반환하고, 조건이 결과를 반환합니다 (그리고 where빈 배열을 반환).


나는 함께 갈 것이다

i = np.min(np.where(V >= x))

여기서는 V(1D 배열) 벡터이고, x는 값이고 i결과 인덱스입니다.

참고 URL : https://stackoverflow.com/questions/16243955/numpy-first-occurrence-of-value-greater- 기존 값보다

반응형