Wydajny filtr progowy tablicy z numpy

81

Muszę przefiltrować tablicę, aby usunąć elementy, które są poniżej określonego progu. Mój obecny kod wygląda tak:

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

Problem polega na tym, że tworzy to tymczasową listę, używając filtru z funkcją lambda (wolno).

Ponieważ jest to dość prosta operacja, być może jest jakaś funkcja numpy, która robi to w efektywny sposób, ale nie mogłem jej znaleźć.

Pomyślałem, że innym sposobem na osiągnięcie tego może być sortowanie tablicy, znalezienie indeksu progu i zwrócenie wycinka od tego indeksu w górę, ale nawet jeśli byłoby to szybsze dla małych danych wejściowych (i tak i tak nie będzie zauważalne ), jest definitywnie asymptotycznie mniej efektywny wraz ze wzrostem wielkości wkładu.

Jakieś pomysły? Dzięki!

Aktualizacja : Zrobiłem też kilka pomiarów, a sortowanie + krojenie było nadal dwa razy szybsze niż czysty filtr Pythona, gdy wprowadzono 100 000 000 wpisów.

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
fortran
źródło
2
tak, jest całkiem fajny :-) nawet automatycznie oblicza, ile iteracji powinien wykonać, aby uśrednić pomiary, jeśli wykonanie kodu zajmuje bardzo mało czasu
fortran
5
@yosukesabai - IPython %timeitużywa wbudowanego timeitmodułu. Spójrz też na to. docs.python.org/library/timeit.html
Joe Kington

Odpowiedzi:

112

b = a[a>threshold] to powinno wystarczyć

Testowałem następująco:

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

mam

$ 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

yosukesabai
źródło
1
dodany wynik testu, a nie tylko to, co moim zdaniem powinno zrobić. : p
yosukesabai
3
Ten rodzaj indeksowania nie zachowuje rozmiaru tablicy, jak można zachować tę samą liczbę elementów i wyzerować wartości podprogowe?
linello
9
@linello, a [a <= threshold] = 0
zamaskuje
4
Natknąłem się na kwestię filtrowania na podstawie dwóch kryteriów. Oto rozwiązanie: stackoverflow.com/a/3248599/1373468
Robin Newhouse,
@yosukesabai Czy można to zrobić dokładnie, bez faktycznej zmiany oryginalnych wartości. Jeśli np.mamam to zrobić, nie wiem, jak to zrobić.
embert