NumPy propone una forma de obtener el índice del valor máximo de una matriz a través de np.argmax
.
Me gustaría algo similar, pero devolviendo los índices de los N
valores máximos.
Por ejemplo, si tengo una matriz, [1, 3, 2, 4, 5]
, function(array, n=3)
volvería los índices [4, 3, 1]
que corresponden a los elementos [5, 4, 3]
.
python
numpy
max
numpy-ndarray
Alexis Métaireau
fuente
fuente
array([5, 1, 5, 5, 2, 3, 2, 4, 1, 5])
, pizcan= 3
? ¿Cuál de todas las alternativas, como[0, 2, 3]
,[0, 2, 9]
,...
sería la correcta? Por favor, explique más sobre sus requisitos específicos. Graciasargsort
podría ser una alternativa viable si no le importa el orden de las devoluciones devueltas. Vea mi respuesta a continuación.Respuestas:
Lo más simple que he podido encontrar es:
Esto implica un tipo completo de la matriz. Me pregunto si
numpy
proporciona una forma integrada de hacer una clasificación parcial; Hasta ahora no he podido encontrar uno.Si esta solución resulta ser demasiado lenta (especialmente para los pequeños
n
), puede valer la pena buscar codificar algo en Cython .fuente
arr.argsort()[-1:-4:-1]
? Lo probé en el intérprete y aparece el mismo resultado, pero me pregunto si no está roto por algún ejemplo.np.argsort(-arr)[:3]
, que me parece más legible y al grano.arr.argsort()[::-1][:n]
es mejor porque regresa vacío para enn=0
lugar de la matriz completaLas versiones más recientes de NumPy (1.8 y superiores) tienen una función llamada
argpartition
para esto. Para obtener los índices de los cuatro elementos más grandes, hagaA diferencia
argsort
, esta función se ejecuta en tiempo lineal en el peor de los casos, pero los índices devueltos no están ordenados, como se puede ver en el resultado de la evaluacióna[ind]
. Si también lo necesitas, clasifícalos después:Para obtener los elementos top- k en orden ordenado de esta manera se necesita tiempo O ( n + k log k ).
fuente
argpartition
ejecuta en tiempo lineal, O (n), utilizando el algoritmo de introselección . La clasificación posterior solo maneja k elementos, de modo que se ejecuta en O (k log k).np.argpartition
y su algoritmo hermano,np.partition
hay una explicación más detallada en la pregunta vinculada: stackoverflow.com/questions/10337533/…a=np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
porque las listas normal de Python no son compatibles con la indexación de las listas, a diferencia denp.array
np.argpartition
toma unaxis
argumento opcional . Para encontrar los índices de los valores n superiores para cada fila:np.argpartition(a, -n, axis=1)[-n:]
Más simple aún:
donde n es el número de valores máximos.
fuente
arr[arr.argsort()[-n:]]
en lugar de negar la matriz, acaba de tomar una rebanada de los últimos elementos nUtilizar:
Para listas regulares de Python:
Si usa Python 2, use en
xrange
lugar derange
.Fuente: heapq - Algoritmo de cola de montón
fuente
heapq.nlargest(3, xrange(len(a)), a.take)
. Para las listas de Python podemos usar en.__getitem__
lugar de.take
.A
en general:heapq.nlargest(3, range(len(A.ravel())), A.ravel().take)
. (Espero que esto solo funcione en vistas, ver también (ravel vs flatten
] ( stackoverflow.com/a/28930580/603003 )).Si está trabajando con una matriz multidimensional, deberá aplanar y desentrañar los índices:
Por ejemplo:
fuente
Si no le importa el orden de los elementos K-th más grandes que puede usar
argpartition
, que deberían funcionar mejor que una clasificación completaargsort
.Los créditos van a esta pregunta .
Ejecuté algunas pruebas y parece que tiene un
argpartition
rendimiento superior aargsort
medida que aumenta el tamaño de la matriz y el valor de K.fuente
Para las matrices multidimensionales, puede usar la
axis
palabra clave para aplicar la partición a lo largo del eje esperado.Y para agarrar los artículos:
Pero tenga en cuenta que esto no devolverá un resultado ordenado. En ese caso, puede usar a lo
np.argsort()
largo del eje previsto:Aquí hay un ejemplo:
fuente
np.take_along_axis
(que probablemente no existía cuando respondió esta pregunta)Esto será más rápido que una clasificación completa, dependiendo del tamaño de su matriz original y el tamaño de su selección:
Por supuesto, implica la manipulación de su matriz original. Lo que puede solucionar (si es necesario) haciendo una copia o reemplazando los valores originales. ... lo que sea más barato para su caso de uso.
fuente
argmax(.)
no es ambigua también. (En mi humilde opinión, intenta seguir algún tipo de lógica de cortocircuito, pero desafortunadamente no proporciona un comportamiento universalmente aceptable). GraciasEl método
np.argpartition
solo devuelve los k índices más grandes, realiza una ordenación local y es más rápido quenp.argsort
(realizar una ordenación completa) cuando la matriz es bastante grande. Pero los índices devueltos NO están en orden ascendente / descendente . Digamos con un ejemplo:Podemos ver que si desea un orden ascendente estricto de k índices superiores,
np.argpartition
no le devolverá lo que desea.Además de hacer una clasificación manual después de np.argpartition, mi solución es usar PyTorch,
torch.topk
una herramienta para la construcción de redes neuronales, que proporciona API similares a NumPy con soporte para CPU y GPU. Es tan rápido como NumPy con MKL, y ofrece un impulso de GPU si necesita grandes cálculos de matriz / vector.El estricto código de los principales índices de ascenso / descenso será:
Tenga en cuenta que
torch.topk
acepta un tensor de antorcha y devuelve los valores k superiores y los índices k superiores en tipotorch.Tensor
. Similar a np, torch.topk también acepta un argumento de eje para que pueda manejar matrices / tensores multidimensionales.fuente
Utilizar:
Ahora la
result
lista contendría N tuplas (index
,value
) dondevalue
está maximizada.fuente
Utilizar:
También funciona con matrices 2D. Por ejemplo,
fuente
bottleneck
tiene una función de ordenación parcial, si el gasto de ordenar la matriz completa solo para obtener los N valores más grandes es demasiado grande.No sé nada sobre este módulo; Yo solo busqué en Google
numpy partial sort
.fuente
La siguiente es una manera muy fácil de ver los elementos máximos y sus posiciones. Aquí
axis
está el dominio;axis
= 0 significa número máximo de columna yaxis
= 1 significa número máximo de fila para el caso 2D. Y para dimensiones superiores depende de ti.fuente
Lo encontré más intuitivo de usar
np.unique
.La idea es que el método único devuelve los índices de los valores de entrada. Luego, a partir del valor único máximo y las indicaciones, se puede recrear la posición de los valores originales.
fuente
Creo que la forma más eficiente de tiempo es iterar manualmente a través de la matriz y mantener un montón mínimo de tamaño k, como han mencionado otras personas.
Y también se me ocurre un enfoque de fuerza bruta:
Establezca el elemento más grande en un valor negativo grande después de usar argmax para obtener su índice. Y luego la próxima llamada de argmax devolverá el segundo elemento más grande. Y puede registrar el valor original de estos elementos y recuperarlos si lo desea.
fuente
Este código funciona para una matriz de matriz numpy:
Esto produce una indexación de matriz n_largest verdadero-falso que también funciona para extraer elementos n_largest de una matriz de matriz
fuente