[英]What is the fastest way to insert elements diagonally in 2D numpy array?
假設我們有一個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]]
最快的方法是什么?
創建一個新的更大的矩陣,剩下的空間為零。 將原始矩陣復制到子矩陣,剪輯和重塑:
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)
這是一種方式(但我不能保證這是最快的方式):
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]])
它適用於任何二維數組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]])
它有效,但我認為@Daniel的答案是要走的路。
另一種方法,可能更慢,附加和重塑
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]])
看起來你正在采用下三角形和上三角形陣列並用零對角線分開它們。 這個序列做到了:
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
一起使用。
假設你有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數組。
在此之前,我們為這個新的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 [1]。
同樣,我不知道它有多快,但您可以嘗試使用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)。 如果你從一個方陣開始,你可以不用這個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.