Search code examples
pythontruncatesvdtruncation

Truncating a 2D array for a given tolerance [Python]


An old question on Singular Value Decomposition lead me to ask this question: How could I truncate a 2-Dimensional array, to a number of columns dictated by a certain tolerance?

Specifically, please consider the following code snippet, which defines an accepted tolerance of 1e-4 and applies Singular Value Decomposition to a matrix 'A'.

#Python
tol=1e-4
U,Sa,V=np.linalg.svd(A)
S=np.diag(Sa)

The resulting singular value diagonal matrix 'S' holds non-negative singular values in decreasing order of magnitude.

What I want to obtain is a truncated 'S' matrix, in a way that the columns of the matrix holding singular values lower than 1e-4 would be removed. Then, apply this truncation to the matrix 'U'.

Is there a simple way of doing this? I have been looking around, and found some solutions to the problem for Matlab, but didn't find anything similar for Python. For Matlab, the code would look something like:

%Matlab
tol=1e-4
mask=any(Sigma>=tol,2);
sigRB=Sigma(:,mask);
mask2=any(U>=tol,2);
B=U(:,mask);

Thanks in advance. I hope my post was not too messy to understand.


Solution

  • I am not sure if I understand you correctly. If my solution is not what you ask for, please consider adding an example to your question.

    The following code drops all columns from array s that consist only of values smaller than tol.

    s = np.array([
        [1, 0, 0, 0, 0, 0],
        [0, .9, 0, 0, 0, 0],
        [0, 0, .5, 0, 0, 0],
        [0, 0, 0, .4, 0, 0],
        [0, 0, 0, 0, .3, 0],
        [0, 0, 0, 0, 0, .2]
    ])
    
    print(s)
    
    tol = .4
    ind = np.argwhere(s.max(axis=1) < tol)
    
    s = np.delete(s, ind, 1)
    
    print(s)
    

    Output:

    [[1.  0.  0.  0.  0.  0. ]
     [0.  0.9 0.  0.  0.  0. ]
     [0.  0.  0.5 0.  0.  0. ]
     [0.  0.  0.  0.4 0.  0. ]
     [0.  0.  0.  0.  0.3 0. ]
     [0.  0.  0.  0.  0.  0.2]]
    
    
    [[1.  0.  0.  0. ]
     [0.  0.9 0.  0. ]
     [0.  0.  0.5 0. ]
     [0.  0.  0.  0.4]
     [0.  0.  0.  0. ]
     [0.  0.  0.  0. ]]
    

    I am applying max to axis 1 and then using np.argwhere to get the indices of the columns where the max value is smaller than tol.

    Edit: In order to truncate the columns of matrix 'U', so it coincides in size with the reduced matrix 'S', the following code works:

    k = len(S[0])
    Ured = U[:,0:k]
    Uredsize = np.shape(Ured) # To check it has worked
    print(Uredsize)