2017-03-10 1 views
1

Ich habe das folgende Problem mit dem Sortieren eines 2D-Array mit der Funktion argsort.Python, Problem mit Verbindungen mit Argsort

Genauer gesagt, nehmen wir an, ich habe 5 Punkte und haben die euklidischen Abstände zwischen ihnen berechnet, die D in der 2D-Array gespeichert sind:

D=np.array([[0,0.3,0.4,0.2,0.5],[0.3,0,0.2,0.6,0.1], 
      [0.4,0.2,0,0.5,0],[0.2,0.6,0.5,0,0.7],[0.5,0.1,0,0.7,0]]) 
D 
array([[ 0. , 0.3, 0.4, 0.2, 0.5], 
     [ 0.3, 0. , 0.2, 0.6, 0.1], 
     [ 0.4, 0.2, 0. , 0.5, 0. ], 
     [ 0.2, 0.6, 0.5, 0. , 0.7], 
     [ 0.5, 0.1, 0. , 0.7, 0. ]]) 

Jedes Element D[i,j] (i, j = 0, .. ., 4) zeigt den Abstand zwischen Punkt i und Punkt j. Die diagonalen Einträge sind natürlich gleich Null, da sie die Entfernung eines Punktes zu sich selbst zeigen. Es kann jedoch 2 oder mehr Punkte geben, die sich überlappen. Zum Beispiel befindet sich in diesem speziellen Fall der Punkt an der gleichen Stelle des Punktes , so dass die Abstände D[2,4] und D[4,2] gleich Null sind.

Nun, ich möchte D dieses Array sortieren: für jeden Punkt i ich die Indizes seiner Nachbarpunkte wissen wollen, von der am nächsten an der am weitesten ein. Natürlich für einen gegebenen Punkt i der erste Punkt/Index im sortierten Feld sein sollte i, das heißt der der nächste Punkt ist 1 zu zeigen. I verwendet, um die Funktion argsort:

N = np.argsort(D) 
N 
array([[0, 3, 1, 2, 4], 
     [1, 4, 2, 0, 3], 
     [2, 4, 1, 0, 3], 
     [3, 0, 2, 1, 4], 
     [2, 4, 1, 0, 3]]) 

dieser Funktion können die Abstände sortiert richtig, bis es zu Punkt kommt: der erste Eintrag der 4. Reihe (von Null an zu zählen) nicht (D[4,4]=0) als I Möchte. Ich möchte, dass die 4. Reihe [4, 2, 1, 0, 3] ist. Der erste Eintrag ist , weil Punkte und Überlappung, so dass D[2,4]=D[4,2] und zwischen den gleichen Wert Einträgen D[2,4]=0 und D[4,2]=0, argsort wählen immer die ersten.

Gibt es eine Möglichkeit, dies zu beheben, so dass das sortierte Array N[i,j] von D[i,j] immer mit den Indizes beginnt, die den diagonalen Einträgen D[i,i]=0 entsprechen?

Vielen Dank für Ihre Hilfe, MarcoC

Antwort

2

Eine Möglichkeit wäre, die Diagonalelemente mit etwas weniger als globale Minimum zu füllen und dann argsort verwenden -

In [286]: np.fill_diagonal(D,D.min()-1) # Or use -1 for filling 
      # if we know beforehand that the global minimum is 0 

In [287]: np.argsort(D) 
Out[287]: 
array([[0, 3, 1, 2, 4], 
     [1, 4, 2, 0, 3], 
     [2, 4, 1, 0, 3], 
     [3, 0, 2, 1, 4], 
     [4, 2, 1, 0, 3]]) 

Wenn Sie das nicht möchten, Eingabefeld, das geändert werden soll, erstellen Sie eine Kopie und führen Sie dann die Diagonalfüllung aus.

+0

Sie können es einfach mit "-1" füllen, nein? –

+0

@StefanPochmann Das habe ich am Anfang vorgeschlagen. Aber dann dachte ich, dass Elemente außerhalb der Diagonalen auch kleiner als 0 sein könnten. Also, um es generisch zu machen eingeführt 'D.min() - 1'. – Divakar

0

Wie wäre es damit:

import numpy as np 

D = np.array([[ 0. , 0.3, 0.4, 0.2, 0.5], 
       [ 0.3, 0. , 0.2, 0.6, 0.1], 
       [ 0.4, 0.2, 0. , 0.5, 0. ], 
       [ 0.2, 0.6, 0.5, 0. , 0.7], 
       [ 0.5, 0.1, 0. , 0.7, 0. ]]) 

s = np.argsort(D) 
line = np.argwhere(s[:,0] != np.arange(D.shape[0]))[0,0] 
column = np.argwhere(s[line,:] == line)[0,0] 
s[line,0], s[line, column] = s[line, column], s[line,0] 

einfach die Linien finden, die die Elemente mit numpy.argwhere nicht das dioganal Element vor haben tauschen, dann ist die Spalte zu tauschen und dann. Dann enthält s, was Sie am Ende wollen.

Dies funktioniert für Ihr Beispiel. In einem allgemeinen Fall, in dem numpy.argwhere mehrere Elemente enthalten kann, müsste man eine Schleife über diese Elemente ausführen, anstatt nur [0,0] am Ende der beiden obigen Codezeilen einzugeben.

Ich hoffe, ich könnte helfen.