2016-06-15 2 views
2

This answer erläutert, wie die am nächsten zu finden (sortiert) Array-Element an einem Einpunkt, in einer Art und Weise effizient für große Arrays (leicht modifiziert):Elemente der Matrix einen nächsten an Elementen der Array zwei

def arg_nearest(array, value): 
    idx = np.searchsorted(array, value, side="left") 
    if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])): 
     return idx-1 
    else: 
     return idx 

Wenn wir stattdessen die Array-Elemente am nächsten zu einem Set von Punkten (dh ein zweites Array) suchen möchten; gibt es effiziente (durch Geschwindigkeit, für große Arrays) Möglichkeiten, dies zu erweitern, abgesehen von der Verwendung einer For-Schleife?

Einige Testfälle:

>>> xx = [0.2, 0.8, 1.3, 1.5, 2.0, 3.1, 3.8, 3.9, 4.5, 5.1, 5.5] 
>>> yy = [1, 2, 3, 4, 5] 
>>> of_x_nearest_y(xx, yy) 
[0.5, 2.0, 3.1, 3.9, 5.1] 

>>> xx = [0.2, 0.8, 1.3, 1.5, 2.0, 3.1, 3.8, 3.9, 4.5, 5.1, 5.5] 
>>> yy = [-2, -1, 4.6, 5.8] 
>>> of_x_nearest_y(xx, yy) 
[0.2, 0.2, 4.5, 5.5] 

Edit: vorausgesetzt, beide Arrays sortiert sind, können Sie eine wenig besser als ein vollständig naive for-Schleife tun, indem Werte unter den bereits abgestimmt ausgenommen , dh

+0

'searchsorted' benötigt ein Array von Werten, nach denen gesucht werden soll. Es ist also nicht zu schwierig,' arg_nearest' für Ihren Job zu ändern. – user2357112

+0

@ user2357112 hmmm, guter Punkt! – DilithiumMatrix

Antwort

1

Sie können einige Änderungen vornehmen, um es für ein Array von Elementen inzu erweitern, wie so -

idx = np.searchsorted(xx, yy, side="left").clip(max=xx.size-1) 
mask = (idx > 0) & \ 
     ((idx == len(xx)) | (np.fabs(yy - xx[idx-1]) < np.fabs(yy - xx[idx]))) 
out = xx[idx-mask] 

Erklärung

Nomenklatur: array ist die Anordnung, in der wir Elemente aus value Ort suchen, um die sortierte Art von array zu halten.

Änderungen erforderlich, um die Lösung für ein einzelnes Element zu vielen Elemente für die Suche zu erweitern:

1] Clip der Indizes Array idx von np.searchsorted bei einer max erhalten. von array.size-1, denn für Elemente in value, die größer sind als das Maximum von array, müssen wir idx indexierbar von array machen.

2] Führen Sie numpy ein, um math zu ersetzen, um diese Operationen vektorisiert durchzuführen.

3] Ersetzen Sie die bedingte Anweisung durch den Trick idx - mask. In diesem Fall würde Python intern mask in ein int Array konvertieren, das dem Datentyp idx entspricht. Somit werden alle True Elemente zu 1 und somit zu True Elementen, die wir effektiv idx-1 hätten, was der True Fall der IF bedingten Anweisung im ursprünglichen Code ist.

+0

Schön! Ich kam (effektiv) die gleiche Lösung, außer 8 Linien mit zahlreichen Filtern und ein paar '~' Inversionen zu umfassen ... Sie gewinnen! – DilithiumMatrix

+1

@DilithiumMatrix Interessantes Problem wirklich und sollte nützlich sein bei der Lösung vieler anderer Probleme in der Nähe! Vorher wäre ich mit einer brute-force-basierten Lösung gegangen: 'xx [np.abs (xx [:, None] - yy) .argmin (0)]'. Aber diese 'searchsorted'-basierte Lösung sollte ziemlich gut für große Arrays skalieren. Danke, dass Sie uns diese effiziente Idee vorgestellt haben! – Divakar

+0

Haha, immer froh, dass meine Kämpfe nützlich sind! – DilithiumMatrix

Verwandte Themen