簡體   English   中英

在2D numpy數組中對角插入元素的最快方法是什么?

[英]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.

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