existe-t-il un moyen numpy-thonique, par exemple une fonction, pour trouver la "valeur la plus proche" dans un tableau ? Exemple :
np.find_nearest( array, value )
Merci d'avance !
existe-t-il un moyen numpy-thonique, par exemple une fonction, pour trouver la "valeur la plus proche" dans un tableau ? Exemple :
np.find_nearest( array, value )
Merci d'avance !
import numpy as np
def find_nearest(array,value):
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
@EOL : return np.abs(array-value).min()
donne une mauvaise réponse. Cela vous donne le minimum de la distance de la valeur absolue, et d'une manière ou d'une autre nous devons retourner la valeur réelle du tableau. Nous pourrions ajouter value
et s'en rapprochent, mais la valeur absolue jette un trouble dans les choses...
@~unutbu Vous avez raison, c'est ma faute. Je n'ai rien trouvé de mieux que votre solution !
SI votre tableau est trié et est très grand, c'est une solution beaucoup plus rapide :
def find_nearest(array,value):
idx = np.searchsorted(array, value, side="left")
if math.fabs(value - array[idx-1]) < math.fabs(value - array[idx]):
return array[idx-1]
else:
return array[idx]
Cela permet d'atteindre des réseaux de très grande taille. Vous pouvez facilement modifier la méthode ci-dessus pour trier dans la méthode si vous ne pouvez pas supposer que le tableau est déjà trié. C'est un peu exagéré pour les petits tableaux, mais une fois qu'ils sont grands, c'est beaucoup plus rapide.
Cela semble être la solution la plus raisonnable. Je me demande pourquoi il est si lent de toute façon. Simple np.searchsorted
prend environ 2 µs pour mon jeu de test, la fonction entière environ 10 µs. En utilisant np.abs
ça devient encore pire. Aucune idée de ce que python fait là.
@Michael Pour les valeurs uniques, les routines mathématiques de Numpy seront plus lentes que celles de l math
routines, voir cette réponse .
C'est la meilleure solution si vous souhaitez consulter plusieurs valeurs à la fois (avec quelques ajustements). L'ensemble if/else
doit être remplacé par idx = idx - (np.abs(value - array[idx-1]) < np.abs(value - array[idx])); return array[idx]
Avec une légère modification, la réponse ci-dessus fonctionne avec des tableaux de dimension arbitraire (1d, 2d, 3d, ...) :
def find_nearest(a, a0):
"Element in nd array `a` closest to the scalar value `a0`"
idx = np.abs(a - a0).argmin()
return a.flat[idx]
Ou, écrit en une seule ligne :
a.flat[np.abs(a - a0).argmin()]
En fait, cela ne fonctionne toujours que pour une seule dimension, puisque argmin() donne plusieurs résultats par colonne / dimension. J'ai aussi fait une faute de frappe. Cela fonctionne, au moins pour 2 dimensions : a[np.sum(np.square(np.abs(a-a0)),1).argmin()]
.
Donc, cela ne fonctionne pas pour les dimensions supérieures, et la réponse devrait être supprimée (ou modifiée pour refléter cela)
Voici une extension pour trouver le vecteur le plus proche dans un tableau de vecteurs.
import numpy as np
def find_nearest_vector(array, value):
idx = np.array([np.linalg.norm(x+y) for (x,y) in array-value]).argmin()
return array[idx]
A = np.random.random((10,2))*100
""" A = array([[ 34.19762933, 43.14534123],
[ 48.79558706, 47.79243283],
[ 38.42774411, 84.87155478],
[ 63.64371943, 50.7722317 ],
[ 73.56362857, 27.87895698],
[ 96.67790593, 77.76150486],
[ 68.86202147, 21.38735169],
[ 5.21796467, 59.17051276],
[ 82.92389467, 99.90387851],
[ 6.76626539, 30.50661753]])"""
pt = [6, 30]
print find_nearest_vector(A,pt)
# array([ 6.76626539, 30.50661753])
Je pense norm(..., axis=-1)
devrait être plus rapide que l'extraction du x,y
par l'itération Python. Également, x,y
sont des scalaires ici ? Alors norm(x+y)
est un bug puisque, par exemple, la distance (+1, -1)
sera traité comme 0.
Voici une version qui gère un tableau de "valeurs" non scalaire :
import numpy as np
def find_nearest(array, values):
indices = np.abs(np.subtract.outer(array, values)).argmin(0)
return array[index]
Ou une version qui renvoie un type numérique (par exemple int, float) si l'entrée est scalaire :
def find_nearest(array, values):
values = np.atleast_1d(values)
indices = np.abs(np.subtract.outer(array, values)).argmin(0)
out = array[indices]
return out if len(out) > 1 else out[0]
Bonne réponse, je n'ai jamais utilisé le outer
Je n'ai jamais utilisé la méthode de l'ufunc auparavant, mais je pense que je l'utiliserai davantage à l'avenir. La première fonction doit retourner array[indices]
d'ailleurs.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.