NumPy:沿矩阵对角线构造正方形/扩展对角矩阵

Sum*_*ron 17 python arrays numpy matrix

假设您有两个数组:

index = [1, 2, 3]
counts = [2, 3, 2]
Run Code Online (Sandbox Code Playgroud)

或奇异数组

arr = [1, 1, 2, 2, 2, 3, 3]
Run Code Online (Sandbox Code Playgroud)

如何有效构建矩阵

[
  [1, 1, 0, 0, 0, 0, 0],
  [1, 1, 0, 0, 0, 0, 0],
  [0, 0, 2, 2, 2, 0, 0],
  [0, 0, 2, 2, 2, 0, 0],
  [0, 0, 2, 2, 2, 0, 0],
  [0, 0, 0, 0, 0, 3, 3],
  [0, 0, 0, 0, 0, 3, 3]
]
Run Code Online (Sandbox Code Playgroud)

与 NumPy?

我知道

square = np.zeros((7, 7))
np.fill_diagnol(square, arr) # see arr above
Run Code Online (Sandbox Code Playgroud)

产生

[
  [1, 0, 0, 0, 0, 0, 0],
  [0, 1, 0, 0, 0, 0, 0],
  [0, 0, 2, 0, 0, 0, 0],
  [0, 0, 0, 2, 0, 0, 0],
  [0, 0, 0, 0, 2, 0, 0],
  [0, 0, 0, 0, 0, 3, 0],
  [0, 0, 0, 0, 0, 0, 3]
]
Run Code Online (Sandbox Code Playgroud)

对于n由指定的值,如何“扩展”对角线ncounts[index-1]index[I]

tmp = np.array((arr * N)).reshape((len(arr), len(arr)) 
np.floor( (tmp + tmp.T) / 2 ) # <-- this is closer


array([[1., 1., 1., 1., 1., 2., 2.],
       [1., 1., 1., 1., 1., 2., 2.],
       [1., 1., 2., 2., 2., 2., 2.],
       [1., 1., 2., 2., 2., 2., 2.],
       [1., 1., 2., 2., 2., 2., 2.],
       [2., 2., 2., 2., 2., 3., 3.],
       [2., 2., 2., 2., 2., 3., 3.]])
Run Code Online (Sandbox Code Playgroud)

这得到了我想要的,但可能无法很好地扩展?

riffled = list(zip(index, counts))
riffled
# [(1, 2), (2, 3), (3, 2)]
Run Code Online (Sandbox Code Playgroud)
a = np.zeros((len(arr), len(arr))) # 7, 7 square
last = 0 # <-- keep track of current sub square
for i, c in riffled:
    a[last:last+c, last:last+c] = np.ones((c, c)) * i 
    last += c # <-- shift square

Run Code Online (Sandbox Code Playgroud)

屈服

array([[1., 1., 0., 0., 0., 0., 0.],
       [1., 1., 0., 0., 0., 0., 0.],
       [0., 0., 2., 2., 2., 0., 0.],
       [0., 0., 2., 2., 2., 0., 0.],
       [0., 0., 2., 2., 2., 0., 0.],
       [0., 0., 0., 0., 0., 3., 3.],
       [0., 0., 0., 0., 0., 3., 3.]])
Run Code Online (Sandbox Code Playgroud)

小智 10

您可以使用 scipy.linalg.block_diag 来完成该工作:

import numpy as np
import scipy.linalg as linalg


a = 1*np.ones((2,2))
b = 2*np.ones((3,3))
c = 3*np.ones((2,2))

superBlock = linalg.block_diag(a,b,c)

print(superBlock)

#returns
#[[1. 1. 0. 0. 0. 0. 0.]
# [1. 1. 0. 0. 0. 0. 0.]
# [0. 0. 2. 2. 2. 0. 0.]
# [0. 0. 2. 2. 2. 0. 0.]
# [0. 0. 2. 2. 2. 0. 0.]
# [0. 0. 0. 0. 0. 3. 3.]
# [0. 0. 0. 0. 0. 3. 3.]]
Run Code Online (Sandbox Code Playgroud)

如果你想从值列表和计数列表中到达那里,你可以这样做:

values = [1,2,3]
counts = [2,3,2]

mats = []
for v,c in zip(values,counts):
    thisMatrix = v*np.ones((c,c))
    mats.append( thisMatrix )


superBlock = linalg.block_diag(*mats)


print(superBlock)
Run Code Online (Sandbox Code Playgroud)

  • 如果用户在此创建步骤之后只需要使用密集矩阵,那么这是完美的。但是,如果所有数据都可以像示例一样稀疏地描述,那么使用稀疏版本也可能有一些好处:scipy.sparse.block_diag https://docs.scipy.org/doc/scipy/reference/ generated/scipy .sparse.block_diag.html#scipy.sparse.block_diag (2认同)

Qua*_*ang 3

尝试广播:

idx = np.repeat(np.arange(len(counts)), counts)
np.where(idx==idx[:,None], arr, 0)
# or
# arr * (idx==idx[:,None])
Run Code Online (Sandbox Code Playgroud)

输出;

array([[1, 1, 0, 0, 0, 0, 0],
       [1, 1, 0, 0, 0, 0, 0],
       [0, 0, 2, 2, 2, 0, 0],
       [0, 0, 2, 2, 2, 0, 0],
       [0, 0, 2, 2, 2, 0, 0],
       [0, 0, 0, 0, 0, 3, 3],
       [0, 0, 0, 0, 0, 3, 3]])
Run Code Online (Sandbox Code Playgroud)

  • 这样可行!请读者注意,所涉及的“arr”是一个 Python 列表,因此要使其工作,请通过“np.array(arr)”将其转换为 numpy (3认同)