Transforming a list containing the elements below the diagonal of a matrix into a full matrix

2.2k views Asked by At

I want to create a full-fledged matrix from a list of the elements that are below the diagonal. The following list contains the elements below the diagonal: enter image description here

And this would be the desired output:

enter image description here

Up until this point, I tried to make this work with normal sintax in python by implementing the following code:

list_similarities = [1,0.1,0.6,0.4,1,0.1,0.2,1,0.7,1]

the_range = range(0,4)

list_of_lists = []
counter_element = 0
counter = -1
for element in the_range:
    counter += 1
    counter_element += len(the_range)-element
    intermediary = (len(the_range)-element)
    first_element = counter_element-intermediary
    line_list = list_similarities[first_element:counter_element]
    # counter = 0, then no need to add an additional element
    # print(line_list)
    if counter == 0:
        "do nothing"
    elif counter >0:
        for item in range(0,element):
            from_list_to_add = list_of_lists[item]
            element_to_add = from_list_to_add[item+1]
            line_list.insert(0,element_to_add)
    print(line_list)
    list_of_lists.append(line_list.copy())
    # print("final lists:", list_of_lists)


# print(counter_element)
print("final lists:", list_of_lists)

However, the output is the following:

final lists: [[1, 0.1, 0.6, 0.4], [0.1, 1, 0.1, 0.2], [0.1, 0.1, 1, 0.7], [0.7, 0.1, 0.1, 1]]

It does the first 2 lists, which represent the 2 rows from the matrix, but will not do the last 2 because of the way my code works and so far I don't know a solution for that..

This is due to the fact that my counter will make the list go out of range. I looked at a lot of posts on the stack overflow, but I cannot find something that would work in my situation. If you can point me towards a similar example it would be perfect.

Thank you for your time and suggestions!

UPDATE : My question is not a duplicate of Numpy: convert an array to a triangular matrix because I do not want to create a matrix where my values from the array are part of just the lower triangular matrix, but rather they are also in the upper triangular matrix.

2

There are 2 answers

2
b-fg On BEST ANSWER

A solution using numpy.triu_indices and numpy.tril_indices. I have guided each step with comments. The key is to first find the upper right indices, assign the value from the list, then make the matrix symmetric.

import numpy as np

n = 4
l = [1,0.1,0.6,0.4,1,0.1,0.2,1,0.7,1]

a = np.zeros((n,n)) # Initialize nxn matrix
triu = np.triu_indices(n) # Find upper right indices of a triangular nxn matrix
tril = np.tril_indices(n, -1) # Find lower left indices of a triangular nxn matrix
a[triu] = l # Assign list values to upper right matrix
a[tril] = a.T[tril] # Make the matrix symmetric

print(a)

Output

[[1.  0.1 0.6 0.4]
 [0.1 1.  0.1 0.2]
 [0.6 0.1 1.  0.7]
 [0.4 0.2 0.7 1. ]]
1
seralouk On

Its very simple using numpy.triu_indices_from.

Use this:

import numpy as np

list_similarities = [1,0.1,0.6,0.4,1,0.1,0.2,1,0.7,1]
n = 4

Full_matrix = np.zeros((n,n))
inds = np.triu_indices_from(Full_matrix, k = 0)
# use [:] to copy the list and avoid any problem if the initial list is further needed
Full_matrix[inds] = list_similarities[:]
Full_matrix[(inds[1], inds[0])] = list_similarities[:]

Results

array([[1. , 0.1, 0.6, 0.4],
       [0.1, 1. , 0.1, 0.2],
       [0.6, 0.1, 1. , 0.7],
       [0.4, 0.2, 0.7, 1. ]])

P.S: More details about the reason I copy the list using list_similarities[:] here