簡體   English   中英

從向量創建矩陣,其中每行是向量的移位版本

[英]Create a matrix from a vector where each row is a shifted version of the vector

我有一個像這樣的numpy數組

import numpy as np

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

我想創建一個如下所示的數組:

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

因此,每行對應於移位了行索引+ 1的ar

簡單的實現可能如下所示:

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)

這給了我想要的輸出。

我的問題是,是否有一種更聰明的方法來避免循環。

這里有一種方法,使用NumPy strides基本上用剩余元素填充,然后strides幫助我們非常有效地創建移位版本 -

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))

樣品運行 -

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]])

運行時測試 -

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

制作副本(如果你想進行更改而不只是用作只讀數組)不會對strides方法造成太大的傷害 -

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

這是一種方法

def roll_matrix(vec):
    N = len(vec)
    buffer = np.empty((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]

在您的情況下,我們構建buffer

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.]])

然后壓扁它,修剪它,重新塑造它以使其rolled

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.]])

最后,切掉最后一列的垃圾

兩個現有的答案都很好; 如果您已經使用scipy,那么這個答案可能只是有意義的。

您描述的矩陣稱為循環矩陣 如果您不介意對scipy的依賴,可以使用scipy.linalg.circulant創建一個:

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]])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM