2017-05-02 2 views
6

ich eine numpy Array wie dieseErstellen Sie eine Matrix aus einem Vektor, wobei jede Zeile eine verschobene Version des Vektors ist

import numpy as np 

ar = np.array([1, 2, 3, 4]) 

und ich möchte ein Array erstellen, die wie folgt aussieht:

array([[4, 1, 2, 3], 
     [3, 4, 1, 2], 
     [2, 3, 4, 1], 
     [1, 2, 3, 4]]) 

Dabei entspricht jede Zeile ar, die durch den Zeilenindex verschoben + 1.

Eine einfache Implementierung könnte wie folgt aussehen:

012.
ar_roll = np.tile(ar, ar.shape[0]).reshape(ar.shape[0], ar.shape[0]) 

for indi, ri in enumerate(ar_roll): 
    ar_roll[indi, :] = np.roll(ri, indi + 1) 

was mir die gewünschte Ausgabe gibt.

Meine Frage ist, ob es eine klügere Möglichkeit gibt, dies zu tun, die die Schleife vermeidet.

Antwort

5

Hier ist ein Ansatz NumPy strides grundsätzlich mit den übrig gebliebenen Elemente Klotzen und dann die strides uns bei der Erstellung helfen, die Version ziemlich effizient verschoben -

def strided_method(ar): 
    a = np.concatenate((ar, ar[:-1])) 
    L = len(ar) 
    n = a.strides[0] 
    return np.lib.stride_tricks.as_strided(a[L-1:], (L,L), (-n,n)) 

Beispielläufe -

In [42]: ar = np.array([1, 2, 3, 4]) 

In [43]: strided_method(ar) 
Out[43]: 
array([[4, 1, 2, 3], 
     [3, 4, 1, 2], 
     [2, 3, 4, 1], 
     [1, 2, 3, 4]]) 

In [44]: ar = np.array([4,9,3,6,1,2]) 

In [45]: strided_method(ar) 
Out[45]: 
array([[2, 4, 9, 3, 6, 1], 
     [1, 2, 4, 9, 3, 6], 
     [6, 1, 2, 4, 9, 3], 
     [3, 6, 1, 2, 4, 9], 
     [9, 3, 6, 1, 2, 4], 
     [4, 9, 3, 6, 1, 2]]) 

Runtime Test -

In [5]: a = np.random.randint(0,9,(1000)) 

# @Eric's soln 
In [6]: %timeit roll_matrix(a) 
100 loops, best of 3: 3.39 ms per loop 

# @Warren Weckesser's soln 
In [8]: %timeit circulant(a[::-1]) 
100 loops, best of 3: 2.03 ms per loop 

# Strides method 
In [18]: %timeit strided_method(a) 
100000 loops, best of 3: 6.7 µs per loop 

Eine Kopie erstellen (wenn Sie Änderungen vornehmen möchten) s und nicht nur die Verwendung als Nur-Lese-Array) wird uns nicht verletzen schlecht für die strides Methode -

In [19]: %timeit strided_method(a).copy() 
1000 loops, best of 3: 381 µs per loop 
+0

Das verwendet weniger Speicher als meine Lösung, aber die Ausgabe ist nicht sicher beschreibbar. Ich bezweifle jedoch, dass das ein Problem ist, dies die bessere Lösung zu machen – Eric

+0

Funktioniert gut, danke (upvoted)! – Cleb

+0

@Eric: Was meinst du mit "nicht sicher beschreibbar"? – Cleb

3

Hier ist ein Ansatz

def roll_matrix(vec): 
    N = len(vec) 
    buffer = np.zeros((N, N*2 - 1)) 

    # generate a wider array that we want a slice into 
    buffer[:,:N] = vec 
    buffer[:,N:] = vec[:-1] 

    rolled = buffer.reshape(-1)[N-1:-1].reshape(N, -1) 
    return rolled[:,:N] 

In Ihrem Fall, wir buffer bauen

array([[ 1., 2., 3., 4., 1., 2., 3.], 
     [ 1., 2., 3., 4., 1., 2., 3.], 
     [ 1., 2., 3., 4., 1., 2., 3.], 
     [ 1., 2., 3., 4., 1., 2., 3.]]) 

Dann glätten Sie es sein, es schneiden, umformen es rolled zu erhalten:

array([[ 4., 1., 2., 3., 1., 2.], 
     [ 3., 4., 1., 2., 3., 1.], 
     [ 2., 3., 4., 1., 2., 3.], 
     [ 1., 2., 3., 4., 1., 2.]]) 

Und schließlich, schneiden Sie den Müll letzte Reihen

+0

funktioniert gut, danke (upvoted)! – Cleb

3

Beide der vorhandenen Antworten sind in Ordnung; Diese Antwort ist wahrscheinlich nur von Interesse, wenn Sie bereits scipy verwenden.

Die Matrix, die Sie beschreiben, ist als circulant matrix bekannt. Wenn Sie nicht die Abhängigkeit von scipy dagegen, Sie scipy.linalg.circulant verwenden können zu erstellen:

In [136]: from scipy.linalg import circulant 

In [137]: ar = np.array([1, 2, 3, 4]) 

In [138]: circulant(ar[::-1]) 
Out[138]: 
array([[4, 1, 2, 3], 
     [3, 4, 1, 2], 
     [2, 3, 4, 1], 
     [1, 2, 3, 4]]) 
+0

Ich benutze scipy, so dass die Antwort sehr hilfreich ist, da sie auch die lesbarste ist (upvoted). Was die Geschwindigkeit anbelangt, scheint es weniger effizient zu sein, aber es ist großartig, dass es dafür bereits eine eingebaute Lösung gibt! – Cleb

+0

Sieht so aus, als wäre scipy einen Patch wert, um die schnellere Implementierung von Divakar zu nutzen. Sie können die scipy Implementierung sehen [hier] (https://github.com/scipy/scipy/blob/v0.19.0/scipy/linalg/special_matrices.py#L206-L243) – Eric

+0

@Eric Gute Idee! Scipy könnte mit Sicherheit einige Tricks machen! – Divakar

Verwandte Themen