2016-06-16 12 views
2

Gibt es eine pythonic Weise die der folgenden Schritte ausführen:Diagonals eines mehrdimensionalen numpy Array

import numpy as np 
def diagonal(A): 
    (x,y,y) = A.shape 
    diags = [] 
    for a in A: diags.append(np.diagonal(a)) 
    result = np.vstack(diags) 
    assert result.shape == (x,y) 
    return result 
+1

Bitte erweitern Sie, was "A" ist. Gehen Sie davon aus, dass es sich um eine "n * m * m" -Matrix handelt? –

+0

@ evan058 Ja, ich habe versucht, diese Annahme mit der ersten Zeile meiner diagonal() -Funktion zu kommunizieren. – dshin

Antwort

3

Ansatz # 1

A sauber Art und Weise mit np.diagonal auf einer transponierten Version des Eingangsfeldes sein würde, wie so -

np.diagonal(A.T) 

Grundsätzlich sind wir Spiegeln Sie die Abmessungen des Eingabe-Array mit A.T, um np.diagonal verwenden die letzten zwei Achsen zum Extrahieren der Diagonalen Elemente entlang, bec In der Standardeinstellung hätte es sonst stattdessen die ersten beiden Achsen verwendet. Das Beste daran ist, dass dies für Arrays mit einer beliebigen Anzahl von Dimensionen funktionieren würde.

Ansatz # 2

Hier ist ein weiterer Ansatz eine Kombination aus advanced and basic indexing mit -

m,n = A.shape[:2] 
out = A[np.arange(m)[:,None],np.eye(n,dtype=bool)] 

Man kann auch einige Umformungs verwenden mit basic indexing -

out = A.reshape(m,-1)[:,np.eye(n,dtype=bool).ravel()] 

Probelauf -

In [87]: A 
Out[87]: 
array([[[73, 52, 62], 
     [20, 7, 7], 
     [ 1, 68, 89]], 

     [[15, 78, 98], 
     [24, 22, 35], 
     [19, 1, 91]], 

     [[ 5, 37, 64], 
     [22, 4, 43], 
     [84, 45, 12]], 

     [[24, 45, 42], 
     [70, 45, 1], 
     [ 6, 48, 60]]]) 

In [88]: np.diagonal(A.T) 
Out[88]: 
array([[73, 7, 89], 
     [15, 22, 91], 
     [ 5, 4, 12], 
     [24, 45, 60]]) 

In [89]: m,n = A.shape[:2] 

In [90]: A[np.arange(m)[:,None],np.eye(n,dtype=bool)] 
Out[90]: 
array([[73, 7, 89], 
     [15, 22, 91], 
     [ 5, 4, 12], 
     [24, 45, 60]]) 
2

Unter der Annahme, dass A wird ein Array mit Form (m, n, n) (dh A kann interpretiert werden als eine Sammlung von m Arrays mit Form), hier ist eine schnelle Methode, die eine Ansicht des Eingangszurückgibt:

In [14]: from numpy.lib.stride_tricks import as_strided 

In [15]: def diags(a): 
    ....:  b = as_strided(a, strides=(a.strides[0], a.strides[1]+a.strides[2]), shape=(a.shape[0], a.shape[1])) 
    ....:  return b 
    ....: 

In [16]: a 
Out[16]: 
array([[[8, 6, 6, 5], 
     [1, 0, 3, 5], 
     [8, 1, 6, 7], 
     [2, 8, 7, 1]], 

     [[0, 8, 8, 0], 
     [1, 4, 2, 4], 
     [1, 4, 5, 6], 
     [2, 5, 2, 7]], 

     [[5, 2, 5, 2], 
     [2, 5, 7, 6], 
     [6, 5, 1, 8], 
     [7, 6, 5, 8]]]) 

In [17]: diags(a) 
Out[17]: 
array([[8, 0, 6, 1], 
     [0, 4, 5, 7], 
     [5, 5, 1, 8]]) 

Wenn ich der Rückgabewert sagen ist ein Ansicht, ich meine, es bezieht sich auf den gleichen zugrunde liegenden Speicher wie die Eingabe. Wenn Sie später den Rückgabewert direkt ändern, ändert sich auch die ursprüngliche Eingabe. Zum Beispiel

In [24]: d = diags(a) 

In [25]: d[0, :] = 99 

In [26]: a[0] 
Out[26]: 
array([[99, 6, 6, 5], 
     [ 1, 99, 3, 5], 
     [ 8, 1, 99, 7], 
     [ 2, 8, 7, 99]]) 
+0

Danke, sieht ziemlich pythonisch. – dshin

+0

Mit diesem gesagt, es sieht nicht besonders sauber oder intuitiv. Gibt es einen besseren Weg? – dshin

+1

"sauber", "intuitiv", "besser" ... es hängt von Ihrer Definition dieser Wörter ab. Trotzdem, @ Divakars Antwort sieht ziemlich gut aus (wie üblich!), Insbesondere Approach # 1. Ich glaube nicht, dass Sie viel sauberer werden können. –

Verwandte Themen