使一个numpy ndarray矩阵对称化

22

我有一个大小为70x70的numpy ndarray,主要是对角线矩阵。唯一非对角线上的值在对角线下方。我想把这个矩阵变成对称矩阵。

作为一个从Matlab世界来的新手,我无法在不使用for循环的情况下使它工作。在MATLAB中这很容易:

W = max(A,A')

其中A'表示矩阵的转置,max()函数会确保生成对称的W矩阵。

在Python中是否有一种优雅的方式实现这一点呢?

例如,给定一个样例矩阵A

1 0 0 0
0 2 0 0
1 0 2 0
0 1 0 3

期望的输出矩阵W是:

1 0 1 0
0 2 0 1
1 0 2 0
0 1 0 3

1
答案在这里回答:https://dev59.com/xHE85IYBdhLWcg3w3Xhp#2573982 - plonser
3个回答

37

我找到了以下解决方案,适用于我:

import numpy as np
W = np.maximum( A, A.transpose() )

2
问题在于,如果您的矩阵“A”很大,那么这会浪费很多空间,因为我想它会创建第二个矩阵,对吗? - Radio Controlled
1
如果您尝试镜像的非对角线元素为负数,那么这将无法工作,不是吗? - davewy
当处理负系数时,您只需执行 W = (A + A.transpose()) / 2 - alexis_thual

12

使用NumPy的triltriu函数,按如下方式操作。它将下三角中的元素“镜像”到上三角。

import numpy as np
A = np.array([[1, 0, 0, 0], [0, 2, 0, 0], [1, 0, 2, 0], [0, 1, 0, 3]])
W = np.tril(A) + np.triu(A.T, 1)

tril(m, k=0)函数获取矩阵m的下三角(返回一个所有在第k条对角线上方元素被清零的矩阵m副本)。类似地,triu(m, k=0)函数获取矩阵m的上三角(所有在第k条对角线下方的元素被清零)。

为了避免对角线加入两次,必须从其中一个三角形中排除对角线,使用 np.tril(A) + np.triu(A.T, 1) 或者 np.tril(A, -1) + np.triu(A.T)

还要注意,这与使用maximum的行为略有不同。所有在上三角中的元素都会被覆盖,无论它们是否是最大值。这意味着它们可以是任何值(例如naninf)。


3

就我所知,使用你提到的 MATLAB 的 numpy 相当于 @plonser 添加的 link 更加高效。

In [1]: import numpy as np
In [2]: A = np.zeros((4, 4))
In [3]: np.fill_diagonal(A, np.arange(4)+1)
In [4]: A[2:,:2] = np.eye(2)

# numpy equivalent to MATLAB:
In [5]: %timeit W = np.maximum( A, A.T)
100000 loops, best of 3: 2.95 µs per loop

# method from link
In [6]: %timeit W = A + A.T - np.diag(A.diagonal())
100000 loops, best of 3: 9.88 µs per loop

对于较大的矩阵,可以采用类似的计时方法:

In [1]: import numpy as np
In [2]: N = 100
In [3]: A = np.zeros((N, N))
In [4]: A[2:,:N-2] = np.eye(N-2)
In [5]: np.fill_diagonal(A, np.arange(N)+1)
In [6]: print A
Out[6]: 
array([[   1.,    0.,    0., ...,    0.,    0.,    0.],
       [   0.,    2.,    0., ...,    0.,    0.,    0.],
       [   1.,    0.,    3., ...,    0.,    0.,    0.],
       ..., 
       [   0.,    0.,    0., ...,   98.,    0.,    0.],
       [   0.,    0.,    0., ...,    0.,   99.,    0.],
       [   0.,    0.,    0., ...,    1.,    0.,  100.]])

# numpy equivalent to MATLAB:
In [6]: %timeit W = np.maximum( A, A.T)
10000 loops, best of 3: 28.6 µs per loop

# method from link
In [7]: %timeit W = A + A.T - np.diag(A.diagonal())
10000 loops, best of 3: 49.8 µs per loop

当 N = 1000 时

# numpy equivalent to MATLAB:
In [6]: %timeit W = np.maximum( A, A.T)
100 loops, best of 3: 5.65 ms per loop

# method from link
In [7]: %timeit W = A + A.T - np.diag(A.diagonal())
100 loops, best of 3: 11.7 ms per loop

大约是3倍。对于更大的矩阵,比如100x100或1000x1000,是否也成立? - Vladislavs Dovgalecs
@xeon 我为你提到的尺寸添加了时间。这些时间是在我的机器上测试的,可能会因人而异。 ~2x 的差异来自于执行的操作数量。两者都使用 numpy 对象和 numpy 方法。与 MATLAB 类似,numpy 旨在优化矩阵运算,因此 numpy 方法通常是最有效的。 - Steven C. Howell
我将A.transpose()替换为A.T以指出它们是相同的,但后者需要更少的键入(http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.T.html)。 - Steven C. Howell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接