SciPy - pinv() Function



The scipy.linalg.pinv() function calculates the Moore-Penrose pseudo-inverse of any matrix through Singular Value Decomposition (SVD). This approach works for both rectangular and square matrices, which gives it broad applications. The function treats small singular values as zero based on given tolerances allowing it to handle rank-deficient matrices.

Scientists and researchers often use this function to solve least-squares problems when matrices don't have full rank. It plays a key role in regression, data fitting, and numerical analysis. The function also helps to solve systems of linear equations, including those with too many or too few equations.

The pinv() function uses SVD for all types of matrices, so it can handle more cases but takes a bit longer. In contrast, the pinvh() function is built for symmetric or Hermitian matrices and uses eigenvalue decomposition to work faster. You should use pinv() when you're dealing with general matrices like rectangular or square ones. Choose pinvh() when you know your matrix is symmetric to get better speed.

When solving linear systems in cases where a direct inverse using inv() cannot be computed, such as for singular or ill-conditioned matrices, the Moore-Penrose pseudo-inverse is particularly important because it provides a generalized matrix inverse.

Syntax

The syntax for the Scipy pinv() method is as follows −

.pinv(a, *, atol=None, rtol=None, return_rank=False, check_finite=True)

Parameters

This method accepts the following parameters −

  • a (array_like) − The matrix for which the pseudo-inverse is to be computed. Can be any rectangular or square matrix.

  • atol (float, optional) − Absolute tolerance for rank estimation. Default is 0.

  • rtol (float, optional) − Relative tolerance for rank estimation. Default is 0.

  • return_rank (bool,optional) − If True, the method returns the rank of the matrix along with the pseudo-inverse. Default is False.

  • check_finite (bool, optional) − If true it checks the matrix contains only finite numbers. If it is disabled performance will be faster but if there is NaNs or IFNs it will crash or causes trouble.

Return Value

This method returns the following −

  • B (ndarray) − The pseudo-inverse of the input matrix a.

  • rank (int, optional) − The numerical rank of the matrix if return_rank=True.

Example 1: Pseudo-inverse of Matrix

This is the basic example of pinvh() method to compute pseudo-inverse of a rectangular matrix. A matrix is called rectangular when its rows and columns are not equal

import numpy as np
import scipy.linalg

# Define a rectangular matrix
A = np.array([[1, 2, 3], [4, 5, 6]])

# Compute the pseudo-inverse
pinv_A = scipy.linalg.pinv(A)

print("Pseudo-inverse of A:", pinv_A)

Following is an output of the above code

Pseudo-inverse of A:
 [[-0.94444444  0.44444444]
 [-0.11111111  0.11111111]
 [ 0.72222222 -0.22222222]]

Example 2: Solving Least-Squares Problems

The pseudo-inverse method helps solve systems with more equations than unknowns. It works to minimize the difference between Ax and b. This results in a solution that fits best, which comes in handy for regression and least-squares issues.

In the code, we figure out the pseudo-inverse of A and use it to solve Ax=b. This gives us the best possible approximation. The output below, the residual isn't zero because it's an overdetermined system. There's no exact solution, but this method minimizes the residual giving the best-fitting answer.

import numpy as np
from scipy.linalg import pinv

# Define an overdetermined matrix (more rows than columns)
A = np.array([[2, 3],
              [5, 7],
              [11, 13]])

# Define the target vector
b = np.array([1, 2, 3])
pinv_A = pinv(A)

# Solve for x using the pseudo-inverse: x = pinv(A) * b
x = np.dot(pinv_A, b)

print("Pseudo-inverse of A:", pinv_A)

print("\nSolution vector x (minimizes ||Ax - b||):", (x))

# Verify the solution: Check the residual ||Ax - b||
residual = np.linalg.norm(np.dot(A, x) - b)
print("\nResidual ||Ax - b||:")
print(residual)

Output of the above code is as follows

Pseudo-inverse of A: [[-0.50515464 -0.78865979  0.54123711]
 [ 0.42268041  0.67010309 -0.3814433 ]]

Solution vector x (minimizes ||Ax - b||): [-0.45876289  0.6185567 ]

Residual ||Ax - b||:
0.07179581586177375

Example 3: Data Fitting with Multiple Outputs

To minimize the residual error AXB for each column of B, the pseudo-inverse computed by pinv() helps to solve systems with multiple target vectors.

In this example, we compute the pseudo-inverse of A and use this to solve for the solution matrix X, where each column is the least-squares solution for the corresponding column of B.

import numpy as np
from scipy.linalg import pinv

# Define the coefficient matrix A and multiple target vectors B
A = np.array([[1, 1], [1, 2], [1, 3]])
B = np.array([[1, 2], [2, 3], [2, 4]])

# Compute the pseudo-inverse and solve
pinv_A = pinv(A)
X = np.dot(pinv_A, B)

print("Pseudo-inverse of A:\n", pinv_A)
print("\nSolution matrix X (minimizes ||AX - B||):\n", X)

Output of the above code is as follows

Pseudo-inverse of A:
 [[ 1.33333333e+00  3.33333333e-01 -6.66666667e-01]
 [-5.00000000e-01 -3.02420752e-17  5.00000000e-01]]

Solution matrix X (minimizes ||AX - B||):
 [[0.66666667 1.        ]
 [0.5        1.        ]]
scipy_linalg.htm
Advertisements