Svd.pt

Svd.pt

Atualizado 2026-02-24 Leitura 3 min
Resumo
  • A SVD fatoriza uma matriz em bases ortogonais e valores singulares, permitindo aproximação de baixo posto.
  • Truncar valores singulares pequenos remove ruído enquanto preserva as componentes principais do sinal.
  • A SVD está na base de muitas técnicas práticas, incluindo PCA e modelos de fatores latentes.

Intuição #

A SVD decompõe os dados em modos independentes ordenados por intensidade. Reter apenas os modos fortes produz representações compactas com perda de informação controlada.

Explicação Detalhada #

1. Por que SVD? #

  • Qualquer matriz retangular (A) pode ser decomposta em partes interpretáveis: rotações mais escalonamento.
  • Ao truncar os valores singulares, obtemos a melhor aproximação de baixo posto no sentido da norma de Frobenius.
  • A SVD é numericamente estável e constitui a espinha dorsal de muitos algoritmos (LSA, PCA, filtragem colaborativa).

2. Definição #

Para (A \in \mathbb{R}^{m \times n}):

$$A = U \Sigma V^\top$$
  • (U): vetores singulares esquerdos (ortonormais, tamanho (m \times m))
  • (\Sigma): matriz diagonal com valores singulares (\sigma_1 \ge \sigma_2 \ge \dots)
  • (V): vetores singulares direitos (ortonormais, tamanho (n \times n))

Os valores singulares principais capturam a maior parte da energia da matriz.


3. Preparar uma imagem #

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from scipy import linalg
from PIL import Image

img = Image.open("./sample.png").convert("L").resize((163, 372)).rotate(90, expand=True)
img

4. Calcular a SVD #

X = np.asarray(img)
U, Sigma, VT = linalg.svd(X, full_matrices=True)

print(f"A: {X.shape}, U: {U.shape}, Σ:{Sigma.shape}, V^T:{VT.shape}")

5. Aproximação de baixo posto / compressão #

for rank in [1, 2, 3, 4, 5, 10, 20, 50]:
    U_i = U[:, :rank]
    Sigma_i = np.matrix(linalg.diagsvd(Sigma[:rank], rank, rank))
    VT_i = VT[:rank, :]
    temp_image = np.asarray(U_i * Sigma_i * VT_i)

    plt.title(f"rank={rank}")
    plt.imshow(temp_image, cmap="gray")
    plt.show()

Um pequeno número de valores singulares já reconstrói a imagem razoavelmente bem.


6. Inspecionar vetores singulares #

total = np.zeros((163, 372))
for rank in [1, 2, 3, 4, 5]:
    U_i = U[:, :rank]
    Sigma_i = np.matrix(linalg.diagsvd(Sigma[:rank], rank, rank))
    VT_i = VT[:rank, :]

    if rank > 1:
        for ri in range(rank - 1):
            Sigma_i[ri, ri] = 0

    temp_image = np.asarray(U_i * Sigma_i * VT_i)
    total += temp_image

    plt.figure(figsize=(5, 5))
    plt.suptitle(f"Contribution of $u_{rank}$")
    plt.subplot(211)
    plt.imshow(temp_image, cmap="gray")
    plt.subplot(212)
    plt.plot(VT[0])
    plt.show()

plt.imshow(total)

Cada par de vetores singulares codifica um padrão particular na imagem; adicionar mais pares refina os detalhes.


7. Dicas práticas #

  • Compressão: escolha (k) de modo que (\sum_{i=1}^k \sigma_i / \sum_j \sigma_j) atinja a energia desejada.
  • Redução de ruído: descartar valores singulares pequenos frequentemente funciona como um denoiser.
  • PCA: simplesmente aplique SVD à matriz de dados centrada; os vetores singulares direitos correspondem aos eixos principais.
  • Custo: a SVD completa é (O(mn \min(m,n))); use SVD truncada ou randomizada para matrizes grandes.