Devolva com eficiência o índice do primeiro valor que satisfaça a condição na matriz

Preciso encontrar o índice do primeiro valor em uma matriz NumPy 1d ou série numérica do Pandas, satisfazendo uma condição. A matriz é grande e o índice pode estar próximo do inícioo final da matriz,o a condição pode não ser atendida. Não sei dizer com antecedência o que é mais provável. Se a condição não for atendida, o valor de retorno deve ser-1. Eu considerei algumas abordagens.

Attempt 1
# func(arr) returns a Boolean array
idx = next(iter(np.where(func(arr))[0]), -1)

Mas isso geralmente é muito lento comofunc(arr) aplica uma função vetorizada nointeir array em vez de parar quando a condição for atendida. Especificamente, é caro quando a condição é atendida perto docomeça da matriz.

Attempt 2

np.argmax é marginalmente mais rápido, mas falha ao identificar quando uma condição éNunc conheceu

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) retorna0, ou seja, uma instância em que a condição énã satisfeito.

Attempt 3
# func(arr) returns a Boolean scalar
idx = next((idx for idx, val in enumerate(arr) if func(arr)), -1)

Mas isso é muito lento quando a condição é atendida perto dofi da matriz. Presumivelmente, isso ocorre porque a expressão do gerador possui uma sobrecarga cara de um grande número de__next__ chamadas.

É istosempr um compromisso ou existe uma maneira, para @ genéricfunc, para extrair o primeiro índice com eficiênci

Avaliação comparativ

Para comparações, assumafunc localiza o índice quando um valor é maior que uma determinada constante:

# 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

questionAnswers(1)

yourAnswerToTheQuestion