2012-03-31 24 views
27

Wie kann ich die Werte der Diagonale einer Matrix in numpy ändern?Ändern der Werte der Diagonalen einer Matrix in numpy

Ich überprüfte Numpy modify ndarray diagonal, aber die Funktion dort ist nicht in numpy v 1.3.0 implementiert.

können sagen, dass wir eine np.array X haben und ich möchte alle Werte der Diagonalen auf 0.

+1

Welche Version von numpy verwenden Sie? 'np.diag_indices_from' wurde in v1.4 hinzugefügt – JoshAdel

+0

yep, du hast recht, ich benutze derzeit python v 1.3.0 – pacodelumberg

+0

@LangerHansIslands Hoffentlich meinst du numpy 1.3, nicht Python 1.3 (die Mitte der neunziger Jahre herauskam .. .: p) – Dougal

Antwort

2
def replaceDiagonal(matrix, replacementList): 
    for i in range(len(replacementList)): 
     matrix[i][i] = replacementList[i] 

Wo Größe n in einer n x n-Matrix ist.

+3

Oder 'n = len (ersatzliste); Matrix [: n,: n] = Ersatzliste. Dies macht die Schleife in C statt in Python und wird daher viel schneller sein. – Dougal

+0

@Dougal: Großartig, das wusste ich nicht. Kannst du es als Antwort posten? –

+0

Sicher, [gerade getan] (http://stackoverflow.com/a/9959707/344821). – Dougal

12

Wenn Sie eine Version von numpy verwenden, die nicht fill_diagonal haben (die right way die Diagonale auf eine Konstante eingestellt) oder diag_indices_from, Sie können diese ziemlich leicht mit Array-Slicing tun:

# assuming a 2d square array 
n = mat.shape[0] 
mat[range(n), range(n)] = 0 

diese viel schneller als eine explizite Schleife in Python sind, weil der Looping in C geschieht und möglicherweise vektorisiert wird.

Eine schöne Sache ist, dass Sie auch eine Diagonale mit einer Liste von Elementen füllen können, anstatt einen konstanten Wert (wie diagflat, aber zum Ändern einer bestehenden Matrix, anstatt eine neue zu erstellen). Zum Beispiel wird festgelegt dies die Diagonale Ihrer Matrix 0, 1, 2, ...:

# again assuming 2d square array 
n = mat.shape[0] 
mat[range(n), range(n)] = range(n) 

Wenn Sie mehr Array Formen unterstützen müssen, das komplizierter ist (weshalb fill_diagonal schön ist. ..):

m[list(zip(*map(range, m.shape)))] = 0 

(Das ist list Aufruf in Python notwendig, nur 3, wo zip einen Iterator zurückgibt)

+0

Um es für zukünftige Leser klar zu machen, setzt 'mat [: n,: n] = 0' _ das ganze Array/Matrix_ auf 0, nicht nur die diagonalen Elemente. 'zip' Version macht in der Tat die Diag. – gorlum0

+0

@ gorlum0 Whoops - Danke, dass du das herausgebracht hast. Ich habe es gerade bearbeitet, um es zu reparieren (der 'zip' ist dort eigentlich nicht nötig)'. – Dougal

+0

Coole, sogar nackte "Bereiche". Dieses implizite Zeug ist schwer zu kennen. – gorlum0

9

diese Hier ist ein weiterer guter Weg, zu tun.. Wenn Sie eine eindimensionale Sicht auf die Hauptdiagonale Verwendung des Arrays:

A.ravel()[:A.shape[1]**2:A.shape[1]+1] 

Für die i-te superdiagonal Verwendung:

A.ravel()[i:max(0,A.shape[1]-i)*A.shape[1]:A.shape[1]+1] 

Für die i-te subdiagonal Verwendung:

A.ravel()[A.shape[1]*i:A.shape[1]*(i+A.shape[1]):A.shape[1]+1] 

Oder im Allgemeinen, für die i-Diagonale, wo die Hauptdiagonale 0 ist, sind die Subdiagonalen negativ und die Superdiagonalen sind positiv, verwenden:

Dies sind Ansichten und keine Kopien, so dass sie zum Extrahieren einer Diagonale schneller ausgeführt werden, aber alle Änderungen am neuen Array-Objekt werden auf das ursprüngliche Array angewendet. Auf meinem Computer laufen diese schneller als die Funktion fill_diagonal, wenn die Hauptdiagonale auf eine Konstante gesetzt wird, aber das ist möglicherweise nicht immer der Fall. Sie können auch verwendet werden, um einer Diagonalen anstelle einer Konstante ein Wertefeld zuzuordnen.

Hinweise: Bei kleinen Arrays kann das Attribut flat des NumPy-Arrays möglicherweise schneller verwendet werden. Wenn Geschwindigkeit ein großes Problem ist, könnte es sich lohnen, A.shape[1] eine lokale Variable zu machen. Wenn das Array nicht zusammenhängend ist, wird auch ravel() eine Kopie zurückgeben. Um einem schrittweisen Segment Werte zuzuweisen, muss das ursprüngliche Array, das zum Generieren des schrittweisen Segments verwendet wurde, kreativ geschnitten werden (wenn es zusammenhängend ist). oder um das flat Attribut zu verwenden.

Auch war ursprünglich geplant, dass in NumPy 1.10 und später die 'Diagonale' Methode von Arrays eine Ansicht statt einer Kopie zurückgeben wird. Diese Änderung wurde noch nicht gemacht, aber hoffentlich wird dieser Trick an einer Stelle nicht mehr nötig sein. Siehe http://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.diagonal.html

+0

Schön und hacky, ich mag es! Nur ein Vorbehalt ist, ich denke, dass Sie das 'wrap = True'-Verhalten erhalten würden, das in den [np.fill_diagonal] -Dokumenten beschrieben wird (http://docs.scipy.org/doc/numpy/reference/generated/numpy.fill_diagonal.html)). Sie können wahrscheinlich das Problem lösen, indem Sie Ihren Slices einen angemessenen Stop-Wert hinzufügen. – Jaime

+0

Danke, guter Fang. Ich habe es gerade bearbeitet, um das und ein paar andere Dinge zu beheben. – IanH

1
>>> a = numpy.random.rand(2,2) 
>>> a 
array([[ 0.41668355, 0.07982691], 
     [ 0.60790982, 0.0314224 ]]) 
>>> a - numpy.diag(numpy.diag(a)) 
array([[ 0.  , 0.07982691], 
     [ 0.60790982, 0.  ]]) 
4

Minimal. Code.

X[np.diag_indices_from(X)] = 0. 

screenshot

1

können Sie Folgendes tun.

Angenommen, Ihre Matrix ist 4 * 4 Matrix.

indices_diagonal = np.diag_indices(4) 

yourarray[indices_diagonal] = Val 
Verwandte Themen