numpy를 사용하는 배열의 효율적인 임계 값 필터


81

특정 임계 값보다 낮은 요소를 제거하려면 배열을 필터링해야합니다. 내 현재 코드는 다음과 같습니다.

threshold = 5
a = numpy.array(range(10)) # testing data
b = numpy.array(filter(lambda x: x >= threshold, a))

문제는 람다 함수가있는 필터를 사용하여 임시 목록을 생성한다는 것입니다 (느림).

이것은 매우 간단한 작업이므로 효율적인 방식으로 수행하는 numpy 함수가있을 수 있지만 찾을 수 없었습니다.

이를 달성하는 또 다른 방법은 배열을 정렬하고 임계 값의 인덱스를 찾고 해당 인덱스에서 슬라이스를 반환하는 것이 될 수 있다고 생각했습니다.하지만 이것이 작은 입력에 대해 더 빠르더라도 ), 입력 크기가 증가함에 따라 점근 적으로 덜 효율적입니다.

어떤 아이디어? 감사!

업데이트 : 나도 몇 가지 측정을 수행했으며 입력이 100.000.000 항목 일 때 정렬 + 슬라이싱이 순수한 파이썬 필터보다 두 배 빠릅니다.

In [321]: r = numpy.random.uniform(0, 1, 100000000)

In [322]: %timeit test1(r) # filter
1 loops, best of 3: 21.3 s per loop

In [323]: %timeit test2(r) # sort and slice
1 loops, best of 3: 11.1 s per loop

In [324]: %timeit test3(r) # boolean indexing
1 loops, best of 3: 1.26 s per loop

2
예, 아주 좋습니다. :-) 코드를 실행하는 데 시간이 거의 걸리지 않으면 측정을 평균화하기 위해 수행해야하는 반복 횟수를 자동으로 계산하기도합니다
fortran

5
@yosukesabai-IPython %timeit은 내장 timeit모듈을 사용합니다 . 이것도보세요. docs.python.org/library/timeit.html
Joe Kington

답변:


112

b = a[a>threshold] 이것은해야한다

다음과 같이 테스트했습니다.

import numpy as np, datetime
# array of zeros and ones interleaved
lrg = np.arange(2).reshape((2,-1)).repeat(1000000,-1).flatten()

t0 = datetime.datetime.now()
flt = lrg[lrg==0]
print datetime.datetime.now() - t0

t0 = datetime.datetime.now()
flt = np.array(filter(lambda x:x==0, lrg))
print datetime.datetime.now() - t0

나는 얻었다

$ python test.py
0:00:00.028000
0:00:02.461000

http://docs.scipy.org/doc/numpy/user/basics.indexing.html#boolean-or-mask-index-arrays


1
내가 생각하는 것뿐만 아니라 테스트 결과를 추가했습니다. : p
yosukesabai 2011

3
이러한 종류의 인덱싱은 배열의 크기를 유지하지 않습니다. 동일한 수의 요소를 유지하고 하위 임계 값을 0으로 만드는 것이 어떻게 가능합니까?
linello 2013

9
@linello하는 [A <= 임계] = 0이 임계 값을 초과하지 않는 부분을 마스크 아웃하려고
yosukesabai

4
두 가지 기준에 따라 필터링 문제에 부딪 혔습니다. 해결책은 다음과 같습니다. stackoverflow.com/a/3248599/1373468
Robin Newhouse 2014 년

@yosukesabai 실제로 원래 값을 변경하지 않고 정확하게 이것을 할 수 있습니까? np.ma그렇게 할 의도가 있다면 방법을 알 수 없습니다.
embert 2014-01-24
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.