Ефективний пороговий фільтр масиву з numpy


81

Мені потрібно відфільтрувати масив, щоб видалити елементи, які нижчі за певний поріг. Мій поточний код такий:

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

Проблема в тому, що це створює тимчасовий список, використовуючи фільтр з лямбда-функцією (повільний).

Оскільки це досить проста операція, можливо, існує функція numpy, яка робить це ефективно, але мені не вдалося її знайти.

Я думав, що іншим способом досягнення цього може бути сортування масиву, пошук індексу порогу та повернення фрагмента з цього індексу далі, але навіть якщо це буде швидше для невеликих входів (і це все одно не буде помітно ), його остаточно асимптотично менш ефективним із збільшенням розміру вхідних даних.

Будь-які ідеї? Дякую!

Оновлення : Я також зробив кілька вимірювань, і сортування + нарізання все ще було вдвічі швидшим, ніж чистий фільтр python, коли вхідні дані складали 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
Джо Кінгтон,

Відповіді:


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

3
Цей вид індексації не підтримує розмір масиву, як можна зберегти однакову кількість елементів та обнулення підпорогових значень?
linello

9
@linello, [a <= = порог] = 0 збирається замаскувати частину, яка не перевищує порогову величину
yosukesabai

4
Я зайнявся питанням фільтрації на основі двох критеріїв. Ось рішення: stackoverflow.com/a/3248599/1373468
Робін Ньюхаус

@yosukesabai Чи можна зробити саме це, фактично не змінюючи початкові значення. Якщо np.maце призначено для цього, я не можу зрозуміти, як.
embert
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.