将一个对称矩阵(二维数组)的上/下三角部分转化为一维数组,并将其返回为二维格式。

12 人关注

In this question 它解释了如何访问一个给定矩阵的 lower upper 三角部分,例如。

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

在这里,我需要在一个一维数组中转换矩阵,这可以做的。

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

在用a做了大量的计算后,改变了它的值,它将被用来填充一个对称的二维数组。

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

Returning:

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

是否有更好的方法来完成这个任务?更具体地说,避免用Python循环来重建二维数组?

python
arrays
numpy
matrix
Saullo G. P. Castro
Saullo G. P. Castro
发布于 2013-07-08
4 个回答
seralouk
seralouk
发布于 2022-07-12
已采纳
0 人赞同

把一个向量放回二维对称数组的最快和最聪明的方法是这样做的。

情况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.array来代替numpy.matrix,上述方法也能正常使用。

情况2:有偏移(k=1),即上三角部分不包括对角线。

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.]])
    
Daniel
Daniel
发布于 2022-07-12
0 人赞同

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

m=np.array(m)
inds = np.triu_indices_from(m,k=1)
m[(inds[1], inds[0])] = m[inds]
array([[11, 12, 13],
       [12, 22, 23],
       [13, 23, 33]])

从a创建一个对称数组。

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
array([[ 11.,  12.,  13.],
       [ 12.,  22.,  23.],
       [ 13.,  23.,  33.]])
    
在返回到对称的 a 之前,我必须处理中间项阵列 2D-array
你可以操作 m[indup] ,只要它以正确的顺序返回一个1D的numpy数组。这里面有什么特别的问题吗?
a要从 array([11, 12, 13, 22, 23, 33]) 到相应的二维阵列 array([[11,12,13],[12,22,23],[13,23,33]])
你是说你想从a中获得一个对称数组吗?
只对 3x3 和更小的代码起作用
user4322543
发布于 2022-07-12
0 人赞同

你可以使用 阵列创建例程 numpy.triu , numpy.tril ,以及 numpy.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]])
    
谢谢你的提示;)
我执行了同样的步骤,但 a 变成了 array([[ 22., 12., 13.], [ 12., 44., 23.], [ 13., 23., 66.]]) 。对角线元素被加到自己身上
@Madhav,numpy可能在这个帖子后更新了np.tril和np.triu,以包括k=0时的对角线。或者我原来的回应可能只是错误的。我已经通过用np.diag减去对角线来纠正了。
jo37
jo37
发布于 2022-07-12
0 人赞同

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

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)]