기존 값보다 큰 값의 첫 번째 발생 횟수
1D 배열을 numpy로 하고 있는데 값이 numpy 배열의 값을 초과하는 인덱스의 위치를 찾고 싶습니다.
예.
aa = range(-10,10)
aa
서, 값 「」, 「」5
과됩니니다다
이게 좀 빨라요(더 좋아 보여요)
np.argmax(aa>5)
처음부터 멈출 것이기 때문이다.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
어레이의 소트된 콘텐츠를 고려하면 검색 정렬이라는 보다 빠른 방법이 있습니다.
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
저도 이 문제에 관심이 있어서 제안된 모든 답변을 성능도와 비교했습니다. (해임자:저는 perfplot의 저자입니다.)
참조하고 있는 어레이가 이미 정렬되어 있는 경우는,
numpy.searchsorted(a, alpha)
널 위한 거야O(log(n) 연산입니다.즉, 속도는 어레이의 크기에 거의 의존하지 않습니다.그보다 더 빨리 갈 순 없어
어레이에 대해 아무것도 모르더라도 이 어레이에 대해 잘못 알고 있는 것은 아닙니다.
numpy.argmax(a > alpha)
이미 정렬됨:
정렬되지 않음:
플롯을 재현하는 코드:
import numpy
import perfplot
alpha = 0.5
numpy.random.seed(0)
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)
perfplot.save(
"out.png",
# 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, 23)],
xlabel="len(array)",
)
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
요소 간에 일정한 단계가 있는 배열
의 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
searchsorted, argmax 및 numba는 단순히 잘못된 값을 반환합니다.하지만searchsorted
그리고.numba
배열에 유효한 인덱스가 아닌 인덱스를 반환합니다.
기능where
,min
,nonzero
그리고.calculate
예외를 두다단, 에 대한 예외입니다.calculate
도움이 되는 말은 뭐든 할 수 있어요
즉, 이러한 콜을 적절한 래퍼 함수로 랩핑하여 예외 또는 비활성 반환값을 검출하고 적어도 값이 어레이 내에 있는지 여부를 확신할 수 없는 경우 적절하게 처리해야 합니다.
주의: 계산과searchsorted
옵션은 특수한 조건에서만 작동합니다."계산" 함수를 사용하려면 일정한 단계가 필요하며 검색 정렬을 위해서는 배열이 정렬되어야 합니다.따라서 이러한 방법은 적절한 상황에서 유용할 수 있지만 이 문제에 대한 일반적인 해결책은 아닙니다.정렬된 Python 목록을 다루는 경우 Numpys 검색 정렬을 사용하는 대신 이등분 모듈을 살펴보는 것이 좋습니다.
제안하고 싶습니다.
np.min(np.append(np.where(aa>5)[0],np.inf))
그러면 조건이 충족되는 가장 작은 인덱스가 반환되고 조건이 충족되지 않으면 무한대가 반환됩니다.where
빈 배열을 반환합니다).
같이 가고 싶다
i = np.min(np.where(V >= x))
어디에V
is 벡터(1d 배열),x
가치 및i
는 결과 인덱스입니다.
대신 을 사용해야 합니다.후자는 값을 찾을 수 없는 경우에도 위치 0을 반환합니다.이것은 예상한 인덱스가 아닙니다.
>>> aa = np.array(range(-10,10))
>>> print(aa)
array([-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9])
조건이 충족되면 인덱스 배열을 반환합니다.
>>> idx = np.where(aa > 5)[0]
>>> print(idx)
array([16, 17, 18, 19], dtype=int64)
그렇지 않으면 빈 배열을 반환합니다.
>>> not_found = len(np.where(aa > 20)[0])
>>> print(not_found)
array([], dtype=int64)
에에에 argmax
이 경우: 솔루션이 모호하지 않다면 단순할수록 좋습니다.그래서 이 상태에 빠졌는지를 확인하기 위해서if len(np.where(aa > value_to_search)[0]) > 0
.
언급URL : https://stackoverflow.com/questions/16243955/numpy-first-occurrence-of-value-greater-than-existing-value
'source' 카테고리의 다른 글
jQuery에서 체크박스가 켜져 있는지 확인합니다. (0) | 2022.09.13 |
---|---|
vibed 앱에서 MySQL/MariaDB 데이터베이스에 연결할 수 없음 (0) | 2022.09.13 |
로컬에 설치된 Python 모듈 목록을 가져오려면 어떻게 해야 합니까? (0) | 2022.09.12 |
mysql_module_array()/module_module_assoc()/module_module_num_rows 등...파라미터 1이 리소스가 될 것으로 예상합니다. (0) | 2022.09.12 |
휴지 상태에서는 MultipleBagFetchException이 느려짐 - 여러 개의 가방을 동시에 가져올 수 없음 (0) | 2022.09.12 |