pythonnumpy

Python matrix diagonal of inf without fill_diagonal


I need to set the diagonal elements of a matrix to Inf.

An easy way to do it is to use np.fill_diagonal.

np.fill_diagonal(my_matrix, float('inf')

However fill_diagonal modifies the input matrix instead of returning a new matrix with the diagonal filled. This doesn't work for me. I need the diagonals filled WITHOUT modifying the original matrix.

Of course I could clone the original matrix, so I will always keep a copy of the original matrix. However I don't really like this solution, since I will update my original matrix often and therefore I'll have to make copies of it every time I need the diagonal to be inf.

Is there a function that will do the same that fill_diagonal but without modifying the input matrix? Something like:

new_matrix = np.fill_diagonal(original_matrix, float('inf') 

Why I need this:

My matrix is a distance matrix between points and I want to compute at each step the two closest points. Of course the diagonal of this matrix is 0 (since the distance from a point to itself is 0). So my solution to make sure I don't take the same point is to set the diagonals to Inf.

However once the two points are found, I need to compute the average of the distances between this two points and the rest of the points, so I actually need the diagonals to be 0 instead of Inf.

Currently what I'm doing is:

However I don't like the idea of setting diagonals to Inf and then back to 0, I would prefer just passing a function to argmax that returns data with diagonal filled with Inf without actually modifying the matrix data.

Something like:

idx = np.argmin(return_filled_diagonals(data, float('Inf'))
# here I can operate with data as usual since it has not been modified.

Solution

  • orig_mat = np.array([[1.2,2,3],[4,5,6],[7,8,9]])
    
    #set diagonal to inf without making a copy of the array.
    orig_mat + np.where(np.eye(orig_mat.shape[0])>0,np.inf,0)
    array([[ inf,   2.,   3.],
           [  4.,  inf,   6.],
           [  7.,   8.,  inf]])
    
    #the original array remains untorched.
    print(orig_mat)
    [[ 1.2  2.   3. ]
     [ 4.   5.   6. ]
     [ 7.   8.   9. ]]