Сравнительный анализ производительности

ужно найти индекс первого значения в массиве 1d NumPy или числовом ряду Панд, удовлетворяющих условию. Массив большой, и индекс может быть ближе к началуили же конец массива,или же условие не может быть выполнено вообще. Я не могу сказать заранее, что более вероятно. Если условие не выполняется, возвращаемое значение должно быть-1, Я рассмотрел несколько подходов.

Попытка 1
# func(arr) returns a Boolean array
idx = next(iter(np.where(func(arr))[0]), -1)

Но это часто слишком медленноfunc(arr) применяет векторизованную функцию квсе массив, а не остановка при выполнении условия. В частности, это дорого, когда условие выполняется вблизиНачало массива.

Попытка 2

np.argmax немного быстрее, но не может определить, когда условиеникогда встретил:

np.random.seed(0)
arr = np.random.rand(10**7)

assert next(iter(np.where(arr > 0.999999)[0]), -1) == np.argmax(arr > 0.999999)

%timeit next(iter(np.where(arr > 0.999999)[0]), -1)  # 21.2 ms
%timeit np.argmax(arr > 0.999999)                    # 17.7 ms

np.argmax(arr > 1.0) возвращается0то есть случай, когда условиене довольный.

Попытка 3
# func(arr) returns a Boolean scalar
idx = next((idx for idx, val in enumerate(arr) if func(arr)), -1)

Но это слишком медленно, когда условие выполняется вблизиконец массива. Предположительно, это потому, что выражение генератора имеет дорогостоящие издержки из-за большого__next__ звонки.

Этовсегда компромисс или есть способ, для общегоfuncэффективно извлечь первый индекс?

Бенчмаркинг

Для сравнения предположимfunc находит индекс, когда значение больше заданной константы:

# Python 3.6.5, NumPy 1.14.3, Numba 0.38.0
import numpy as np

np.random.seed(0)
arr = np.random.rand(10**7)
m = 0.9
n = 0.999999

# Start of array benchmark
%timeit next(iter(np.where(arr > m)[0]), -1)                       # 43.5 ms
%timeit next((idx for idx, val in enumerate(arr) if val > m), -1)  # 2.5 µs

# End of array benchmark
%timeit next(iter(np.where(arr > n)[0]), -1)                       # 21.4 ms
%timeit next((idx for idx, val in enumerate(arr) if val > n), -1)  # 39.2 ms

Ответы на вопрос(1)

Ваш ответ на вопрос