Si está buscando la primera fila en la que existe un elemento en la primera columna, esto funciona (aunque arrojará un error de índice si no existe)rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
BrT
29
¿Qué sucede si desea que deje de buscar después de encontrar el primer valor? No creo que where () sea comparable a find ()
np.argwheresería un poco más útil aquí:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
Eric
3
Vale la pena señalar que esta respuesta supone que la matriz es 2D. wherefunciona en cualquier matriz, y devolverá una tupla de longitud 3 cuando se usa en una matriz 3D, etc.
P. Camilleri
70
Si necesita el índice de la primera aparición de un solo valor , puede usar nonzero(o where, lo que equivale a lo mismo en este caso):
>>> t = array([1,1,1,2,2,3,8,3,8,8])>>> nonzero(t ==8)(array([6,8,9]),)>>> nonzero(t ==8)[0][0]6
Si necesita el primer índice de cada uno de los muchos valores , obviamente podría hacer lo mismo que anteriormente varias veces, pero hay un truco que puede ser más rápido. A continuación se encuentran los índices del primer elemento de cada subsecuencia :
Observe que encuentra el comienzo de ambas subsecuencias de 3s y ambas subsecuencias de 8s:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
Por lo tanto, es ligeramente diferente a encontrar la primera aparición de cada valor. En su programa, puede trabajar con una versión ordenada tpara obtener lo que desea:
>>> st = sorted(t)>>> nonzero(r_[1, diff(st)[:-1]])(array([0,3,5,7]),)
@ Geoff, r_concatena; o, más precisamente, traduce objetos de corte a concatenación a lo largo de cada eje. Podría haber usado en su hstacklugar; eso puede haber sido menos confuso. Consulte la documentación para obtener más información sobre r_. También hay un c_.
Vebjorn Ljosa
+1, buena! (vs NP.where) su solución es mucho más simple (y probablemente más rápida) en el caso de que solo sea la primera aparición de un valor dado en una matriz 1D lo que necesitamos
doug
3
El último caso (encontrar el primer índice de todos los valores) está dado porvals, locs = np.unique(t, return_index=True)
askewchan
@askewchan su versión es funcionalmente equivalente, pero mucho, mucho, mucho más lenta
Jivan
50
También puede convertir una matriz NumPy para listar en el aire y obtener su índice. Por ejemplo,
l =[1,2,3,4,5]# Python list
a = numpy.array(l)# NumPy array
i = a.tolist().index(2)# i will return index of 2print i
Es posible que la biblioteca haya cambiado desde que esto se escribió por primera vez. Pero esta fue la primera solución que funcionó para mí.
amracel
1
Hice un buen uso de esto para encontrar múltiples valores en una lista usando una comprensión de la lista:[find_list.index(index_list[i]) for i in range(len(index_list))]
Matt Wenham
1
@MattWenham Si es lo suficientemente grande, puede convertirlo find_listen una matriz NumPy de object(o cualquier otra cosa más específica que sea apropiada) y simplemente hacer find_arr[index_list].
Narfanar
Totalmente fuera de tema, pero esta es la primera vez que veo la frase "en el aire", lo que más he visto, en su lugar, es probablemente "sobre la marcha".
flow2k
18
Solo para agregar un muy eficiente y práctico numbaalternativa basada en np.ndenumerateencontrar el primer índice:
from numba import njit
import numpy as np
@njitdef index(array, item):for idx, val in np.ndenumerate(array):if val == item:return idx
# If no item was found return None, other return types might be a problem due to# numbas type inference.
Esto es bastante rápido y trata naturalmente con matrices multidimensionales :
Esto puede ser mucho más rápido (porque está cortocircuitando la operación) que cualquier enfoque que use np.whereo np.nonzero.
Sin embargo np.argwhere, también podría tratar con gracia las matrices multidimensionales (necesitaría convertirlo manualmente en una tupla y no está en cortocircuito), pero fallaría si no se encuentra ninguna coincidencia:
@njites una abreviatura de, jit(nopython=True)es decir, la función se compilará completamente sobre la marcha en el momento de la primera ejecución para que las llamadas del intérprete de Python se eliminen por completo.
bartolo-otrit
14
Si va a usar esto como un índice en otra cosa, puede usar índices booleanos si las matrices son de escala amplia; No necesitas índices explícitos. La forma más simple de hacer esto es simplemente indexar en función de un valor de verdad.
other_array[first_array == item]
Cualquier operación booleana funciona:
a = numpy.arange(100)
other_array[first_array >50]
El método distinto de cero también toma booleanos:
index = numpy.nonzero(first_array == item)[0][0]
Los dos ceros son para la tupla de índices (suponiendo que first_array es 1D) y luego el primer elemento en la matriz de índices.
l.index(x)devuelve el i más pequeño de manera que i es el índice de la primera aparición de x en la lista.
Se puede suponer con seguridad que la index()función en Python se implementa para que se detenga después de encontrar la primera coincidencia, y esto da como resultado un rendimiento promedio óptimo.
Para encontrar un elemento que se detiene después de la primera coincidencia en una matriz NumPy, use un iterador ( ndenumerate ).
In[67]: l=range(100)In[68]: l.index(2)Out[68]:2
Matriz NumPy:
In[69]: a = np.arange(100)In[70]: next((idx for idx, val in np.ndenumerate(a)if val==2))Out[70]:(2L,)
Tenga en cuenta que ambos métodos index()y nextdevuelven un error si no se encuentra el elemento. Con next, se puede usar un segundo argumento para devolver un valor especial en caso de que no se encuentre el elemento, p. Ej.
In[77]: next((idx for idx, val in np.ndenumerate(a)if val==400),None)
Hay otras funciones en NumPy ( argmax, wherey nonzero) que puede ser utilizado para encontrar un elemento en una matriz, pero todos tienen el inconveniente de ir a través de todo el conjunto en busca de todas las ocurrencias, por tanto, no está optimizado para encontrar el primer elemento. Tenga en cuenta también eso wherey nonzerodevuelva las matrices, por lo que debe seleccionar el primer elemento para obtener el índice.
Simplemente comprobando que para matrices grandes la solución que usa un iterador es más rápida cuando el elemento buscado está al comienzo de la matriz (usando %timeiten el shell de IPython):
In[285]: a = np.arange(100000)In[286]:%timeit next((idx for idx, val in np.ndenumerate(a)if val==0))100000 loops, best of 3:17.6µs per loop
In[287]:%timeit np.argmax(a==0)1000 loops, best of 3:254µs per loop
In[288]:%timeit np.where(a==0)[0][0]1000 loops, best of 3:314µs per loop
Creo que también debe incluir un momento para el peor de los casos (último elemento) para que los lectores sepan qué les sucede en el peor de los casos cuando utilizan su enfoque.
MSeifert
@MSeifert No puedo obtener un momento razonable para la solución de iterador del peor de los casos: voy a eliminar esta respuesta hasta que descubra qué le
sucede
1
no %timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))funciona Si se pregunta por qué es 1000 veces más lento, es porque los bucles de Python sobre matrices numpy son notoriamente lentos.
MSeifert
@MSeifert no, no lo sabía, pero también estoy desconcertado por el hecho de que argmaxy whereen este caso son mucho más rápidos (elemento buscado al final de la matriz)
usuario2314737
Deben ser tan rápidos como si el elemento estuviera al principio. Siempre procesan toda la matriz, por lo que siempre toman el mismo tiempo (al menos deberían).
MSeifert
9
Para las matrices ordenadas unidimensionales , sería mucho más simple y eficiente O (log (n)) usar numpy.searchsorted que devuelve un entero NumPy (posición). Por ejemplo,
arr = np.array([1,1,1,2,3,3,4])
i = np.searchsorted(arr,3)
Solo asegúrate de que la matriz ya esté ordenada
También verifique si el índice devuelto realmente contiene el elemento buscado, ya que el objetivo principal de searchsorted es encontrar índices donde se deben insertar elementos para mantener el orden.
if arr[i]==3:print("present")else:print("not present")
searchsorted no es nlog (n) ya que no ordena la matriz antes de buscar, se supone que la matriz de argumentos ya está ordenada. consulte la documentación de numpy.searchsorted (enlace de arriba)
Alok Nayak
6
Para indexar cualquier criterio, puede hacer algo como lo siguiente:
In[1]:from numpy import*In[2]: x = arange(125).reshape((5,5,5))In[3]: y = indices(x.shape)In[4]: locs = y[:,x >=120]# put whatever you want in place of x >= 120In[5]: pts = hsplit(locs, len(locs[0]))In[6]:for pt in pts:.....:print(', '.join(str(p[0])for p in pt))4,4,04,4,14,4,24,4,34,4,4
Y aquí hay una función rápida para hacer lo que hace list.index (), excepto que no genera una excepción si no se encuentra. Cuidado, esto es probablemente muy lento en matrices grandes. Probablemente pueda mono parchear esto en matrices si prefiere usarlo como método.
def ndindex(ndarray, item):if len(ndarray.shape)==1:try:return[ndarray.tolist().index(item)]except:passelse:for i, subarray in enumerate(ndarray):try:return[i]+ ndindex(subarray, item)except:passIn[1]: ndindex(x,103)Out[1]:[4,0,3]
Para los arreglos 1D, recomendaría np.flatnonzero(array == value)[0], lo que es equivalente a ambos np.nonzero(array == value)[0][0]y np.where(array == value)[0][0]evita la fealdad de desempaquetar una tupla de 1 elemento.
Una alternativa para seleccionar el primer elemento de np.where () es usar una expresión generadora junto con enumerate, como:
>>>import numpy as np
>>> x = np.arange(100)# x = array([0, 1, 2, 3, ... 99])>>> next(i for i, x_i in enumerate(x)if x_i ==2)2
Para una matriz bidimensional, uno haría:
>>> x = np.arange(100).reshape(10,10)# x = array([[0, 1, 2,... 9], [10,..19],])>>> next((i,j)for i, x_i in enumerate(x)...for j, x_ij in enumerate(x_i)if x_ij ==2)(0,2)
La ventaja de este enfoque es que deja de verificar los elementos de la matriz después de encontrar la primera coincidencia, mientras que np.where verifica todos los elementos para encontrar una coincidencia. Una expresión generadora sería más rápida si hay una coincidencia temprana en la matriz.
En caso de que no haya una coincidencia en la matriz, este método también le permite especificar convenientemente un valor de reserva. Si el primer ejemplo volviera Nonecomo una alternativa, sería next((i for i, x_i in enumerate(x) if x_i == 2), None).
Erlend Magnus Viggen
4
Hay muchas operaciones en NumPy que tal vez podrían reunirse para lograr esto. Esto devolverá índices de elementos iguales al elemento:
numpy.nonzero(array - item)
Luego, puede tomar los primeros elementos de las listas para obtener un solo elemento.
Respuestas:
Sí, aquí está la respuesta dada una matriz NumPy
array
, y un valoritem
, para buscar:El resultado es una tupla con primero todos los índices de fila, luego todos los índices de columna.
Por ejemplo, si una matriz tiene dos dimensiones y contiene su artículo en dos ubicaciones, entonces
sería igual a su artículo y también lo haría
numpy.where
fuente
rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
np.argwhere
sería un poco más útil aquí:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
where
funciona en cualquier matriz, y devolverá una tupla de longitud 3 cuando se usa en una matriz 3D, etc.Si necesita el índice de la primera aparición de un solo valor , puede usar
nonzero
(owhere
, lo que equivale a lo mismo en este caso):Si necesita el primer índice de cada uno de los muchos valores , obviamente podría hacer lo mismo que anteriormente varias veces, pero hay un truco que puede ser más rápido. A continuación se encuentran los índices del primer elemento de cada subsecuencia :
Observe que encuentra el comienzo de ambas subsecuencias de 3s y ambas subsecuencias de 8s:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
Por lo tanto, es ligeramente diferente a encontrar la primera aparición de cada valor. En su programa, puede trabajar con una versión ordenada
t
para obtener lo que desea:fuente
r_
es?r_
concatena; o, más precisamente, traduce objetos de corte a concatenación a lo largo de cada eje. Podría haber usado en suhstack
lugar; eso puede haber sido menos confuso. Consulte la documentación para obtener más información sobrer_
. También hay unc_
.vals, locs = np.unique(t, return_index=True)
También puede convertir una matriz NumPy para listar en el aire y obtener su índice. Por ejemplo,
Imprimirá 1.
fuente
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
en una matriz NumPy deobject
(o cualquier otra cosa más específica que sea apropiada) y simplemente hacerfind_arr[index_list]
.Solo para agregar un muy eficiente y práctico numbaalternativa basada en
np.ndenumerate
encontrar el primer índice:Esto es bastante rápido y trata naturalmente con matrices multidimensionales :
Esto puede ser mucho más rápido (porque está cortocircuitando la operación) que cualquier enfoque que use
np.where
onp.nonzero
.Sin embargo
np.argwhere
, también podría tratar con gracia las matrices multidimensionales (necesitaría convertirlo manualmente en una tupla y no está en cortocircuito), pero fallaría si no se encuentra ninguna coincidencia:fuente
@njit
es una abreviatura de,jit(nopython=True)
es decir, la función se compilará completamente sobre la marcha en el momento de la primera ejecución para que las llamadas del intérprete de Python se eliminen por completo.Si va a usar esto como un índice en otra cosa, puede usar índices booleanos si las matrices son de escala amplia; No necesitas índices explícitos. La forma más simple de hacer esto es simplemente indexar en función de un valor de verdad.
Cualquier operación booleana funciona:
El método distinto de cero también toma booleanos:
Los dos ceros son para la tupla de índices (suponiendo que first_array es 1D) y luego el primer elemento en la matriz de índices.
fuente
l.index(x)
devuelve el i más pequeño de manera que i es el índice de la primera aparición de x en la lista.Se puede suponer con seguridad que la
index()
función en Python se implementa para que se detenga después de encontrar la primera coincidencia, y esto da como resultado un rendimiento promedio óptimo.Para encontrar un elemento que se detiene después de la primera coincidencia en una matriz NumPy, use un iterador ( ndenumerate ).
Matriz NumPy:
Tenga en cuenta que ambos métodos
index()
ynext
devuelven un error si no se encuentra el elemento. Connext
, se puede usar un segundo argumento para devolver un valor especial en caso de que no se encuentre el elemento, p. Ej.Hay otras funciones en NumPy (
argmax
,where
ynonzero
) que puede ser utilizado para encontrar un elemento en una matriz, pero todos tienen el inconveniente de ir a través de todo el conjunto en busca de todas las ocurrencias, por tanto, no está optimizado para encontrar el primer elemento. Tenga en cuenta también esowhere
ynonzero
devuelva las matrices, por lo que debe seleccionar el primer elemento para obtener el índice.Comparación de tiempo
Simplemente comprobando que para matrices grandes la solución que usa un iterador es más rápida cuando el elemento buscado está al comienzo de la matriz (usando
%timeit
en el shell de IPython):Este es un problema abierto de NumPy GitHub .
Ver también: Numpy: encuentre el primer índice de valor rápidamente
fuente
%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))
funciona Si se pregunta por qué es 1000 veces más lento, es porque los bucles de Python sobre matrices numpy son notoriamente lentos.argmax
ywhere
en este caso son mucho más rápidos (elemento buscado al final de la matriz)Para las matrices ordenadas unidimensionales , sería mucho más simple y eficiente O (log (n)) usar numpy.searchsorted que devuelve un entero NumPy (posición). Por ejemplo,
Solo asegúrate de que la matriz ya esté ordenada
También verifique si el índice devuelto realmente contiene el elemento buscado, ya que el objetivo principal de searchsorted es encontrar índices donde se deben insertar elementos para mantener el orden.
fuente
Para indexar cualquier criterio, puede hacer algo como lo siguiente:
Y aquí hay una función rápida para hacer lo que hace list.index (), excepto que no genera una excepción si no se encuentra. Cuidado, esto es probablemente muy lento en matrices grandes. Probablemente pueda mono parchear esto en matrices si prefiere usarlo como método.
fuente
Para los arreglos 1D, recomendaría
np.flatnonzero(array == value)[0]
, lo que es equivalente a ambosnp.nonzero(array == value)[0][0]
ynp.where(array == value)[0][0]
evita la fealdad de desempaquetar una tupla de 1 elemento.fuente
Una alternativa para seleccionar el primer elemento de np.where () es usar una expresión generadora junto con enumerate, como:
Para una matriz bidimensional, uno haría:
La ventaja de este enfoque es que deja de verificar los elementos de la matriz después de encontrar la primera coincidencia, mientras que np.where verifica todos los elementos para encontrar una coincidencia. Una expresión generadora sería más rápida si hay una coincidencia temprana en la matriz.
fuente
None
como una alternativa, seríanext((i for i, x_i in enumerate(x) if x_i == 2), None)
.Hay muchas operaciones en NumPy que tal vez podrían reunirse para lograr esto. Esto devolverá índices de elementos iguales al elemento:
Luego, puede tomar los primeros elementos de las listas para obtener un solo elemento.
fuente
El paquete numpy_indexed (descargo de responsabilidad, soy su autor) contiene un equivalente vectorizado de list.index para numpy.ndarray; es decir:
Esta solución ha vectorizado el rendimiento, se generaliza a ndarrays y tiene varias formas de tratar con valores perdidos.
fuente
Nota: esto es para la versión Python 2.7
Puede usar una función lambda para tratar el problema, y funciona tanto en la matriz NumPy como en la lista.
Y puedes usar
para obtener el primer índice de los elementos filtrados.
Para python 3.6, use
en vez de
fuente
<filter object at 0x0000027535294D30>
Python 3 (probado en Python 3.6.3). ¿Quizás actualizar para Python 3?