Gibt es eine numpy-thonische Möglichkeit, z. B. eine Funktion, um den nächsten Wert in einem Array zu finden?
Beispiel:
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()
gibt die falsche Antwort. Dies gibt Ihnen die min der absoluten Wertentfernung, und irgendwie müssen wir den tatsächlichen Array-Wert zurückgeben. Wir könnten hinzufügenvalue
undFutureWarning: '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.
Verwendenidxmin
stattargmin
funktioniert für mich mit der obigen Lösung. (v3.6.4)Wenn Ihr Array sortiert und sehr groß ist, ist dies eine viel schnellere Lösung:
Dies skaliert auf sehr große Arrays. Sie können das oben Gesagte leicht ändern, um es in der Methode zu sortieren, wenn Sie nicht davon ausgehen können, dass das Array bereits sortiert ist. Es ist übertrieben für kleine Arrays, aber sobald sie groß werden, ist dies viel schneller.
quelle
np.searchsorted
dauert ungefähr 2 µs für meinen Testsatz, die gesamte Funktion ca. 10 µs. Mit wirdnp.abs
es noch schlimmer. Keine Ahnung, was Python dort macht.math
Routinen, siehe diese Antwort .if/else
muss ersetzt werden durchidx = idx - (np.abs(value - array[idx-1]) < np.abs(value - array[idx])); return array[idx]
value
es größer alsarray
das größte Element ist. Ich habe dieif
Aussage geändertif idx == len(array) or math.fabs(value - array[idx - 1]) < math.fabs(value - array[idx])
, damit sie für mich funktioniert!if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])):
Mit geringfügigen Änderungen funktioniert die obige Antwort mit Arrays beliebiger Dimension (1d, 2d, 3d, ...):
Oder als einzelne Zeile geschrieben:
quelle
a[np.abs(a-a0).argmin)]
funktioniert gut.a[np.sum(np.square(np.abs(a-a0)),1).argmin()]
.Zusammenfassung der Antwort : Wenn eine sortiert ist,
array
ist der Halbierungscode (unten angegeben) am schnellsten. ~ 100-1000-mal schneller für große Arrays und ~ 2-100-mal schneller für kleine Arrays. Es erfordert auch keine Numpy. Wenn Sie eine unsortierte haben , sollten Sie,array
wenn siearray
groß ist, zuerst eine O (n logn) -Sortierung und dann eine Halbierung verwenden. Wenn siearray
klein ist, scheint Methode 2 die schnellste zu sein.Zuerst sollten Sie klarstellen, was Sie unter dem nächsten Wert verstehen . Oft möchte man das Intervall auf einer Abszisse, zB Array = [0,0.7,2.1], Wert = 1,95, Antwort wäre idx = 1. Dies ist der Fall, den Sie vermutlich benötigen (andernfalls kann das Folgende sehr einfach mit einer bedingten Folgeanweisung geändert werden, sobald Sie das Intervall gefunden haben). Ich werde bemerken, dass der optimale Weg, dies durchzuführen, die Halbierung ist (die ich zuerst bereitstellen werde - beachten Sie, dass es überhaupt kein Numpy erfordert und schneller ist als die Verwendung von Numpy-Funktionen, weil sie redundante Operationen ausführen). Dann werde ich einen Zeitvergleich mit den anderen hier von anderen Benutzern präsentierten bereitstellen.
Halbierung:
Jetzt definiere ich den Code aus den anderen Antworten, sie geben jeweils einen Index zurück:
Jetzt werde ich die Codes zeitlich festlegen: Beachten Sie, dass die Methoden 1,2,4,5 das Intervall nicht korrekt angeben. Die Methoden 1,2,4 runden auf den nächsten Punkt im Array (z. B.> = 1,5 -> 2), und Methode 5 rundet immer auf (z. B. 1,45 -> 2). Nur die Methoden 3 und 6 und natürlich die Halbierung geben das Intervall richtig an.
Für ein großes Array ergibt die Halbierung 4us im Vergleich zu den nächstbesten 180us und den längsten 1,21 ms (~ 100 - 1000-mal schneller). Für kleinere Arrays ist es ~ 2-100 mal schneller.
quelle
array
es klein ist, scheint Methode 2 die schnellste zu sein." Wie klein meintest du @JoshAlbert?Hier ist eine Erweiterung, um den nächsten Vektor in einem Array von Vektoren zu finden.
quelle
norm(..., axis=-1)
sollte schneller sein als das Extrahieren derx,y
Werte durch Python-Iteration. Auchx,y
Skalare sind hier? Dannnorm(x+y)
ist ein Fehler, da z. B. die Entfernung(+1, -1)
als 0 behandelt wird.idx = np.array([np.linalg.norm(x+y) for (x,y) in abs(array-value)]).argmin()
Wenn Sie numpy nicht verwenden möchten, geschieht dies wie folgt:
quelle
Hier ist eine Version, die ein nicht skalares "Werte" -Array verarbeitet:
Oder eine Version, die einen numerischen Typ zurückgibt (z. B. int, float), wenn die Eingabe skalar ist:
quelle
outer
Methode eines Ufunc verwendet. Ich denke, ich werde sie in Zukunft häufiger anwenden. Die erste Funktion solltearray[indices]
übrigens zurückkehren.np.subtract.outer
erzeugt die gesamte Außenproduktmatrix, die sehr langsam und speicherintensiv ist, wennarray
und / odervalues
sehr groß ist.Hier ist eine Version mit scipy für @Ari Onasafari, antworte " um den nächsten Vektor in einem Array von Vektoren zu finden "
quelle
Hier ist eine schnelle vektorisierte Version von @ Dimitris Lösung, wenn Sie viele
values
suchen müssen (values
kann ein mehrdimensionales Array sein):Benchmarks
> 100-mal schneller als die Verwendung einer
for
Schleife mit @ Demitris Lösung`quelle
idx = np.searchsorted(array, values)
idx[array[idx] - values>np.diff(array).mean()*0.5]-=1
return array[idx]
Bei großen Arrays ist die (ausgezeichnete) Antwort von @Demitri weitaus schneller als die derzeit als beste gekennzeichnete Antwort. Ich habe seinen genauen Algorithmus auf zwei Arten angepasst:
Die folgende Funktion funktioniert unabhängig davon, ob das Eingabearray sortiert ist oder nicht.
Die folgende Funktion gibt den Index des Eingabearrays zurück, der dem nächsten Wert entspricht, der etwas allgemeiner ist.
Beachten Sie, dass die folgende Funktion auch einen bestimmten Randfall behandelt, der zu einem Fehler in der ursprünglichen Funktion von @Demitri führen würde. Ansonsten ist mein Algorithmus identisch mit seinem.
quelle
x = np.array([2038, 1758, 1721, 1637, 2097, 2047, 2205, 1787, 2287, 1940, 2311, 2054, 2406, 1471, 1460])
. Mitfind_nearest(x, 1739.5)
(dem ersten Quantil am nächsten) erhalte ich1637
(vernünftig) und1
(Fehler?).Dies ist eine vektorisierte Version der Antwort von unutbu :
quelle
Ich denke, der pythonischste Weg wäre:
Dies ist der Grundcode. Sie können es als Funktion verwenden, wenn Sie möchten
quelle
Alle Antworten sind nützlich, um die Informationen zum Schreiben von effizientem Code zu sammeln. Ich habe jedoch ein kleines Python-Skript geschrieben, um es für verschiedene Fälle zu optimieren. Dies ist der beste Fall, wenn das bereitgestellte Array sortiert ist. Wenn man den Index des nächsten Punktes eines bestimmten Wertes durchsucht,
bisect
ist das Modul am zeiteffizientesten. Wenn man die Indizes durchsucht, die einem Array entsprechen,numpy searchsorted
ist das am effizientesten.In [63]:% Zeit bisect.bisect_left (xlist, 0.3) CPU-Zeiten: Benutzer 0 ns, System: 0 ns, Gesamt: 0 ns Wandzeit: 22,2 µs
In [64]:% time np.searchsorted (xar, 0,3, side = "left") CPU-Zeiten: Benutzer 0 ns, sys: 0 ns, gesamt: 0 ns Wandzeit: 98,9 µs
% time np.searchsorted (xar, randpts, side = "left") CPU-Zeiten: Benutzer 4 ms, sys: 0 ns, gesamt: 4 ms Wandzeit: 1,2 ms
Wenn wir der multiplikativen Regel folgen, sollte numpy ~ 100 ms dauern, was ~ 83X schneller bedeutet.
quelle
Für das 2d-Array, um die i, j-Position des nächsten Elements zu bestimmen:
quelle
quelle
Vielleicht hilfreich für
ndarrays
:quelle