Effizienter Schwellenwertfilter eines Arrays mit Numpy

81

Ich muss ein Array filtern, um die Elemente zu entfernen, die unter einem bestimmten Schwellenwert liegen. Mein aktueller Code lautet wie folgt:

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

Das Problem ist, dass dadurch eine temporäre Liste erstellt wird, die einen Filter mit einer Lambda-Funktion (langsam) verwendet.

Da dies eine recht einfache Operation ist, gibt es möglicherweise eine Numpy-Funktion, die dies auf effiziente Weise ausführt, aber ich konnte sie nicht finden.

Ich habe gedacht, dass ein anderer Weg, dies zu erreichen, darin bestehen könnte, das Array zu sortieren, den Index des Schwellenwerts zu finden und ab diesem Index ein Slice zurückzugeben, aber selbst wenn dies für kleine Eingaben schneller wäre (und es sowieso nicht auffällt ), es ist definitiv asymptotisch weniger effizient, wenn die Eingabegröße zunimmt.

Irgendwelche Ideen? Vielen Dank!

Update : Ich habe auch einige Messungen vorgenommen und das Sortieren + Schneiden war immer noch doppelt so schnell wie der reine Python-Filter, als die Eingabe 100.000.000 Einträge betrug.

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
quelle
2
Ja, es ist ganz nett :-) Es berechnet sogar automatisch, wie viele Iterationen es durchführen soll, um die Messungen zu
mitteln,
5
@yosukesabai - IPython %timeitverwendet das integrierte timeitModul. Schauen Sie es sich auch an. docs.python.org/library/timeit.html
Joe Kington

Antworten:

111

b = a[a>threshold] das sollte reichen

Ich habe wie folgt getestet:

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

ich habe

$ 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
quelle
1
Testergebnis hinzugefügt, nicht nur das, was ich denke, dass es tun sollte. : p
yosukesabai
3
Diese Art der Indizierung behält nicht die Größe des Arrays bei. Wie ist es möglich, die gleiche Anzahl von Elementen beizubehalten und die Unterschwellenwerte auf Null zu setzen?
Linello
9
@linello, ein [a <= Schwelle] = 0 wird den Teil maskieren, der die Schwelle nicht überschreitet
yosukesabai
4
Ich bin auf das Problem der Filterung anhand von zwei Kriterien gestoßen. Hier ist die Lösung: stackoverflow.com/a/3248599/1373468
Robin Newhouse
@yosukesabai Ist es möglich, genau dies zu tun, ohne die ursprünglichen Werte tatsächlich zu ändern. Wenn das np.madazu gedacht ist, kann ich nicht herausfinden, wie.
Embert