¿Existe una forma numpy-thonic, por ejemplo, función, para encontrar el valor más cercano en una matriz?
Ejemplo:
np.find_nearest( array, value )
import numpy as np
def find_nearest(array, value):
array = np.asarray(array)
idx = (np.abs(array - value)).argmin()
return array[idx]
array = np.random.random(10)
print(array)
# [ 0.21069679 0.61290182 0.63425412 0.84635244 0.91599191 0.00213826
# 0.17104965 0.56874386 0.57319379 0.28719469]
value = 0.5
print(find_nearest(array, value))
# 0.568743859261
return np.abs(array-value).min()
da la respuesta incorrecta. Esto le da el mínimo de la distancia del valor absoluto, y de alguna manera necesitamos devolver el valor real del conjunto. Podríamos añadirvalue
y acercarse, pero el valor absoluto lanza una llave en las cosas ...FutureWarning: 'argmin' is deprecated. Use 'idxmin' instead. The behavior of 'argmin' will be corrected to return the positional minimum in the future. Use 'series.values.argmin' to get the position of the minimum now.
Usar enidxmin
lugar deargmin
funciona para mí con la solución anterior. (v3.6.4)SI su matriz está ordenada y es muy grande, esta es una solución mucho más rápida:
Esto se escala a matrices muy grandes. Puede modificar fácilmente lo anterior para ordenar en el método si no puede asumir que la matriz ya está ordenada. Es excesivo para arreglos pequeños, pero una vez que se hacen grandes, esto es mucho más rápido.
fuente
np.searchsorted
toma alrededor de 2 µs para mi conjunto de prueba, toda la función unos 10 µs. Usarlonp.abs
está empeorando. No tengo idea de qué hace Python allí.math
rutinas, vea esta respuesta .if/else
debe ser reemplazado poridx = idx - (np.abs(value - array[idx-1]) < np.abs(value - array[idx])); return array[idx]
value
es más grande quearray
el elemento más grande. ¡Cambié laif
declaración paraif idx == len(array) or math.fabs(value - array[idx - 1]) < math.fabs(value - array[idx])
que funcione para mí!if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])):
Con una ligera modificación, la respuesta anterior funciona con matrices de dimensión arbitraria (1d, 2d, 3d, ...):
O, escrito como una sola línea:
fuente
a[np.abs(a-a0).argmin)]
funciona bien.a[np.sum(np.square(np.abs(a-a0)),1).argmin()]
.Resumen de la respuesta : si uno tiene un orden
array
, el código de bisección (que se muestra a continuación) se realiza más rápido. ~ 100-1000 veces más rápido para matrices grandes y ~ 2-100 veces más rápido para matrices pequeñas. No requiere numpy tampoco. Si tiene un no ordenado,array
entonces siarray
es grande, primero debe considerar usar una clasificación O (n logn) y luego una bisección, y siarray
es pequeño, entonces el método 2 parece el más rápido.Primero debes aclarar lo que quieres decir con el valor más cercano . A menudo se quiere el intervalo en una abscisa, por ejemplo, matriz = [0,0.7,2.1], valor = 1.95, la respuesta sería idx = 1. Este es el caso que sospecho que necesita (de lo contrario, lo siguiente se puede modificar muy fácilmente con una declaración condicional de seguimiento una vez que encuentre el intervalo). Notaré que la forma óptima de realizar esto es con la bisección (que proporcionaré primero; tenga en cuenta que no requiere numpy en absoluto y es más rápido que usar funciones numpy porque realizan operaciones redundantes). Luego proporcionaré una comparación de tiempos con los otros presentados aquí por otros usuarios.
Bisección:
Ahora definiré el código de las otras respuestas, cada una devuelve un índice:
Ahora cronometraré los códigos: los métodos de nota 1,2,4,5 no dan correctamente el intervalo. Los métodos 1, 2, 4 redondean al punto más cercano en la matriz (por ejemplo,> = 1.5 -> 2), y el método 5 siempre redondea hacia arriba (por ejemplo, 1.45 -> 2). Solo los métodos 3 y 6 y, por supuesto, la bisección dan el intervalo correctamente.
Para una gran matriz, la bisección da 4us en comparación con el siguiente mejor 180us y el más largo 1.21ms (~ 100 - 1000 veces más rápido). Para arreglos más pequeños es ~ 2-100 veces más rápido.
fuente
array
es pequeño, entonces el método 2 parece el más rápido". ¿Qué tan pequeño quisiste decir @JoshAlbert?Aquí hay una extensión para encontrar el vector más cercano en una matriz de vectores.
fuente
norm(..., axis=-1)
debería ser más rápido que extraer losx,y
valores a través de la iteración de Python. Además, ¿x,y
hay escalares aquí? Entoncesnorm(x+y)
es un error ya que, por ejemplo, la distancia(+1, -1)
se tratará como 0.idx = np.array([np.linalg.norm(x+y) for (x,y) in abs(array-value)]).argmin()
Si no quieres usar numpy, esto lo hará:
fuente
Aquí hay una versión que manejará una matriz de "valores" no escalares:
O una versión que devuelve un tipo numérico (por ejemplo, int, float) si la entrada es escalar:
fuente
outer
método de un ufunc antes, creo que lo usaré más en el futuro. La primera función debería volverarray[indices]
, por cierto.np.subtract.outer
generará toda la matriz del producto externo que es realmente lenta y requiere mucha memoria siarray
y / ovalues
es muy grande.Aquí hay una versión con scipy para @Ari Onasafari, responda " para encontrar el vector más cercano en una matriz de vectores "
fuente
Aquí hay una versión rápida y vectorizada de la solución de @ Dimitri si tiene muchas
values
para buscar (values
puede ser una matriz multidimensional):Puntos de referencia
> 100 veces más rápido que usar un
for
bucle con la solución de @ Demitri`fuente
idx = np.searchsorted(array, values)
luego:idx[array[idx] - values>np.diff(array).mean()*0.5]-=1
y finalmentereturn array[idx]
Para matrices grandes, la respuesta (excelente) dada por @Demitri es mucho más rápida que la respuesta actualmente marcada como la mejor. He adaptado su algoritmo exacto de las siguientes dos maneras:
La siguiente función funciona independientemente de si la matriz de entrada está ordenada o no.
La siguiente función devuelve el índice de la matriz de entrada correspondiente al valor más cercano, que es algo más general.
Tenga en cuenta que la función a continuación también maneja un caso de borde específico que conduciría a un error en la función original escrita por @Demitri. De lo contrario, mi algoritmo es idéntico al suyo.
fuente
x = np.array([2038, 1758, 1721, 1637, 2097, 2047, 2205, 1787, 2287, 1940, 2311, 2054, 2406, 1471, 1460])
. Confind_nearest(x, 1739.5)
(valor más cercano al primer cuantil), obtengo1637
(razonable) y1
(¿error?).Esta es una versión vectorizada de la respuesta de unutbu :
fuente
Creo que la forma más pitónica sería:
Este es el código básico. Puedes usarlo como una función si quieres
fuente
Todas las respuestas son beneficiosas para recopilar la información para escribir código eficiente. Sin embargo, he escrito un pequeño script de Python para optimizarlo en varios casos. Será el mejor caso si se ordena la matriz proporcionada. Si uno busca el índice del punto más cercano de un valor especificado, entonces el
bisect
módulo es el más eficiente en el tiempo. Cuando uno busca los índices corresponden a una matriz, elnumpy searchsorted
es más eficiente.En [63]:% de tiempo bisect.bisect_left (xlist, 0.3) tiempos de CPU: usuario 0 ns, sys: 0 ns, total: 0 ns Tiempo de pared: 22.2 µs
En [64]:% de tiempo np.searchsorted (xar, 0.3, side = "left") Tiempo de CPU: usuario 0 ns, sys: 0 ns, total: 0 ns Tiempo de pared: 98.9 µs
% de tiempo np.searchsorted (xar, randpts, side = "left") Tiempo de CPU: usuario 4 ms, sys: 0 ns, total: 4 ms Tiempo de muro: 1,2 ms
Si seguimos la regla multiplicativa, entonces numpy debería tomar ~ 100 ms, lo que implica ~ 83X más rápido.
fuente
Para la matriz 2d, para determinar la posición i, j del elemento más cercano:
fuente
fuente
Quizás útil para
ndarrays
:fuente