numpy 将对称矩阵(2D数组)的上/下三角部分转换为1D数组,并将其返回到2D格式

lpwwtiir  于 2023-08-05  发布在  其他
关注(0)|答案(5)|浏览(110)

this question中,解释了如何访问给定矩阵的lowerupper三角部分,例如:

m = np.matrix([[11, 12, 13],
               [21, 22, 23],
               [31, 32, 33]])

字符串
在这里,我需要将矩阵转换为1D数组,可以这样做:

indices = np.triu_indices_from(m)
a = np.asarray( m[indices] )[-1]
#array([11, 12, 13, 22, 23, 33])


在对a进行大量计算,更改其值后,它将用于填充对称2D数组:

new = np.zeros(m.shape)
for i,j in enumerate(zip(*indices)):
    new[j]=a[i]
    new[j[1],j[0]]=a[i]


返回:

array([[ 11.,  12.,  13.],
       [ 12.,  22.,  23.],
       [ 13.,  23.,  33.]])


有没有更好的方法来实现这一点?更具体地说,避免Python循环来重建2D数组?

x33g5p2x

x33g5p2x1#

将向量放回2D对称数组的最快、最聪明的方法是这样做:
情况1:无偏移(k=0),即上三角形部分包括对角线

import numpy as np

X = np.array([[1,2,3],[4,5,6],[7,8,9]])
#array([[1, 2, 3],
#       [4, 5, 6],
#       [7, 8, 9]])

#get the upper triangular part of this matrix
v = X[np.triu_indices(X.shape[0], k = 0)]
print(v)
# [1 2 3 5 6 9]

# put it back into a 2D symmetric array
size_X = 3
X = np.zeros((size_X,size_X))
X[np.triu_indices(X.shape[0], k = 0)] = v
X = X + X.T - np.diag(np.diag(X))
#array([[1., 2., 3.],
#       [2., 5., 6.],
#       [3., 6., 9.]])

字符串

即使您使用numpy.matrix代替numpy.array,上述也可以正常工作。
情况2:具有偏移(k= l),即上三角形部分不包括对角线

import numpy as np

X = np.array([[1,2,3],[4,5,6],[7,8,9]])
#array([[1, 2, 3],
#       [4, 5, 6],
#       [7, 8, 9]])

#get the upper triangular part of this matrix
v = X[np.triu_indices(X.shape[0], k = 1)] # offset
print(v)
# [2 3 6]

# put it back into a 2D symmetric array
size_X = 3
X = np.zeros((size_X,size_X))
X[np.triu_indices(X.shape[0], k = 1)] = v
X = X + X.T
#array([[0., 2., 3.],
#       [2., 0., 6.],
#       [3., 6., 0.]])

34gzjxbg

34gzjxbg2#

你只是想组成一个对称的数组吗?您可以完全跳过对角线索引。

m=np.array(m)
inds = np.triu_indices_from(m,k=1)
m[(inds[1], inds[0])] = m[inds]

m

array([[11, 12, 13],
       [12, 22, 23],
       [13, 23, 33]])

字符串
从下列项目建立对称数组:

new = np.zeros((3,3))
vals = np.array([11, 12, 13, 22, 23, 33])
inds = np.triu_indices_from(new)
new[inds] = vals
new[(inds[1], inds[0])] = vals
new
array([[ 11.,  12.,  13.],
       [ 12.,  22.,  23.],
       [ 13.,  23.,  33.]])

ccrfmcuu

ccrfmcuu3#

您可以使用数组创建例程(如numpy.triunumpy.trilnumpy.diag)从三角形创建对称矩阵。这是一个简单的3x3示例。

a = np.array([[1,2,3],[4,5,6],[7,8,9]])
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

a_triu = np.triu(a, k=0)
array([[1, 2, 3],
       [0, 5, 6],
       [0, 0, 9]])

a_tril = np.tril(a, k=0)
array([[1, 0, 0],
       [4, 5, 0],
       [7, 8, 9]])

a_diag = np.diag(np.diag(a))
array([[1, 0, 0],
       [0, 5, 0],
       [0, 0, 9]])

字符串
加上转置并减去对角线:

a_sym_triu = a_triu + a_triu.T - a_diag
array([[1, 2, 3],
       [2, 5, 6],
       [3, 6, 9]])

a_sym_tril = a_tril + a_tril.T - a_diag
array([[1, 4, 7],
       [4, 5, 8],
       [7, 8, 9]])

xu3bshqb

xu3bshqb4#

比大型矩阵的公认解决方案更快:

import numpy as np
X = np.array([[1,2,3],[4,5,6],[7,8,9]])
values = X[np.triu_indices(X.shape[0], k = 0)]

X2 = np.zeros_like(X)
triu_idx = np.triu_indices_from(X2)
X2[triu_idx], X2[triu_idx[::-1]] = values, values

字符串

t3irkdon

t3irkdon5#

你可以使用SciPy中的squareform。它添加了一个零对角线,您可以按如下方式避免:

from scipy.spatial.distance import squareform

m = np.array([[1,2,3],[4,5,6],[7,8,9]])
#array([[1, 2, 3],
#       [4, 5, 6],
#       [7, 8, 9]])

a = m[np.triu_indices(m.shape[0], k = 0)]
# [1 2 3 5 6 9]

m_p = squareform(a) #with zero diagonal
#array([[0, 1, 2, 3],
#      [1, 0, 5, 6],
#      [2, 5, 0, 9],
#      [3, 6, 9, 0]])

#Get indices of diagonal inside a:
diag_ind = np.cumsum(np.insert(np.arange(m.shape[0], 1, -1),0,0))

#Get squareform of array without diagonal elements 
#then replace the zeros with the diagonal elements
m_pp = squareform(np.delete(a, diag_ind))
np.fill_diagonal(m_pp, a[diag_ind])

#m_pp = array([[1, 2, 3],
#      [2, 5, 6],
#      [3, 6, 9]])

字符串
通过从形状值开始的倒计数的累积和获得索引,其中预先插入零以包括第零个元素。

相关问题