2015-01-10 21 views
5

Ich möchte diagonale Elemente aus einer 2D-Matrix ändern. Dies sind Haupt- und Nicht-Hauptdiagonalen.Numpy: Diagonale Elemente der Matrix vor 1.10

numpy.diagonal() In NumPy 1.10, wird es eine Lese/Schreib-Ansicht zurückzukehren, Schreiben an die zurück Array wird Ihre ursprüngliche Array ändern.

numpy.fill_diagonal(), numpy.diag_indices() funktioniert nur mit Hauptdiagonalelemente

Hier ist meine Anwendungsfall: Ich habe eine Matrix der folgenden Form neu erstellen möchten, das ist sehr trivial mit Diagonalnotation gegeben, dass ich alle x, y, z als Arrays haben.

matrix

+0

was ist mit 'numpy.diag'? – talonmies

+1

Ich denke 'np.diag' nennt' np.diagonal' welches vor Numpy 1.10, [Schwierigkeiten] (http://docs.scipy.org/doc/numpy/reference/generated/numpy.diagonal.html) darstellt. wenn Sie versuchen, Werte in das Array zu schreiben. –

+0

Vielleicht werfen Sie einen Blick auf ['scipy.sparse.diags'] (http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.diags.html) und [' scipy .spärlich.dia_matrix'] (http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.sparse.dia_matrix.htm). –

Antwort

4

Sie könnten immer Slicing verwenden, um einen Wert o zuzuweisen r Array zu den Diagonalen.

Durch das Übergeben einer Liste von Zeilenindizes und einer Liste von Spaltenindizes können Sie direkt (und effizient) auf die Speicherorte zugreifen. Zum Beispiel:

>>> z = np.zeros((5,5)) 
>>> z[np.arange(5), np.arange(5)] = 1 # diagonal is 1 
>>> z[np.arange(4), np.arange(4) + 1] = 2 # first upper diagonal is 2 
>>> z[np.arange(4) + 1, np.arange(4)] = [11, 12, 13, 14] # first lower diagonal values 

ändert die Anordnung von Nullen z zu:

array([[ 1., 2., 0., 0., 0.], 
     [ 11., 1., 2., 0., 0.], 
     [ 0., 12., 1., 2., 0.], 
     [ 0., 0., 13., 1., 2.], 
     [ 0., 0., 0., 14., 1.]]) 

Im Allgemeinen für eine k x k Array namens z, können Sie die i ten oberen diagonalen einstellen mit

z[np.arange(k-i), np.arange(k-i) + i] 

und die i ten unteren Diagonale mit

z[np.arange(k-i) + i, np.arange(k-i)] 

Hinweis: Wenn Sie anrufen np.arange mehrmals vermeiden möchten, können Sie einfach ix = np.arange(k) einmal schreiben und dann diesen Bereich in Scheiben schneiden je nach Bedarf: nur zum Spaß

np.arange(k-i) == ix[:-i] 
4

Versuchen Sie folgendes:

>>> A = np.zeros((6,6)) 
>>> i,j = np.indices(A.shape) 
>>> z = [1, 2, 3, 4, 5] 

Jetzt können Sie intuitiv jede Diagonale Zugang:

>>> A[i==j-1] = z 
>>> A 
array([[ 0., 1., 0., 0., 0., 0.], 
     [ 0., 0., 2., 0., 0., 0.], 
     [ 0., 0., 0., 3., 0., 0.], 
     [ 0., 0., 0., 0., 4., 0.], 
     [ 0., 0., 0., 0., 0., 5.], 
     [ 0., 0., 0., 0., 0., 0.]]) 

In gleicher Weise können Sie Arrays A[i==j] zuweisen usw.

+0

Habe die Leistung nicht mit @ajcrs Antwort verglichen, aber ich mag diese Einfachheit. – FooBar

+0

@FooBar Diese Methode ist definitiv syntaktisch einfacher als meine :-) Aber leistungsmäßig ist es nicht effizient, eine Maske (mit 'i == j-1') für größere Matrizen zu konstruieren. Bei einer 1000x1000-Matrix ist die Einstellung der ersten oberen Diagonalen etwa 100 mal langsamer als die direkte Angabe der Indizes. Dies liegt daran, dass Sie eine Million "==" Vergleiche durchführen müssen, um die boolesche Maske zu erstellen (ganz zu schweigen von der großen booleschen Matrix im Speicher). Ob das zählt, hängt natürlich von Ihrem Anwendungsfall ab. –

1

hier ein anderer Ansatz. Sie können Ihre eigene Diagonalfunktion schreiben, um die Ansicht der Diagonale wiederherzustellen, die Sie benötigen.

import numpy as np 

def diag(a, k=0): 
    if k > 0: 
     a = a[:, k:] 
    elif k < 0: 
     a = a[-k:, :] 

    shape = (min(a.shape),) 
    strides = (sum(a.strides),) 
    return np.lib.stride_tricks.as_strided(a, shape, strides) 

a = np.arange(20).reshape((4, 5)) 
diag(a, 2)[:] = 88 
diag(a, -2)[:] = 99 
print(a) 
# [[ 0 1 88 3 4] 
# [ 5 6 7 88 9] 
# [99 11 12 13 88] 
# [15 99 17 18 19]]