简体   繁体   中英

Making a numpy ndarray matrix symmetric

I have a 70x70 numpy ndarray, which is mainly diagonal. The only off-diagonal values are the below the diagonal. I would like to make the matrix symmetric.

As a newcomer from Matlab world, I can't get it working without for loops. In MATLAB it was easy:

W = max(A,A')

where A' is matrix transposition and the max() function takes care to make the W matrix which will be symmetric.

Is there an elegant way to do so in Python as well?

EXAMPLE The sample A matrix is:

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

The desired output matrix W is:

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

Found a following solution which works for me:

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

For what it is worth, using the MATLAB's numpy equivalent you mentioned is more efficient than the link @plonser added.

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

Timing for larger matrices can be done similarly:

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

And with 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

Use the NumPy tril and triu functions as follows. It essentially "mirrors" elements in the lower triangle into the upper triangle.

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) gets the lower triangle of a matrix m (returns a copy of the matrix m with all elements above the k th diagonal zeroed). Similarly, triu(m, k=0) gets the upper triangle of a matrix m (all elements below the k th diagonal zeroed).

To prevent the diagonal being added twice, one must exclude the diagonal from one of the triangles, using either np.tril(A) + np.triu(AT, 1) or np.tril(A, -1) + np.triu(AT) .

Also note that this behaves slightly differently to using maximum . All elements in the upper triangle are overwritten, regardless of whether they are the maximum or not. This means they can be any value (eg nan or inf ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM