Existe-t-il une méthode numpy-thonique, par exemple une fonction, pour trouver la valeur la plus proche dans un tableau?
Exemple:
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()
donne la mauvaise réponse. Cela vous donne le min de la distance de valeur absolue, et en quelque sorte nous devons retourner la valeur réelle du tableau. Nous pourrions ajoutervalue
et approcher, mais la valeur absolue jette une clé dans les choses ...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.
Utiliseridxmin
au lieu deargmin
fonctionne pour moi avec la solution ci-dessus. (v3.6.4)SI votre tableau est trié et est très grand, c'est une solution beaucoup plus rapide:
Cela se transforme en très grands tableaux. Vous pouvez facilement modifier ce qui précède pour trier dans la méthode si vous ne pouvez pas supposer que le tableau est déjà trié. C'est exagéré pour les petits tableaux, mais une fois qu'ils sont grands, c'est beaucoup plus rapide.
la source
np.searchsorted
prend environ 2 µs pour mon ensemble de test, la fonction entière environ 10 µs. L'utilisationnp.abs
devient encore pire. Aucune idée de ce que python fait là-bas.math
routines, voir cette réponse .if/else
doit être remplacé paridx = idx - (np.abs(value - array[idx-1]) < np.abs(value - array[idx])); return array[idx]
value
est plus grand quearray
le plus gros élément. J'ai changé laif
déclaration pour laif idx == len(array) or math.fabs(value - array[idx - 1]) < math.fabs(value - array[idx])
faire fonctionner pour moi!if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])):
Avec une légère modification, la réponse ci-dessus fonctionne avec des tableaux de dimension arbitraire (1d, 2d, 3d, ...):
Ou, écrit en une seule ligne:
la source
a[np.abs(a-a0).argmin)]
fonctionne bien.a[np.sum(np.square(np.abs(a-a0)),1).argmin()]
.Résumé de la réponse : si l'on a trié,
array
le code de bissection (donné ci-dessous) est le plus rapide. ~ 100-1000 fois plus rapide pour les grandes baies, et ~ 2-100 fois plus rapide pour les petites baies. Il ne nécessite pas non plus numpy. Si vous avez un tri non trié,array
si ifarray
est grand, vous devez d' abord envisager d'utiliser un tri O (n logn), puis une bissection, et s'ilarray
est petit, la méthode 2 semble la plus rapide.Vous devez d'abord clarifier ce que vous entendez par valeur la plus proche . Souvent, on veut l'intervalle en abscisse, par exemple tableau = [0,0.7,2.1], valeur = 1,95, la réponse serait idx = 1. C'est le cas dont je soupçonne que vous avez besoin (sinon les éléments suivants peuvent être modifiés très facilement avec une instruction conditionnelle de suivi une fois que vous avez trouvé l'intervalle). Je noterai que la manière optimale d'effectuer ceci est avec la bissection (que je fournirai en premier - notez qu'elle ne nécessite pas du tout numpy et est plus rapide que d'utiliser les fonctions numpy car elles effectuent des opérations redondantes). Ensuite, je fournirai une comparaison temporelle avec les autres présentées ici par d'autres utilisateurs.
Bissection:
Je vais maintenant définir le code des autres réponses, elles renvoient chacune un index:
Je vais maintenant chronométrer les codes: Notez que les méthodes 1, 2, 4, 5 ne donnent pas correctement l'intervalle. Les méthodes 1,2,4 arrondissent au point le plus proche dans le tableau (par exemple> = 1,5 -> 2), et la méthode 5 arrondit toujours (par exemple 1,45 -> 2). Seules les méthodes 3 et 6, et bien sûr la bissection donnent correctement l'intervalle.
Pour un grand tableau, la bissection donne 4us par rapport au 180us suivant et au plus long 1,21 ms (~ 100 - 1000 fois plus rapide). Pour les baies plus petites, c'est ~ 2-100 fois plus rapide.
la source
array
c'est petit, la méthode 2 semble la plus rapide". à quel point vouliez-vous dire @JoshAlbert?Voici une extension pour trouver le vecteur le plus proche dans un tableau de vecteurs.
la source
norm(..., axis=-1)
devrait être plus rapide que d'extraire lesx,y
valeurs via l'itération Python. Aussi,x,y
les scalaires sont-ils ici? Ilnorm(x+y)
y a ensuite un bug puisque, par exemple, la distance(+1, -1)
sera traitée comme 0.idx = np.array([np.linalg.norm(x+y) for (x,y) in abs(array-value)]).argmin()
Si vous ne voulez pas utiliser numpy, cela le fera:
la source
Voici une version qui gérera un tableau de "valeurs" non scalaire:
Ou une version qui retourne un type numérique (par exemple int, float) si l'entrée est scalaire:
la source
outer
méthode d'un ufunc auparavant, je pense que je l'utiliserai plus à l'avenir. Soit ditarray[indices]
en passant, la première fonction devrait revenir .np.subtract.outer
générera toute la matrice du produit externe qui est vraiment lente et gourmande en mémoire siarray
et / ouvalues
est très grande.Voici une version avec scipy pour @Ari Onasafari, répondez " pour trouver le vecteur le plus proche dans un tableau de vecteurs "
la source
Voici une version vectorisée rapide de la solution de @ Dimitri si vous en avez beaucoup
values
à rechercher (values
peut être un tableau multidimensionnel):Repères
> 100 fois plus rapide que l'utilisation d'une
for
boucle avec la solution de @ Demitri »la source
idx = np.searchsorted(array, values)
alors:idx[array[idx] - values>np.diff(array).mean()*0.5]-=1
et enfinreturn array[idx]
Pour les grands tableaux, la (excellente) réponse donnée par @Demitri est beaucoup plus rapide que la réponse actuellement indiquée comme la meilleure. J'ai adapté son algorithme exact des deux manières suivantes:
La fonction ci-dessous fonctionne que le tableau d'entrée soit trié ou non.
La fonction ci-dessous renvoie l' index du tableau d'entrée correspondant à la valeur la plus proche, ce qui est un peu plus général.
Notez que la fonction ci-dessous gère également un cas de bord spécifique qui entraînerait un bogue dans la fonction d'origine écrite par @Demitri. Sinon, mon algorithme est identique au sien.
la source
x = np.array([2038, 1758, 1721, 1637, 2097, 2047, 2205, 1787, 2287, 1940, 2311, 2054, 2406, 1471, 1460])
. Avecfind_nearest(x, 1739.5)
(valeur la plus proche du premier quantile), j'obtiens1637
(raisonnable) et1
(bug?).Ceci est une version vectorisée de la réponse d' unutbu :
la source
Je pense que la manière la plus pythonique serait:
Ceci est le code de base. Vous pouvez l'utiliser comme fonction si vous le souhaitez
la source
Toutes les réponses sont utiles pour rassembler les informations pour écrire du code efficace. Cependant, j'ai écrit un petit script Python à optimiser pour divers cas. Ce sera le meilleur cas si le tableau fourni est trié. Si l'on recherche l'index du point le plus proche d'une valeur spécifiée, alors le
bisect
module est le plus efficace en temps. Lorsqu'une recherche les indices correspondent à un tableau, lenumpy searchsorted
plus efficace.Dans [63]:% temps bisect.bisect_left (xlist, 0,3) Temps CPU: utilisateur 0 ns, sys: 0 ns, total: 0 ns Temps de mur: 22,2 µs
Dans [64]:% time np.searchsorted (xar, 0.3, side = "left") Temps CPU: utilisateur 0 ns, sys: 0 ns, total: 0 ns Temps de mur: 98,9 µs
% time np.searchsorted (xar, randpts, side = "left") Temps CPU: utilisateur 4 ms, sys: 0 ns, total: 4 ms Temps de mur: 1,2 ms
Si nous suivons la règle multiplicative, alors numpy devrait prendre ~ 100 ms, ce qui implique ~ 83X plus rapide.
la source
Pour un tableau 2d, pour déterminer la position i, j de l'élément le plus proche:
la source
la source
Peut-être utile pour
ndarrays
:la source