Numpy : 빠른 가치의 첫 번째 눈길 찾기
Numpy 배열에서 숫자가 처음으로 사용할 수있는 어떻게 사용할 수 있습니까? 나에게는 속도가 중요합니다. 나는 전체 배열을 스캔하고 첫 번째 발생하지 않습니다.
itemindex = numpy.where(array==item)[0][0]
nonzero(array == item)[0][0]
참고 1 : 해당 질문의 답변 중 어느 것도 관련 이없는 것 있습니다. 배열에서 서술의 첫 번째 보안을 반환하는 Numpy 함수가?
참고 2 : 사용하는 것이 Python 루프보다 선호됩니다.
Numpy 2.0.0에 대해 예정된 기능 요청이 있습니다 : https://github.com/numpy/numpy/issues/2269
너무 늦었지만 나중에 참조 할 수 있습니다. numba ( 1 )를 사용 하는 것이 numpy가 구현할 때까지 가장 쉬운 방법입니다. 아나콘다 설치되어 배포판을 사용한다면 이미 설치되어있을 것입니다. 코드가 단어 생략
@jit(nopython=True)
def find_first(item, vec):
"""return the index of the first occurence of item in vec"""
for i in xrange(len(vec)):
if item == vec[i]:
return i
return -1
그리고 :
>>> a = array([1,7,8,32])
>>> find_first(8,a)
2
몇 가지 방법에 대한 벤치 마크를 만들었습니다.
argwhere
nonzero
질문에서와 같이.tostring()
@Rob Reilink의 답변에서와 같이- 다른 루프
- Fortran 루프
추가 및 포트란 코드를 사용할 수 있습니다. 나는 목록으로 변환하는 것과 같이 유망하지 않은 것을 건너 뛰었습니다.
로그의 결과. X 축은 바늘의 위치입니다 (배열 아래에 있는지 찾는 데 시간이 더 오래 있습니다). 마지막 값은 배열에없는 바늘입니다. Y 축은 그것을 사용 시간입니다.
어레이에는 1 백만 개의 요소가 있고 100 번 실행되었습니다. 결과는 여전히 약간의 변동이 있다고 정성적인 추세는 분명합니다. Python과 f2py는 첫 번째 요소에서 종료되어 다른 방식으로 확장됩니다. 사용하는 것이 처음 1 %에 있지 않습니다 f2py
.
요약하면, f2py는 특히 바늘이 조기에 가장 빠른 솔루션 입니다.
성가신 내장은 실제로 2 분만에 작업 할 수 있습니다. 추가 이 라는 파일 search.f90
:
subroutine find_first(needle, haystack, haystack_length, index)
implicit none
integer, intent(in) :: needle
integer, intent(in) :: haystack_length
integer, intent(in), dimension(haystack_length) :: haystack
!f2py intent(inplace) haystack
integer, intent(out) :: index
integer :: k
index = -1
do k = 1, haystack_length
if (haystack(k)==needle) then
index = k - 1
exit
endif
enddo
end
이외의 것을 소유하고있는 것을 integer
변경하십시오. 그런 다음 다음을 사용하여 준비하십시오.
f2py -c -m search search.f90
그 후에 할 수 있습니다 (Python에서) :
import search
print(search.find_first.__doc__)
a = search.find_first(your_int_needle, your_int_array)
array.tostring()
다음과 같이 find () 메서드를 사용 하여 부울 배열을 Python 문자열로 변환 할 수 있습니다 .
(array==item).tostring().find('\x01')
하지만 파이썬 문자열은 변경 불가능해야하므로 데이터 복사가 포함됩니다. 장점은 예를 들어 상승 에지를 찾아서 검색 할 수도 있다는 것입니다.\x00\x01
정렬 된 배열의 경우 np.searchsorted
작동합니다.
다른 방법과 배열에 대한 사전 지식이 실제로 도움 이되는 문제에 부딪혔다 고 생각합니다 . 데이터의 첫 Y %에서 답을 찾을 확률이 X 인 경우입니다. 운이 좋을 것이라는 희망으로 문제를 나누고 중첩 된 목록 이해 또는 무언가로 파이썬에서 이것을 수행합니다.
이 무차별 대입을 수행하기 위해 C 함수를 작성하는 것도 ctypes 를 사용하여 그리 어렵지 않습니다 .
내가 함께 해킹 한 C 코드 (index.c) :
long index(long val, long *data, long length){
long ans, i;
for(i=0;i<length;i++){
if (data[i] == val)
return(i);
}
return(-999);
}
그리고 파이썬 :
# to compile (mac)
# gcc -shared index.c -o index.dylib
import ctypes
lib = ctypes.CDLL('index.dylib')
lib.index.restype = ctypes.c_long
lib.index.argtypes = (ctypes.c_long, ctypes.POINTER(ctypes.c_long), ctypes.c_long)
import numpy as np
np.random.seed(8675309)
a = np.random.random_integers(0, 100, 10000)
print lib.index(57, a.ctypes.data_as(ctypes.POINTER(ctypes.c_long)), len(a))
92를 얻습니다.
파이썬을 적절한 기능으로 감싸면됩니다.
C 버전은이 시드에 대해 훨씬 빠릅니다 (~ 20 배).
import timeit
t = timeit.Timer('np.where(a==57)[0][0]', 'import numpy as np; np.random.seed(1); a = np.random.random_integers(0, 1000000, 10000000)')
t.timeit(100)/100
# 0.09761879920959472
t2 = timeit.Timer('lib.index(57, a.ctypes.data_as(ctypes.POINTER(ctypes.c_long)), len(a))', 'import numpy as np; np.random.seed(1); a = np.random.random_integers(0, 1000000, 10000000); import ctypes; lib = ctypes.CDLL("index.dylib"); lib.index.restype = ctypes.c_long; lib.index.argtypes = (ctypes.c_long, ctypes.POINTER(ctypes.c_long), ctypes.c_long) ')
t2.timeit(100)/100
# 0.005288000106811523
@tal은 이미 numba
첫 번째 인덱스를 찾는 함수를 제공 했지만 1D 배열에서만 작동합니다. 를 사용 np.ndenumerate
하면 임의 차원 배열에서 첫 번째 인덱스를 찾을 수도 있습니다.
from numba import njit
import numpy as np
@njit
def index(array, item):
for idx, val in np.ndenumerate(array):
if val == item:
return idx
return None
샘플 케이스 :
>>> arr = np.arange(9).reshape(3,3)
>>> index(arr, 3)
(1, 0)
타이밍은 성능이 tals 솔루션 과 유사 함을 보여줍니다 .
arr = np.arange(100000)
%timeit index(arr, 5) # 1000000 loops, best of 3: 1.88 µs per loop
%timeit find_first(5, arr) # 1000000 loops, best of 3: 1.7 µs per loop
%timeit index(arr, 99999) # 10000 loops, best of 3: 118 µs per loop
%timeit find_first(99999, arr) # 10000 loops, best of 3: 96 µs per loop
내가 아는 한 부울 배열의 np.any 및 np.all 만 단락됩니다.
귀하의 경우 numpy는 부울 조건을 생성하기 위해 한 번, 인덱스를 찾기 위해 두 번 전체 배열을 두 번 통과해야합니다.
이 경우 나의 권장 사항은 cython을 사용하는 것입니다. 특히 다른 dtype과 모양에 대해 많은 유연성이 필요하지 않은 경우이 경우에 대한 예제를 조정하는 것이 쉬워야한다고 생각합니다.
나는 이것이 내 직업에 필요했기 때문에 Python과 Numpy의 C 인터페이스를 스스로 가르치고 직접 작성했습니다. http://pastebin.com/GtcXuLyd 1D 배열에만 해당되지만 대부분의 데이터 유형 (int, float 또는 string)에서 작동하며 테스트 결과 순수한 Python에서 예상되는 접근 방식보다 약 20 배 더 빠릅니다. numpy.
목록이 정렬 된 경우 'bisect'패키지를 사용하여 색인을 매우 빠르게 검색 할 수 있습니다 . O (n) 대신 O (log (n))입니다.
bisect.bisect(a, x)
배열 a에서 x를 찾습니다. 정렬 된 경우 모든 첫 번째 요소를 통과하는 C 루틴보다 확실히 더 빠릅니다 (충분한 목록의 경우).
때때로 아는 것이 좋습니다.
오랜 matlab 사용자로서 나는 꽤 오랫동안이 문제에 대한 효율적인 솔루션을 찾고 있습니다. 마지막으로,이 스레드 의 제안에 대한 토론을 통해 여기 에 제안 된 것과 유사한 API를 구현하는 솔루션을 생각해 보았습니다 . 현재로서는 1D 배열 만 지원합니다.
당신은 이것을 이렇게 사용할 것입니다
import numpy as np
import utils_find_1st as utf1st
array = np.arange(100000)
item = 1000
ind = utf1st.find_1st(array, item, utf1st.cmp_larger_eq)
지원되는 조건 연산자는 cmp_equal, cmp_not_equal, cmp_larger, cmp_smaller, cmp_larger_eq, cmp_smaller_eq입니다. 효율성을 위해 확장은 c로 작성됩니다.
여기에서 소스, 벤치 마크 및 기타 세부 정보를 찾을 수 있습니다.
https://pypi.python.org/pypi?name=py_find_1st&:action=display
우리 팀에서 사용하기 위해 (리눅스 및 macOS의 아나콘다) 설치를 단순화하는 아나콘다 설치 프로그램을 만들었습니다. 여기에 설명 된대로 사용할 수 있습니다.
https://anaconda.org/roebel/py_find_1st
일련의 검색을 수행하는 경우 검색 차원이 충분히 크지 않으면 문자열로 변환하는 것과 같은 영리한 작업을 수행하여 얻을 수있는 성능 향상이 외부 루프에서 손실 될 수 있습니다. 위에서 제안한 문자열 변환 트릭을 사용하는 find1과 내부 축을 따라 argmax를 사용하는 find2를 반복하는 성능을 확인하십시오 (불일치가 -1로 반환되도록 조정).
import numpy,time
def find1(arr,value):
return (arr==value).tostring().find('\x01')
def find2(arr,value): #find value over inner most axis, and return array of indices to the match
b = arr==value
return b.argmax(axis=-1) - ~(b.any())
for size in [(1,100000000),(10000,10000),(1000000,100),(10000000,10)]:
print(size)
values = numpy.random.choice([0,0,0,0,0,0,0,1],size=size)
v = values>0
t=time.time()
numpy.apply_along_axis(find1,-1,v,1)
print('find1',time.time()-t)
t=time.time()
find2(v,1)
print('find2',time.time()-t)
출력
(1, 100000000)
('find1', 0.25300002098083496)
('find2', 0.2780001163482666)
(10000, 10000)
('find1', 0.46200013160705566)
('find2', 0.27300000190734863)
(1000000, 100)
('find1', 20.98099994659424)
('find2', 0.3040001392364502)
(10000000, 10)
('find1', 206.7590000629425)
('find2', 0.4830000400543213)
즉, C로 작성된 발견은 이러한 접근 방식 중 하나보다 조금 더 빠릅니다.
이것은 어떤가요
import numpy as np
np.amin(np.where(array==item))
배열을 숨기고 방법을 list
사용할 수 있습니다 index()
.
i = list(array).index(item)
내가 아는 한 이것은 C 방법입니다.
참고 URL : https://stackoverflow.com/questions/7632963/numpy-find-first-index-of-value-fast
'IT' 카테고리의 다른 글
Windows64가 x86-64의 다른 모든 OS와 다른 호출 규칙을 사용하는 이유는 무엇입니까? (0) | 2020.08.28 |
---|---|
Python에서 XML 스키마로 유효성 검사 (0) | 2020.08.28 |
YAML에서 파이프 기호를 사용하는 것은 무엇입니까? (0) | 2020.08.28 |
Pandoc 마크 다운 페이지 나누기 (0) | 2020.08.28 |
Django Rest Framework의 응답에 중개자 (모델을 통해) 포함 (0) | 2020.08.28 |