50
       iluropoda_melanoleuca  bos_taurus  callithrix_jacchus  canis_familiaris
ailuropoda_melanoleuca     0        84.6                97.4                44
bos_taurus                 0           0                97.4              84.6
callithrix_jacchus         0           0                   0              97.4
canis_familiaris           0           0                   0                 0

This is a short version of the python matrix I have. I have the information in the upper triangle. Is there an easy function to copy the upper triangle to the down triangle of the matrix?

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
biojl
  • 1,060
  • 1
  • 8
  • 26

6 Answers6

71

To do this in NumPy, without using a double loop, you can use tril_indices. Note that depending on your matrix size, this may be slower that adding the transpose and subtracting the diagonal though perhaps this method is more readable.

>>> i_lower = np.tril_indices(n, -1)
>>> matrix[i_lower] = matrix.T[i_lower]  # make the matrix symmetric

Be careful that you do not try to mix tril_indices and triu_indices as they both use row major indexing, i.e., this does not work:

>>> i_upper = np.triu_indices(n, 1)
>>> i_lower = np.tril_indices(n, -1)
>>> matrix[i_lower] = matrix[i_upper]  # make the matrix symmetric
>>> np.allclose(matrix.T, matrix)
False
Steven C. Howell
  • 16,902
  • 15
  • 72
  • 97
46

The easiest AND FASTEST (no loop) way to do this for NumPy arrays is the following:

The following is ~3x faster for 100x100 matrices compared to the accepted answer and roughly the same speed for 10x10 matrices.

import numpy as np

X= np.array([[0., 2., 3.],
             [0., 0., 6.],
             [0., 0., 0.]])

X = X + X.T - np.diag(np.diag(X))
print(X)

#array([[0., 2., 3.],
#       [2., 0., 6.],
#       [3., 6., 0.]])

Note that the matrix must either be upper triangular to begin with or it should be made upper triangular as follows.

rng = np.random.RandomState(123)
X = rng.randomint(10, size=(3, 3))
print(X)
#array([[2, 2, 6],
#       [1, 3, 9],
#       [6, 1, 0]])

X = np.triu(X)
X = X + X.T - np.diag(np.diag(X))
print(X)
#array([[2, 2, 6],
#       [2, 3, 9],
#       [6, 9, 0]])

seralouk
  • 30,938
  • 9
  • 118
  • 133
  • 9
    Yes, this works and is faster for large matrices. For 100x100 I get between 3x to 4x faster, but 10x10 I get the same times. An important caveat is this only works if the lower half of the matrix is all zero (as in the OP's question). If for some reason the lower half is not all zeros, you need to include `X = np.triu(X)` before adding the transpose and subtracting the diagonal back off, in which case this was ~2x slower for 10x10, but still ~1.5x faster for 100x100. – Steven C. Howell Jul 22 '20 at 19:49
  • Hi @seralouk, appreciate if you can provide some suggestion in this thread: https://stackoverflow.com/q/65051653/6446053 – mpx Nov 28 '20 at 16:10
7

If I understand the question correctly, I believe this will work

for i in range(num_rows):
    for j in range(i, num_cols):
        matrix[j][i] = matrix[i][j]
A.E. Drew
  • 2,097
  • 1
  • 16
  • 24
3

Heres a better one i guess :

>>> a = np.arange(16).reshape(4, 4)
>>> print(a)
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

>>> iu = np.triu_indices(4,1)
>>> il = (iu[1],iu[0])
>>> a[il]=a[iu]
>>> a
    array([[ 0,  1,  2,  3],
           [ 1,  5,  6,  7],
           [ 2,  6, 10, 11],
           [ 3,  7, 11, 15]])
Satyam
  • 39
  • 5
3

If U is an upper triangular matrix, you can use triu and transpose to make it symmetric:

LDU = triu(U,1)+U.T
Yelrew
  • 31
  • 1
  • 3
0
def inmatrix(m,n):#input Matrix Function 
    a=[]

    for i in range(m):

        b=[]

        for j in range(n):

            elm=int(input("Enter number in Pocket ["+str(i)+"]["+str(j)+"] "))

            b.append(elm)

        a.append(b)

    return  a

def Matrix(a):#print Matrix Function

    for i in range(len(a)):

        for j in range(len(a[0])):

            print(a[i][j],end=" ")

        print()
m=int(input("Enter number of row "))

n=int(input("Enter number of column"))

a=inmatrix(m,n) #call input Matrix function

Matrix(a)#print Matrix 

t=[]#create Blank list 

for i in range(m):

    for j in range(n):

        if i>j:#check upper triangular Elements 

            t.append(a[i][j])#add them in a list 

k=0#variable for list 

for i in range(m):

    for j in range(n):

        if i<j:

            a[i][j]=t[k]copy list item to lower triangular 

            k=k+1

Matrix(a)# print Matrix after change 
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Sanjay Rai
  • 27
  • 3