Dimensionality Reduction

Outono 2025

Dimensionality Reduction

O que é Dimensionality Reduction?

Dimensionality Reduction

O que é Dimensionality Reduction?

Dimensionality Reduction é o processo de reduzir o número de variáveis aleatórias sob consideração, obtendo um conjunto de variáveis principais.

Dimensionality Reduction

O que é Dimensionality Reduction?

Dimensionality Reduction é o processo de reduzir o número de variáveis aleatórias sob consideração, obtendo um conjunto de variáveis principais. Ajuda em:

  • Visualization de dados de alta dimensionalidade
  • Reduzir o custo computacional
  • Eliminar ruído e redundância

Métodos

  • Principal Component Analysis (PCA)
  • Multidimensional Scaling (MDS)
  • Sparse Random Projection (SRP)
  • Locally Linear Embedding (LLE)
  • t-Distributed Stochastic Neighbor Embedding (t-SNE)
  • Uniform Manifold Approximation and Projection (UMAP)

PCA

PCA

Ideia central:

Baseia-se na maximização da variância e na eigen decomposition.

PCA

Ideia central:

Baseia-se na maximização da variância e na eigen decomposition.

Propósito:

Encontrar um conjunto de eixos ortogonais (componentes principais) que capturem a máxima variância nos dados.

PCA

Passos:

  • Centralizar os dados.
  • Calcular a matriz de covariância: \(\sum = \frac{1}{n} X^T X\)
  • Calcular os eigenvectors e eigenvalues: \(\sum v_i = \lambda_i v_i\)
  • Projetar os dados no novo espaço: \(Z = X W_k\) onde \(W_k\) são os top-k eigenvectors.

Exemplo no MNIST

MNIST Dataset

  • Dataset de imagens de 28x28 pixels de dígitos escritos à mão

MNIST Dataset

  • Cada imagem do MNIST pode ser pensada como um array de 28x28 números descrevendo o quão escuro é cada pixel:
  • Podemos achatar cada array em um vetor de 28 * 28 = 784 dimensões, onde cada componente do vetor é um valor entre zero e um que descreve a intensidade do pixel
  • Podemos pensar no MNIST como uma coleção de vetores de 784 dimensões

MNIST Dataset

  • Mas nem todos os vetores nesse espaço de 784 dimensões são dígitos do MNIST! Pontos típicos nesse espaço são bem diferentes
  • Para ter uma ideia de como é um ponto típico, podemos escolher aleatoriamente algumas imagens de 28x28 – cada pixel é aleatoriamente branco, preto ou algum tom de cinza. Esses pontos aleatórios parecem ruído:

MNIST Dataset

  • Imagens de 28x28 que se parecem com dígitos do MNIST são muito raras - elas formam um subespaço muito pequeno do espaço de 784 dimensões
    • Com alguns argumentos um pouco mais complexos, podemos ver que elas ocupam um subespaço de dimensão menor (do que 748)
  • Muitas teorias sobre a estrutura de menor dimensão do MNIST (e dados semelhantes)
    • Hipótese do manifold (popular entre pesquisadores de ML): MNIST é um manifold de baixa dimensão que se curva através do seu embedding space de alta dimensão
    • Outra hipótese (com raízes em topological data analysis) é que dados como o MNIST consistem em blobs com protuberâncias tipo tentáculo que se projetam para o espaço ao redor
    • Mas ninguém sabe ao certo!

MNIST Cube

  • Imagine os pontos de dados do MNIST como pontos suspensos em um cubo de 784 dimensões
    • Cada dimensão do cubo corresponde a um pixel específico
    • Os pontos de dados variam de zero a um de acordo com a intensidade do pixel
    • De um lado da dimensão, há imagens onde aquele pixel é branco. Do outro lado da dimensão, há imagens onde ele é preto. No meio, há imagens onde ele é cinza.
  • Como esse cubo se parece se olharmos para uma face bidimensional específica? Vamos olhar as visualizations de Olah.

MNIST Cube

  • Que qualidades a visualization ‘perfeita’ do MNIST teria? Qual deveria ser o nosso objetivo?
  • Qual é a melhor forma de fazer clustering dos dados do MNIST?
  • Podemos tentar o que aprendemos na semana passada…

PCA on MNIST

Importar bibliotecas:

import numpy as np
import matplotlib.pyplot as plt
import sklearn
from sklearn.datasets import load_digits
from sklearn.decomposition import TruncatedSVD
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.ensemble import RandomTreesEmbedding
from sklearn.manifold import (Isomap, LocallyLinearEmbedding, MDS, SpectralEmbedding, TSNE)
from sklearn.neighbors import NeighborhoodComponentsAnalysis
from sklearn.pipeline import make_pipeline
from sklearn.random_projection import SparseRandomProjection
from sklearn.decomposition import PCA
import plotly.graph_objects as go
from umap import UMAP

PCA on MNIST

Definir funções auxiliares para visualizar clusters em 2D e 3D:

# Authors: Gael Varoquaux
# License: BSD 3 clause (C) INRIA 2014
def plot_clustering(X_red, labels, title=None):
    x_min, x_max = np.min(X_red, axis=0), np.max(X_red, axis=0)
    X_red = (X_red - x_min) / (x_max - x_min)

    plt.figure(figsize=(6, 6))
    for digit in digits.target_names:
        plt.scatter(
            *X_red[y == digit].T,
            marker=f"${digit}$",
            s=50,
            # c=plt.cm.nipy_spectral(labels[y == digit] / 10),
            alpha=0.5,
        )

    plt.xticks([])
    plt.yticks([])
    if title is not None:
        plt.title(title, size=17)
    plt.axis("off")
    plt.tight_layout(rect=[0, 0.03, 1, 0.95])

PCA on MNIST

Definir funções auxiliares para visualizar clusters em 2D e 3D:

def plot_3d_clustering(X_red, labels, title=None):
    component0 = X_red[:, 0]
    component1 = X_red[:, 1]
    component2 = X_red[:, 2]
    indices =  list(range(X_red.shape[0]))
    labels = list (map(lambda x: "label:" + str(y[x]) + ", id:" + str(x),indices))

    fig = go.Figure(data=[go.Scatter3d(
        x=component0,
        y=component1,
        z=component2,
        mode='markers',
        marker=dict(
            size=10,
            color=y,                # set color to an array/list of desired values
            colorscale='Rainbow',   # choose a colorscale
            opacity=1,
            line_width=1,
        ),
        text = labels

    )])
# tight layout
    fig.update_layout(margin=dict(l=50,r=50,b=50,t=50),width=520,height=520)
    fig.layout.template = 'plotly_dark'

    fig.show()

PCA on MNIST

Carregar o dataset do MNIST:

digits = load_digits(n_class=6)
X, y = digits.data, digits.target
n_samples, n_features = X.shape
n_neighbors = 30

print("Amostras: " + str(n_samples))
print("Características: " + str(n_features))
Amostras: 1083
Características: 64

PCA on MNIST

Realizar PCA:

pca = PCA(n_components=2)
pca.fit(X)
X_trans = pca.transform(X)
print("Valores singulares: " + str(pca.singular_values_))
Valores singulares: [503.75922595 466.04224081]

PCA on MNIST

    Vemos que conseguimos agrupar razoavelmente os dados por dígito usando PCA:
plt.scatter(X_trans[:,0],X_trans[:,1])

PCA on MNIST

    Vemos que conseguimos agrupar razoavelmente os dados por dígito usando PCA:
plot_clustering(X_trans, "", "PCA")

PCA on MNIST

    Também podemos visualizar isso em 3D:
pca_3d = PCA(n_components=3)
X_trans_3d = pca_3d.fit_transform(X)
plot_3d_clustering(X_trans_3d, "", "PCA")

MDS

MDS

Também é conhecido como Principal Coordinates Analysis (PCoA).

MDS

Também é conhecido como Principal Coordinates Analysis (PCoA).

Ideia central:

Foca em preservar distâncias usando eigenvalue decomposition de uma matriz de similaridade.

MDS

Também é conhecido como Principal Coordinates Analysis (PCoA).

Ideia central:

Foca em preservar distâncias usando eigenvalue decomposition de uma matriz de similaridade.

Propósito:

Preservar as distâncias par a par entre os pontos de dados no embedding de baixa dimensão.

MDS

Passos:

  • Calcular a matriz de proximidade ao quadrado: \(D^2 = [d^2_{ij}]\)
  • Duplo-centralizar a matriz de distâncias para obter uma matriz de similaridade: \(B = - \frac{1}{2} C D^2 C\) Onde \(C=I-\frac{1}{n} J_n\) é a matriz de centralização e \(J_n = 11^T\) é a matriz de todos uns.
  • Realizar eigen decomposition: \(B = V \Sigma V^T\)
  • Usar os top eigenvectors como coordenadas de baixa dimensão: \(X = V_k \Sigma_k ^{1/2}\)

MDS on MNIST

mds = MDS(n_components=2, n_init=1, max_iter=120, n_jobs=2)
X_mds = mds.fit_transform(X)
plot_clustering(X_mds, "", "MDS")

MDS on MNIST

mds_3d = MDS(n_components=3, n_init=1, max_iter=120, n_jobs=2)
mds_3d.fit(X)
X_mds_3d = mds_3d.fit_transform(X)
plot_3d_clustering(X_mds_3d, "", "MDS")

SRP

SRP

Ideia central:

Projeta usando matrizes sparse random, preservando distâncias.

SRP

Ideia central:

Projeta usando matrizes sparse random, preservando distâncias.

Propósito:

Reduzir a dimensionalidade enquanto preserva aproximadamente as distâncias par a par, usando matrizes sparse random.

SRP

Passos:

  • Gerar uma matriz sparse random: \(\mathcal{R}_{ij} = \sqrt{s} \times \begin{cases} +1, & \text{com probabilidade } \frac{1}{2s} \\ -1, & \text{com probabilidade } \frac{1}{2s} \\ 0, & \text{com probabilidade } 1 - \frac{1}{s} \\ \end{cases}\) Onde \(s\) é o parâmetro de sparsity.
  • Projeta \(Z = X\mathcal{R}\)

SRP on MNIST

srp=SparseRandomProjection(n_components=2, random_state=42)
X_srp=srp.fit_transform(X)
plot_clustering(X_srp, "", "Sparse Random Projection")

SRP on MNIST

srp_3d=SparseRandomProjection(n_components=3, random_state=42)
X_srp_3d=srp_3d.fit(X)
X_srp_3d=srp_3d.fit_transform(X)
plot_3d_clustering(X_srp_3d, "", "Sparse Random Projection")

LLE

LLE

Ideia central:

Usa pesos de reconstrução linear local.

LLE

Ideia central:

Usa pesos de reconstrução linear local.

Propósito:

Preservar as relações de vizinhança local por meio de reconstrução linear.

LLE

Passos:

  • Identificar os k-nearest neighbors de cada ponto: Minimizar \(\sum_i || x_i - \sum _{j \in N(i) w_{ij} x_j } ||^2\)
  • Calcular os pesos que reconstroem cada ponto a partir de seus vizinhos.
  • Encontrar embeddings de baixa dimensão que preservem esses pesos: \(\Phi(Y) = \sum_i ||y_i - \sum _{j \in N(i) w_{ij} y_j } ||^2\)

LLE on MNIST

lle=LocallyLinearEmbedding(n_neighbors=5, n_components=2, method="standard")
X_lle=lle.fit(X)
X_lle=lle.fit_transform(X)
plot_clustering(X_lle, "", "LLE")

LLE on MNIST

lle_3d=LocallyLinearEmbedding(n_neighbors=n_neighbors, n_components=3, method="standard")
X_lle_3d=lle_3d.fit(X)
X_lle_3d=lle_3d.fit_transform(X)
plot_3d_clustering(X_lle_3d, "", "LLE")

t-SNE

t-SNE

Ideia central:

Otimiza a divergência KL entre similaridades de alta e baixa dimensão.

t-SNE

Ideia central:

Otimiza a divergência KL entre similaridades de alta e baixa dimensão.

Propósito:

Preservar a estrutura local dos dados com base em probabilidades de similaridade.

t-SNE

Passos:

  • Converter as distâncias de alta dimensão em probabilidades conjuntas: \(p_{ij} = \frac{p_{j|i} + p_{i|j}}{2n}\) Onde \(p_{j|i} = \frac{ exp( -|| x_i - x_j||^2 / 2 \sigma_i ^2 ) }{\sum_{k\neq i} exp( -|| x_i - x_k||^2 / 2 \sigma_i ^2 ) }\)
  • Definir as similaridades de baixa dimensão: \(q_{ij} = \frac{(1+|| y_i - y_j ||^2)^{-1}}{ \sum_{k\neq l} (1+|| y_k - y_l ||^2)^{-1} }\)
  • Minimizar a divergência de Kullback-Leibler entre \(p_{ij}\) e \(q_{ij}\): \(KL = \sum _{i \neq j} p_{ij} log(\frac{p_{ij}}{q_{ij}})\)

t-SNE on MNIST

tsne = sklearn.manifold.TSNE()
X_tsne = tsne.fit_transform(X)
plot_clustering(X_tsne, "", "T-SNE")

t-SNE on MNIST

tsne_3d = sklearn.manifold.TSNE(3)
X_tsne_3d = tsne_3d.fit_transform(X)
plot_3d_clustering(X_tsne_3d, "", "T-SNE")

Usando t-SNE de Forma Eficaz

  • Gráficos de t-SNE são populares e podem ser úteis, mas somente se você evitar interpretações errôneas comuns
    • Cuidado com os valores dos hyperparameters
    • Lembre-se de que o tamanho dos clusters em um gráfico de t-SNE não significa nada
    • Saiba que as distâncias ENTRE clusters também podem não significar nada
    • Ruído aleatório nem sempre parece aleatório
    • Você pode precisar de múltiplos gráficos para entender a topologia
  • Veja Wattenberg, Viégas, e Johnson (2016) para mais detalhes

UMAP

UMAP

Ideia central:

Usa manifold learning e minimiza uma cross-entropy loss entre estruturas topológicas difusas.

UMAP

Ideia central:

Usa manifold learning e minimiza uma cross-entropy loss entre estruturas topológicas difusas.

Propósito:

Preservar tanto a estrutura local quanto a global usando manifold learning.

UMAP

Passos:

  • Construir um complexo simplicial difuso no espaço de alta dimensão \(p_{ij}\): \(p_{ij} = exp(\frac{d(x_i, x_j) - \rho_i}{\sigma_i})\)
  • Construir um complexo semelhante no espaço de baixa dimensão \(q_{ij}\): \(q_{ij} = \frac{1}{ 1+\alpha || y_i - y_j ||^{2\beta} }\)
  • Minimizar a cross-entropy entre \(p_{ij}\) e \(q_{ij}\): \(CE = \sum _{(i, j)} p_{ij} log(\frac{p_{ij}}{q_{ij}}) + (1 - p_{ij}) log( \frac{1-p_{ij}}{1-q_{ij}} )\)

UMAP on MNIST

ump=UMAP()
ump.fit(X)
X_umap=ump.fit_transform(X)
plot_clustering(X_umap, "not used", "UMAP")

UMAP on MNIST

ump_3d=UMAP(n_components=3)
ump_3d.fit(X)
X_umap_3d = ump_3d.fit_transform(X)
plot_3d_clustering(X_umap_3d, "", "UMAP")

Resumo

Referências (Recomendadas para Aprofundamento)

Olah, Christopher. 2014. «Visualizing Mnist: An exploration of dimensionality reduction». Visualizing MNIST: An Exploration of Dimensionality Reduction - colah’s blog. https://colah.github.io/posts/2014-10-Visualizing-MNIST/.
Wattenberg, Martin, Fernanda Viégas, e Ian Johnson. 2016. «How to use T-Sne effectively». Distill. https://distill.pub/2016/misread-tsne/.