
1.1–1.2 - Brunton: Data-Driven Science and Engineering
Universidade Federal do Pará



Centenas de amostras, mas apenas dois padrões dominantes: os padrões são os seus dois polos.
Cada coluna de \(\mathbf{X} = [\mathbf{x}_1 \ \cdots \ \mathbf{x}_m] \in \mathbb{C}^{n \times m}\) é um conjunto de medições: uma imagem, ou amostras de entrada e saída de um sistema.



Cada padrão é uma coluna \(\mathbf{u}_k\) vezes uma linha \(\mathbf{v}_k^T\), com um peso \(\sigma_k\) (valor singular).
Para \(\mathbf{X} \in \mathbb{C}^{n \times m}\) com \(n \ge m\), a matriz é uma soma de até \(m\) padrões:

\[ \mathbf{X} = \sigma_1 \mathbf{u}_1 \mathbf{v}_1^* + \sigma_2 \mathbf{u}_2 \mathbf{v}_2^* + \cdots + \sigma_m \mathbf{u}_m \mathbf{v}_m^* = \sum_{k=1}^{m} \sigma_k \mathbf{u}_k \mathbf{v}_k^* \qquad (1.4) \]
\[ \color{#1B365D}{\Large \mathbf{X} = \mathbf{U}\boldsymbol{\Sigma}\mathbf{V}^*} \]
\[ \color{#B23A48}{\sigma_1 \ge \sigma_2 \ge \cdots \ge \sigma_m \ge 0} \qquad \text{os padrões vêm ranqueados por importância} \]

\[ \boldsymbol{\Sigma} = \left[\begin{array}{ccc} \sigma_1 & & \\ & \ddots & \\ & & \sigma_m \\ \hline & \mathbf{0} & \end{array}\right] \begin{array}{l} \left.\vphantom{\begin{array}{c} \sigma_1 \\ \ddots \\ \sigma_m \end{array}}\right\} m \times m \ \text{(diagonal)} \\ \left.\vphantom{\begin{array}{c} \mathbf{0} \end{array}}\right\} (n-m) \times m \end{array} \]
As colunas de \(\mathbf{U}\) além da \(m\)-ésima (\(\mathbf{\hat{U}}^\perp\)) multiplicam só zeros de \(\boldsymbol{\Sigma}\).
Diferente da FFT, que usa uma base fixa (senoides), as bases \(\mathbf{U}\) e \(\mathbf{V}\) da SVD são extraídas dos próprios dados, sem conhecimento prévio do sistema.
Definição
Toda matriz \(\mathbf{X} \in \mathbb{C}^{n \times m}\) pode ser escrita como \[ \mathbf{X} = \mathbf{U} \boldsymbol{\Sigma} \mathbf{V}^* \] com \(\mathbf{U}\) (\(n \times n\)) e \(\mathbf{V}\) (\(m \times m\)) unitárias e \(\boldsymbol{\Sigma}\) (\(n \times m\)) diagonal, \(\sigma_k \ge 0\).

Na prática, basta uma linha: a SVD vem pronta do LAPACK, base do NumPy e do MATLAB.
\[ \overset{\displaystyle \mathbf{X}\ (5 \times 3)}{\begin{bmatrix} 3 & 2 & 2 \\ 2 & 3 & -2 \\ 1 & 0 & 1 \\ 0 & 1 & 1 \\ 2 & 2 & 0 \end{bmatrix}} = \overset{\displaystyle \mathbf{\hat{U}}\ (5 \times 3)}{\begin{bmatrix} -0.63 & -0.58 & -0.11 \\ -0.58 & \phantom{-}0.71 & \phantom{-}0.02 \\ -0.13 & -0.34 & -0.36 \\ -0.13 & -0.21 & \phantom{-}0.93 \\ -0.48 & \phantom{-}0.05 & -0.04 \end{bmatrix}} \raise{1.25em}{\overset{\displaystyle \boldsymbol{\hat{\Sigma}}\ (3 \times 3)}{\begin{bmatrix} \color{#B23A48}{5.84} & 0 & 0 \\ 0 & \color{#B23A48}{3.29} & 0 \\ 0 & 0 & \color{#B23A48}{1.05} \end{bmatrix}}} \raise{1.25em}{\overset{\displaystyle \mathbf{V}^T\ (3 \times 3)}{\begin{bmatrix} -0.71 & -0.70 & -0.06 \\ -0.17 & \phantom{-}0.26 & -0.95 \\ -0.68 & \phantom{-}0.66 & \phantom{-}0.30 \end{bmatrix}}} \]
O NumPy devolve os valores singulares como vetor e \(\mathbf{V}^T\); o MATLAB devolve \(\boldsymbol{\Sigma}\) como matriz e \(\mathbf{V}\).
Como \(\boldsymbol{\Sigma}\) é diagonal, \(\mathbf{X}\) é uma soma de matrizes de posto 1, em hierarquia:
\[ \mathbf{X} = \sum_{k=1}^{m} \sigma_k \mathbf{u}_k \mathbf{v}_k^* = \sigma_1 \mathbf{u}_1 \mathbf{v}_1^* + \sigma_2 \mathbf{u}_2 \mathbf{v}_2^* + \cdots + \sigma_m \mathbf{u}_m \mathbf{v}_m^* \]
com \(\mathbf{u}_k\) e \(\mathbf{v}_k\) as \(k\)-ésimas colunas de \(\mathbf{U}\) e \(\mathbf{V}\).

\[ \color{#1B365D}{\mathbf{X} \approx \mathbf{\tilde{X}} = \sum_{k=1}^{r} \sigma_k \mathbf{u}_k \mathbf{v}_k^* = \mathbf{\tilde{U}} \boldsymbol{\tilde{\Sigma}} \mathbf{\tilde{V}}^*} \]

Resultado de Schmidt (o de Gram–Schmidt), redescoberto por Eckart e Young:
Teorema 1.1 (Eckart–Young)
A melhor aproximação de posto \(r\) de \(\mathbf{X}\), no sentido de mínimos quadrados, é a SVD truncada de posto \(r\): \[ \underset{\mathbf{\tilde{X}},\ \text{s.a.}\ \operatorname{posto}(\mathbf{\tilde{X}}) = r}{\operatorname{argmin}} \ \big\| \mathbf{X} - \mathbf{\tilde{X}} \big\|_F = \mathbf{\tilde{U}} \boldsymbol{\tilde{\Sigma}} \mathbf{\tilde{V}}^* \]
ou seja, \[ \mathbf{X} \approx \mathbf{\tilde{X}} = \sum_{k=1}^{r} \sigma_k \mathbf{u}_k \mathbf{v}_k^* = \sigma_1 \mathbf{u}_1 \mathbf{v}_1^* + \sigma_2 \mathbf{u}_2 \mathbf{v}_2^* + \cdots + \sigma_r \mathbf{u}_r \mathbf{v}_r^* \]
Norma de Frobenius: \(\|\mathbf{X}\|_F = \big( \sum_{i=1}^{n} \sum_{j=1}^{m} |X_{ij}|^2 \big)^{1/2}\), a norma 2 da matriz “vetorizada” \(\mathbf{X}(:)\).
O erro da SVD truncada de posto \(r\) é conhecido exatamente, e nenhuma outra matriz de posto \(r\) erra menos:
\[ \big\| \mathbf{X} - \mathbf{\tilde{X}} \big\|_F^2 = \sum_{k=r+1}^{m} \sigma_k^2. \qquad (1.7) \]
Por quê?
O resíduo é a soma dos termos descartados, \(\mathbf{X} - \mathbf{\tilde{X}} = \sum_{k=r+1}^{m} \sigma_k \mathbf{u}_k \mathbf{v}_k^* = \mathbf{U}_{\text{rem}} \boldsymbol{\Sigma}_{\text{rem}} \mathbf{V}_{\text{rem}}^*\). Como \(\|\mathbf{A}\|_F^2 = \operatorname{tr}(\mathbf{A}^*\mathbf{A})\) e \(\mathbf{U}_{\text{rem}}^*\mathbf{U}_{\text{rem}} = \mathbf{V}_{\text{rem}}^*\mathbf{V}_{\text{rem}} = \mathbf{I}\), as bases ortonormais não alteram a norma: \(\|\mathbf{X} - \mathbf{\tilde{X}}\|_F^2 = \|\boldsymbol{\Sigma}_{\text{rem}}\|_F^2 = \sigma_{r+1}^2 + \cdots + \sigma_m^2\).
Como esse erro escala com a magnitude de \(\mathbf{X}\), costuma ser mais útil o erro relativo \(\;\big\| \mathbf{X} - \mathbf{\tilde{X}} \big\|_F^2 \,/\, \|\mathbf{X}\|_F^2 \;\) (1.8):
A SVD truncada também é ótima na norma 2 (norma espectral), induzida pela norma 2 de vetores:
\[ \underset{\mathbf{\tilde{X}},\ \text{s.a.}\ \operatorname{posto}(\mathbf{\tilde{X}}) = r}{\operatorname{argmin}} \ \big\| \mathbf{X} - \mathbf{\tilde{X}} \big\|_2 = \mathbf{\tilde{U}} \boldsymbol{\tilde{\Sigma}} \mathbf{\tilde{V}}^*, \qquad (1.9) \qquad \|\mathbf{X}\|_2 = \max_{\mathbf{v} \neq \mathbf{0}} \frac{\|\mathbf{X}\mathbf{v}\|_2}{\|\mathbf{v}\|_2}. \]
Nessa norma, o erro é ainda mais simples: \[ \big\| \mathbf{X} - \mathbf{\tilde{X}} \big\|_2 = \sigma_{r+1}. \qquad (1.10) \]
Basta expandir o resíduo, \[ \mathbf{X} - \mathbf{\tilde{X}} = \sum_{k=r+1}^{m} \sigma_k \mathbf{u}_k \mathbf{v}_k^*, \qquad (1.11) \] e usar a ortonormalidade dos \(\mathbf{v}_k\): o máximo de \(\|(\mathbf{X} - \mathbf{\tilde{X}})\mathbf{v}\|_2\) sobre vetores unitários é \(\sigma_{r+1}\), atingido em \(\mathbf{v} = \mathbf{v}_{r+1}\).
rng = np.random.default_rng(0)
X = rng.standard_normal((200, 50))
U, S, VT = np.linalg.svd(X, full_matrices=False)
r = 10
Xr = U[:, :r] @ np.diag(S[:r]) @ VT[:r, :] # SVD truncada de posto r (1.5)
print(np.linalg.norm(X - Xr, 'fro')**2, np.sum(S[r:]**2)) # (1.7)
print(np.linalg.norm(X - Xr, 2), S[r]) # (1.10)6438.2718056637295 6438.2718056637295
17.205369539578513 17.205369539578506
Os índices em Python começam em 0: S[r] é \(\sigma_{r+1}\) e S[r:] são \(\sigma_{r+1}, \dots, \sigma_m\); no MATLAB, s(r+1) e s(r+1:end).
Uma imagem em tons de cinza é uma matriz real \(\mathbf{X} \in \mathbb{R}^{n \times m}\) (\(n\) pixels na vertical, \(m\) na horizontal). Aqui, a mesma foto do livro: o cachorro Mordecai (\(2000 \times 1500\) pixels).
A = plt.imread("imgs/dog.jpg") # foto colorida (RGB)
X = np.mean(A, axis=-1) # RGB -> tons de cinza
n, m = X.shape
U, S, VT = np.linalg.svd(X, full_matrices=False) # SVD econômica
aproxima = lambda r: U[:, :r] @ np.diag(S[:r]) @ VT[:r, :] # SVD truncada (1.5)
armazenamento = lambda r: r * (n + m + 1) / (n * m) # fração guardadaA = imread('imgs/dog.jpg'); % foto colorida (RGB)
X = mean(double(A), 3); % RGB -> tons de cinza
[n,m] = size(X);
[U,S,V] = svd(X,'econ'); s = diag(S); % SVD econômica
for r = [5 20 100] % SVD truncada (1.5) para vários postos
Xapprox = U(:,1:r)*S(1:r,1:r)*V(:,1:r)';
figure, imagesc(Xapprox), axis off, colormap gray
title(sprintf('r = %d (%.1f%% dos dados)', r, 100*r*(n+m+1)/(n*m)))
end
figure, subplot(1,2,1), semilogy(s,'k') % valores singulares
subplot(1,2,2), plot(cumsum(s)/sum(s),'k') % soma acumuladaGuardar \(\mathbf{\tilde{U}}\), \(\boldsymbol{\tilde{\Sigma}}\) e \(\mathbf{\tilde{V}}\) exige \(r(n + m + 1)\) números, contra \(nm\) da imagem original: a truncação é uma compressão.

Com \(r = 5\) só se reconhecem as grandes regiões claras e escuras; com \(r = 100\) a imagem já é visualmente próxima da original.

r = 5: soma acumulada = 42.4%, erro relativo (1.8) = 2.62%
r = 20: soma acumulada = 57.0%, erro relativo (1.8) = 0.77%
r = 100: soma acumulada = 75.7%, erro relativo (1.8) = 0.14%