Singular value decomposition#
The SVD of a \(m \times n\) matrix \(A\) is
We use numpy.linalg.svd or scipy.linalg.svd to compute this. Below we use numpy.
%config InlineBackend.figure_format = 'svg'
import numpy as np
import matplotlib.pyplot as plt
Construct a random \(3 \times 2\) matrix.
A = 2 * np.random.rand(3,2) - 1
Reduced SVD#
The reduced SVD is given by
U,S,Vh = np.linalg.svd(A, full_matrices=False)
The function returns \(\textrm{Vh} = V^\star\).
The singular vectors and values are given by
U,S,Vh = np.linalg.svd(A, full_matrices=False)
print('U = \n', U)
print('sigma = ', *S)
print('V = \n', Vh.T)
U =
[[ 0.56362633 0.81337542]
[-0.14178377 0.2670426 ]
[-0.81377068 0.51682557]]
sigma = 1.390363151754217 0.7636365942544742
V =
[[-0.54540601 0.83817199]
[ 0.83817199 0.54540601]]
\(U\) is \(m \times n\) and \(V\) is \(n \times n\). We can verify that \(A = U \Sigma V^\star\) by computing the element-wise maximum difference
print(np.abs(A - U@np.diag(S)@Vh).max())
2.220446049250313e-16
Full SVD#
The full SVD is given by
U,S,Vh = np.linalg.svd(A, full_matrices=True)
The singular vectors and values are given by
U,S,Vh = np.linalg.svd(A, full_matrices=True)
print('U = \n', U)
print('sigma = ', *S)
print('V = \n', Vh.T)
U =
[[ 0.56362633 0.81337542 0.14403396]
[-0.14178377 0.2670426 -0.95319757]
[-0.81377068 0.51682557 0.26583567]]
sigma = 1.390363151754217 0.7636365942544742
V =
[[-0.54540601 0.83817199]
[ 0.83817199 0.54540601]]
\(U\) is \(m \times m\) and \(V\) is \(n \times n\).
Rank deficient case#
Construct a random \(4 \times 3\) matrix whose last column is sum of first two columns. Its rank is 2.
A = 2 * np.random.rand(4,3) - 1
A[:,2] = A[:,0] + A[:,1]
Compute the reduced SVD
U,S,Vh = np.linalg.svd(A, full_matrices=False)
print('U = \n', U)
print('sigma = ', *S)
print('V = \n', Vh.T)
U =
[[-0.59953071 -0.34508729 -0.39074021]
[ 0.09225911 -0.48661847 0.80308371]
[ 0.41885745 -0.76715029 -0.39806246]
[-0.67572895 -0.23579155 0.20958273]]
sigma = 3.037127455137475 0.41484360285223504 2.539493840585527e-17
V =
[[-0.49551087 0.64894964 0.57735027]
[-0.31425144 -0.75359983 0.57735027]
[-0.80976231 -0.10465018 -0.57735027]]
We notice that one out of three singular values is zero. The number of non-zero singular values corresponds to the rank of the matrix.
Random matrix#
m, n = 100, 50
A = 2 * np.random.rand(m,n) - 1
U,S,Vh = np.linalg.svd(A, full_matrices=False)
plt.subplot(121)
plt.plot(S,'o')
plt.xlabel('j')
plt.title('$\\sigma_j$')
plt.subplot(122)
plt.plot(S/S[0],'o')
plt.xlabel('j')
plt.title('$\\sigma_j/\\sigma_1$');
All singular values are of very similar size.