2016-01-06 84 views
2

假設我們有一個像2D numpy的數組:什麼是在2D numpy數組中對角插入元素的最快方法?

matrix = [[1, 2, 3], 
      [4, 5, 6], 
      [7, 8, 9], 
      [10, 11, 12]] 

我想插入值0說這樣對角,它變成了:

matrix = [[0, 1, 2, 3], 
      [4, 0, 5, 6], 
      [7, 8, 0, 9], 
      [10, 11, 12, 0]] 

什麼是做到這一點的最快的方法?

+2

形狀總是'(4,3)'?有什麼限制嗎?如果您嘗試在形狀爲((3,4))的陣列中插入對角線,您想要什麼? – mgilson

+0

原始形狀總是像這樣(n + 1,n),其中n> 0,但我更喜歡如果答案也適用於(n,n)。 –

+0

我會創建一個新的數組(零),並使用'np.tri ...'函數將舊數組的上下三角形複製到新數組中。 – hpaulj

回答

3

創建一個新的更大的矩陣,剩下零空間。原來矩陣複製到一個子矩陣,剪輯,重塑:

matrix = numpy.array([[1, 2, 3], 
      [4, 5, 6], 
      [7, 8, 9], 
      [10, 11, 12]]) 

matrix_new = numpy.zeros((4,5)) 
matrix_new[:-1,1:] = matrix.reshape(3,4) 
matrix_new = matrix_new.reshape(-1)[:-4].reshape(4,4) 

或更廣義的形式:

matrix = numpy.array([[1, 2, 3], 
      [4, 5, 6], 
      [7, 8, 9], 
      [10, 11, 12]]) 

d = matrix.shape[0] 
assert matrix.shape[1] == d - 1 
matrix_new = numpy.ndarray((d, d+1), dtype=matrix.dtype) 
matrix_new[:,0] = 0 
matrix_new[:-1,1:] = matrix.reshape((d-1, d)) 
matrix_new = matrix_new.reshape(-1)[:-d].reshape(d,d) 
3

這裏有一種方法(但我不能保證,這是最快的方法) :

In [62]: a 
Out[62]: 
array([[ 1, 2, 3], 
     [ 4, 5, 6], 
     [ 7, 8, 9], 
     [10, 11, 12]]) 

In [63]: b = np.zeros((a.shape[0], a.shape[1]+1), dtype=a.dtype) 

In [64]: i = np.arange(b.shape[0]) 

In [65]: j = np.arange(b.shape[1]) 

In [66]: b[np.not_equal.outer(i, j)] = a.ravel() # or a.flat, if a is C-contiguous 

In [67]: b 
Out[67]: 
array([[ 0, 1, 2, 3], 
     [ 4, 0, 5, 6], 
     [ 7, 8, 0, 9], 
     [10, 11, 12, 0]]) 

它適用於任何2-d陣列a

In [72]: a 
Out[72]: 
array([[17, 18, 15, 19, 12], 
     [16, 14, 11, 16, 17], 
     [19, 11, 16, 11, 14]]) 

In [73]: b = np.zeros((a.shape[0], a.shape[1]+1), dtype=a.dtype) 

In [74]: i = np.arange(b.shape[0]) 

In [75]: j = np.arange(b.shape[1]) 

In [76]: b[np.not_equal.outer(i, j)] = a.flat 

In [77]: b 
Out[77]: 
array([[ 0, 17, 18, 15, 19, 12], 
     [16, 0, 14, 11, 16, 17], 
     [19, 11, 0, 16, 11, 14]]) 

它有效,但我認爲@丹尼爾的答案是要走的路。

+1

你可以用'〜np.eye(* b.shape,dtype = np.bool)替換'np.not_equal.outer(i,j)' –

1

另一種方法,可能速度較慢,與追加和重塑

import numpy as np 

mat = np.array(range(1,13)).reshape(4,3) 
mat 

array([[ 1, 2, 3], 
     [ 4, 5, 6], 
     [ 7, 8, 9], 
     [10, 11, 12]]) 

z=np.zeros((3,1), dtype=mat.dtype) 
m3=np.append(z,mat.reshape(3,4),1) 
np.append(m3,0).reshape(4,4) 

array([[ 0, 1, 2, 3], 
     [ 4, 0, 5, 6], 
     [ 7, 8, 0, 9], 
     [10, 11, 12, 0]]) 
+0

即將發佈的內容非常接近這個!尼斯想到這裏。另外,看看使用'np.hstack'和'np.concatenate'是否有助於提升性能。 – Divakar

0

同樣,我不知道它是多麼快,但你可以嘗試使用numpy.lib.stride_tricks.as_strided

import numpy as np 
as_strided = np.lib.stride_tricks.as_strided 

matrix = (np.arange(12)+1).reshape((4,3)) 

n, m = matrix.shape 
t = matrix.reshape((m, n)) 
t = np.hstack((np.array([[0]*m]).T, t)) 
t = np.vstack((t, [0]*(n+1))) 
q = as_strided(t, (n,n), (t.itemsize*n, 8)) 
print(q) 

輸出:

[[ 0 1 2 3] 
[ 4 0 5 6] 
[ 7 8 0 9] 
[10 11 12 0]] 

也就是說,用零重新填充重構陣列的左和底部並跨步到將左手零點放在對角線上。不幸的是,在(n+1,n)數組的情況下(因爲例如5 * 3 = 15小於4 * 4 = 16),您需要底部一行零以獲得輸出矩陣中的最終零。如果你以方矩陣開始,你可以不用這個。

1

看起來你正在採取下三角陣和上三角陣,並用零對角線分隔它們。該序列確實是:

In [54]: A=np.arange(1,13).reshape(4,3) 

目標陣列,具有一個多個列

In [55]: B=np.zeros((A.shape[0],A.shape[1]+1),dtype=A.dtype) 

複印在下部三(沒有對角線)

In [56]: B[:,:-1]+=np.tril(A,-1) 

複印上三

In [57]: B[:,1:]+=np.triu(A,0) 

In [58]: B 
Out[58]: 
array([[ 0, 1, 2, 3], 
     [ 4, 0, 5, 6], 
     [ 7, 8, 0, 9], 
     [10, 11, 12, 0]]) 

有一些np.tril_indices...函數,但它們只能用於方陣。所以他們不能與A一起使用。

1

比方說你有apxq numpy的2D陣列A,這裏是與(P,Q)作爲樣品(3,4):

In []: A = np.arange(1,13).reshape(4,3) 
In []: A 
Out[]: 
array([[ 1, 2, 3], 
     [ 4, 5, 6], 
     [ 7, 8, 9], 
     [10, 11, 12]]) 

Step 1:

要插入對角線零,它需要製作一個新的形狀爲px q + 1的二維數組。

在此之前,我們創建與非對角線元素的列索引值的2D陣列的新的二維陣列是這樣

In []: columnIndexArray = np.delete(np.meshgrid(np.arange(q+1), np.arange(p))[0], np.arange(0, p * (q+1), q+2)).reshape(p,q) 

的輸出上述將如下所示:

In []: columnIndexArray 
Out[]: 
array([[1, 2, 3], 
     [0, 2, 3], 
     [0, 1, 3], 
     [0, 1, 2]]) 

Step 2:

現在構造PX q + 1個2d中的零的這樣

陣列
In []: B = np.zeros((p,q+1)) 

In []: B 
Out[]: 
array([[ 0., 0., 0., 0.], 
     [ 0., 0., 0., 0.], 
     [ 0., 0., 0., 0.], 
     [ 0., 0., 0., 0.]]) 

Step 3:

現在從A

In []: B[np.arange(p)[:,None], columnIndexArray] = A 

In []: B 
Out[]: 
array([[ 0., 1., 2., 3.], 
     [ 4., 0., 5., 6.], 
     [ 7., 8., 0., 9.], 
     [ 10., 11., 12., 0.]]) 

Note: 分配與所述值的非對角元素要使代碼動態與A.shape [0]和q與A.shape替換p [1]。

相關問題