UMAP (Aproximação e Projeção Uniforme de Variedades — Uniform Manifold Approximation and Projection)

UMAP (Aproximação e Projeção Uniforme de Variedades (Uniform Manifold Approximation and Projection)) é um algoritmo de redução de dimensionalidade não linear (nonlinear dimensionality-reduction) amplamente usado para visualização de dados de alta dimensionalidade (tipicamente em 2D/3D) e para aprender incorporações de baixa dimensionalidade (low-dimensional embeddings) que podem ser reutilizadas em tarefas a jusante (downstream tasks). Em comparação com métodos lineares como Análise de Componentes Principais (PCA), o UMAP consegue capturar estrutura não linear como variedades curvas e geometria complexa de clusters. Em comparação com o t-SNE, ele frequentemente roda mais rápido, pode preservar mais estrutura global (ainda que de forma imperfeita) e oferece suporte para transformar novos pontos em uma incorporação existente.

O UMAP é melhor entendido como: construir um grafo ponderado de k-vizinhos mais próximos (k-nearest-neighbor graph) no espaço original e, então, encontrar um arranjo de baixa dimensionalidade cujo grafo seja o mais similar possível.

Quando o UMAP é usado

Casos de uso comuns incluem:

  • Visualização exploratória de incorporações (por exemplo, de modelos Transformer (transformers), modelos de visão (vision models) ou autoencodificadores (autoencoders)).
  • Verificações de qualidade dos dados: identificar outliers, exemplos rotulados incorretamente, efeitos de lote (batch effects) ou subpopulações inesperadas.
  • Pré-processamento para ML a jusante: reduzir a dimensionalidade antes de agrupamento ou classificação (frequentemente em combinação com outras etapas).
  • Incorporação interativa (interactive embedding): ajustar uma vez e, depois, incorporar novos pontos de dados com transform (útil em pipelines de produção).

O UMAP não se limita à visualização; ele pode produzir incorporações com qualquer n_components (por exemplo, 5–50) para modelos a jusante.

Intuição: variedades e grafos

O nome do UMAP reflete duas ideias:

  1. Hipótese de variedade (manifold assumption): dados de alta dimensionalidade do mundo real frequentemente ficam próximos de uma “superfície” (variedade (manifold)) de dimensionalidade muito menor embutida no espaço original. Por exemplo, imagens de um objeto girando podem variar ao longo de poucos graus de liberdade, apesar de terem milhares de pixels.

  2. Aproximação baseada em grafos (graph-based approximation): em vez de aprender explicitamente a variedade, o UMAP aproxima a estrutura local da variedade construindo um grafo de k-vizinhos mais próximos (kNN), em que arestas conectam pontos próximos.

O algoritmo busca preservar vizinhanças locais: pontos que estão próximos no espaço original devem permanecer próximos na incorporação. Diferentemente de métodos estritamente locais, o UMAP também tenta (até certo ponto) manter um arranjo global coerente por meio de como ele “costura” as vizinhanças locais.

Etapas do algoritmo em alto nível

Em alto nível, o UMAP faz o seguinte:

  1. Calcula k-vizinhos mais próximos para cada ponto sob uma métrica de distância escolhida (euclidiana, cosseno, etc.).
  2. Converte as relações de vizinhança em um grafo difuso ponderado (weighted fuzzy graph):
    • Para cada ponto, o UMAP atribui uma força de pertinência suave a cada vizinho (mais forte quanto mais próximo).
    • Em seguida, combina essas pertinências direcionadas em um grafo ponderado não direcionado.
  3. Otimiza uma incorporação de baixa dimensionalidade:
    • Inicializa pontos em baixa dimensionalidade (frequentemente com inicialização espectral (spectral initialization) a partir do grafo).
    • Move os pontos para minimizar uma perda que incentiva arestas com alto peso a ficarem próximas e não-arestas a ficarem distantes.

Essa visão de “casamento de grafos” é uma das formas mais práticas de raciocinar sobre o comportamento do UMAP: seus hiperparâmetros (hyperparameters) controlam principalmente como o grafo é construído e quão apertado o arranjo empacota vizinhos.

Um pouco mais de teoria (sem entrar de vez em topologia)

O artigo original do UMAP enquadra o método usando geometria riemanniana (Riemannian geometry) e conjuntos simpliciais difusos (fuzzy simplicial sets), mas você pode entender seu objetivo central como alinhar dois grafos “quase probabilísticos”:

  • Um grafo difuso de alta dimensionalidade: arestas ponderadas representam o quão fortemente pontos estão conectados (vizinhos) no espaço original.
  • Um grafo difuso de baixa dimensionalidade: arestas ponderadas representam o quão fortemente pontos estão conectados na incorporação.

O UMAP então minimiza um objetivo do tipo entropia cruzada (cross-entropy–like objective) entre esses grafos. Na prática, a otimização é realizada com descida do gradiente estocástica (stochastic gradient descent) e amostragem negativa (negative sampling) (amostrando pares não vizinhos) para manter a escalabilidade.

O que isso implica na prática

  • O UMAP se importa principalmente com relações relativas de vizinhança, não com distâncias exatas.
  • Distâncias entre clusters muito afastados em 2D podem ser sugestivas, mas não estritamente significativas.
  • O algoritmo é estocástico; diferentes sementes aleatórias (random seeds) podem gerar arranjos diferentes (frequentemente similares, mas não idênticos).

Hiperparâmetros-chave (e o que eles realmente fazem)

Dois hiperparâmetros dominam o comportamento do UMAP: n_neighbors e min_dist.

`n_neighbors`: estrutura local vs global

n_neighbors controla quantos vizinhos cada ponto conecta no grafo kNN.

  • n_neighbors menor (por exemplo, 5–15):

    • Foca em estrutura bem local.
    • Frequentemente produz clusters mais compactos e mais fragmentados.
    • Pode separar subclusters finos, mas pode exagerar a separação.
  • n_neighbors maior (por exemplo, 30–100+):

    • Incorpora vizinhanças mais amplas.
    • Frequentemente oferece um arranjo mais “global” e variedades mais suaves.
    • Pode mesclar clusters pequenos ou reduzir a separação.

Regra prática:

  • Para visualização de clusters, comece em 15–30.
  • Para trajetórias/variedades contínuas (estágios de desenvolvimento, séries temporais), tente 30–100.

`min_dist`: quão “apertados” os pontos ficam

min_dist controla a distância efetiva mínima entre pontos na incorporação (afeta o formato da curva de força atrativa).

  • min_dist menor (por exemplo, 0.0–0.1):

    • Permite empacotamento bem apertado.
    • Produz clusters compactos e visualmente separados.
    • Útil para perguntas do tipo “há estrutura de clusters?”.
  • min_dist maior (por exemplo, 0.3–0.8):

    • Força os pontos a se espalharem mais.
    • Melhor para visualizar variação contínua dentro de clusters.
    • Frequentemente reduz artefatos de super-agrupamento.

Regra prática:

  • Use 0.0–0.1 para classes discretas.
  • Use 0.2–0.5 para estrutura gradual.

Outros controles importantes

Embora n_neighbors e min_dist sejam os parâmetros de destaque, estes também costumam importar:

  • metric (métrica (metric)):

    • Euclidiana é comum para atributos contínuos.
    • Cosseno frequentemente é melhor para incorporações de texto (text embeddings) e muitas incorporações neurais (neural embeddings).
    • Para dados binários/esparsos, considere métricas apropriadas (e às vezes um pré-processamento diferente, como TF-IDF + SVD).
  • n_components:

    • 2 ou 3 para visualização.
    • Maior (por exemplo, 10–50) se você quiser uma representação compacta para modelos a jusante.
  • random_state:

    • Defina para reprodutibilidade. Sem isso, os arranjos podem mudar entre execuções.
  • init:

    • A inicialização espectral frequentemente produz arranjos globais mais estáveis do que inicialização aleatória.
  • densmap (se suportado pela sua implementação):

    • Variante que tenta preservar densidade relativa; útil quando diferenças de densidade são significativas e você não quer que elas sejam excessivamente distorcidas.

Exemplo prático: UMAP para visualização em dados tabulares

Um fluxo típico é escalar atributos → ajustar o UMAP → plotar.

import umap
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler

X, y = load_digits(return_X_y=True)

X_scaled = StandardScaler().fit_transform(X)

reducer = umap.UMAP(
    n_neighbors=30,
    min_dist=0.1,
    n_components=2,
    metric="euclidean",
    random_state=42,
)

Z = reducer.fit_transform(X_scaled)  # Z is (n_samples, 2)

Plote Z com sua biblioteca de gráficos favorita (matplotlib, seaborn, plotly), colorindo por y. Se você vir sobreposição de classes, tente:

  • aumentar n_neighbors para enfatizar estrutura mais ampla, ou
  • diminuir min_dist para deixar os clusters mais compactos (para visualização).

Incorporando novos pontos de dados (`transform`)

Uma vantagem comum sobre t-SNE é que o UMAP pode incorporar novos pontos em um espaço já existente:

Z_train = reducer.fit_transform(X_scaled)

# Later: new examples
X_new_scaled = StandardScaler().fit_transform(X[:10])  # in real use, reuse the same scaler
Z_new = reducer.transform(X_new_scaled)

Em produção, você deve reutilizar o mesmo pré-processamento (por exemplo, o mesmo scaler ajustado) antes de chamar transform.

Exemplo prático: UMAP para incorporações neurais de texto (distância cosseno)

Para incorporações de modelos como sentence transformers, a distância cosseno frequentemente é uma geometria melhor do que a euclidiana:

import umap
import numpy as np

# Suppose E is (n_samples, d) embedding matrix from a text model
E = np.load("embeddings.npy")

reducer = umap.UMAP(
    n_neighbors=50,
    min_dist=0.3,
    metric="cosine",
    random_state=42,
)
Z = reducer.fit_transform(E)

Se a visualização parecer “raios” ou ilhas excessivamente separadas, tente:

  • aumentar n_neighbors,
  • aumentar min_dist,
  • ou reduzir ruído aplicando primeiro uma redução linear (linear reduction) leve (veja a próxima seção).

Dicas de pré-processamento que afetam fortemente os resultados

O UMAP é sensível à geometria do espaço de entrada. Um bom pré-processamento pode importar mais do que ajustar hiperparâmetros.

Escalonamento e normalização

  • Para atributos numéricos tabulares, padronize (média zero, variância unitária).
  • Para atributos baseados em contagens, considere TF-IDF ou outra normalização.
  • Para incorporações, frequentemente a normalização L2 (L2-normalization) é apropriada (especialmente se estiver usando cosseno).

“PCA e depois UMAP” costuma ser uma boa ideia

Mesmo que PCA seja linear, fazer primeiro uma pequena redução com PCA pode:

  • remover ruído,
  • acelerar a busca de vizinhos,
  • estabilizar resultados.

Uma heurística comum para atributos densos de alta dimensionalidade:

  • PCA para 30–100 dimensões, depois UMAP para 2D/3D.

Isso é especialmente comum em fluxos também usados com t-SNE.

Como interpretar gráficos do UMAP (e o que não superinterpretar)

Gráficos do UMAP são convincentes, mas fáceis de interpretar errado.

Interpretações boas:

  • Vizinhanças são significativas: pontos próximos entre si provavelmente são similares sob sua métrica escolhida.
  • Identidade de cluster pode ser informativa: “ilhas” frequentemente correspondem a grupos nos dados.

Interpretações arriscadas:

  • Distâncias exatas entre clusters: dois clusters estarem distantes não significa necessariamente “duas vezes mais diferentes”.
  • Tamanhos de cluster como densidades: área/compactação aparentes podem ser afetadas por parâmetros como min_dist, amostragem e o objetivo da incorporação.

Se decisões dependerem da estrutura, valide com checagens quantitativas no espaço original (por exemplo, pureza de vizinhos mais próximos (nearest-neighbor purity), estabilidade de clusters ou desempenho a jusante).

UMAP vs PCA vs t-SNE: quando usar cada um

UMAP, PCA e t-SNE se sobrepõem em casos de uso, mas se comportam de forma diferente.

Use PCA quando

  • Você quer uma projeção linear rápida, determinística e interpretável.
  • Você se importa com variância explicada e estrutura linear.
  • Você quer redução de dimensionalidade principalmente para compressão ou como linha de base.

Veja Análise de Componentes Principais (PCA).

Use t-SNE quando

  • Seu objetivo principal é visualização 2D/3D enfatizando estrutura de vizinhança muito local.
  • Você não precisa de uma forma fácil de incorporar novos pontos depois.
  • Você pode arcar com maior tempo de execução e sensibilidade a parâmetros.

O t-SNE pode produzir excelente separação visual de clusters, mas é notoriamente difícil de interpretar globalmente e costuma ser mais lento.

Veja t-SNE.

Use UMAP quando

  • Você quer incorporações não lineares de alta qualidade com boa velocidade/escalabilidade.
  • Você quer um método que frequentemente preserve mais organização global do que o t-SNE (ainda focando em localidade).
  • Você quer transformar novos pontos em uma incorporação existente (por exemplo, pipelines de monitoramento).
  • Você quer flexibilidade via métricas e dimensionalidade da incorporação.

O UMAP frequentemente é a escolha padrão em fluxos modernos de visualização de incorporações.

E quanto ao Kernel PCA?

PCA com kernel é uma extensão não linear do PCA usando kernels. Pode funcionar bem quando você tem um bom kernel para os dados e quer uma abordagem mais “parecida com PCA”, mas pode ser menos escalável do que o UMAP em conjuntos de dados muito grandes e não mira diretamente a preservação de vizinhos da forma como UMAP/t-SNE fazem.

Escolhendo `n_neighbors` e `min_dist`: receitas práticas

Alguns pontos de partida que funcionam bem na prática:

Se você suspeita de clusters discretos (por exemplo, classes)

  • n_neighbors: 15–30
  • min_dist: 0.0–0.1
  • Considere metric="cosine" para incorporações.

Se você suspeita de trajetórias contínuas (por exemplo, tempo, desenvolvimento)

  • n_neighbors: 30–100
  • min_dist: 0.2–0.5
  • Tente um n_neighbors maior se a trajetória se quebrar em fragmentos.

Se o conjunto de dados é enorme (100k+ pontos)

  • Comece com uma pré-redução via PCA/SVD.
  • Considere subamostragem para visualização, ou ajuste o UMAP em um subconjunto e depois use transform no restante.
  • Espere que o ajuste de parâmetros importe menos do que a busca de vizinhos e a qualidade do pré-processamento.

Armadilhas comuns e solução de problemas

“O gráfico muda muito entre execuções”

  • Defina random_state.
  • Use um pipeline de pré-processamento consistente.
  • Considere n_neighbors maior para uma estrutura global mais estável.

“Tudo vira uma bolha só”

  • Diminua n_neighbors para enfatizar vizinhanças locais.
  • Diminua min_dist para permitir clusters mais compactos.
  • Verifique se a métrica combina com seus dados (cosseno vs euclidiana).
  • Garanta que você escalonou/normalizou adequadamente.

“Muitas ilhas pequenas / fragmentação excessiva”

  • Aumente n_neighbors.
  • Aumente min_dist.
  • Considere uma pré-redução com PCA para remover ruído.

“Os clusters parecem significativos, mas o desempenho do modelo a jusante não melhora”

O UMAP é otimizado para preservação de vizinhança em um espaço de incorporação, não necessariamente para maximizar desempenho preditivo. Para tarefas supervisionadas, compare com:

  • uso dos atributos originais,
  • redução linear (PCA),
  • aprendizado de representações baseado em modelo.

Considere também variantes supervisionadas (algumas implementações de UMAP suportam usar rótulos para enviesar a incorporação), mas trate isso como uma escolha de modelagem que pode vazar estrutura dos rótulos para a visualização.

Aplicações além da visualização

Incorporações do UMAP são frequentemente usadas como entradas para:

  • Agrupamento (clustering) (por exemplo, k-means, HDBSCAN) para agrupar pontos em um espaço reduzido. Isso pode ajudar quando o espaço original é ruidoso ou extremamente de alta dimensionalidade, mas também pode introduzir distorções — valide clusters no espaço original quando possível.
  • Busca aproximada de vizinhos mais próximos (approximate nearest neighbor search) em dimensões menores (às vezes útil, mas não garante preservar todas as relações de vizinhança perfeitamente).
  • Engenharia de atributos (feature engineering): usar n_components > 2 para criar atributos compactos para modelos mais simples.

(Se você fizer agrupamento nas saídas do UMAP, trate isso como um pipeline heurístico, e não como uma abordagem teoricamente garantida.)

Resumo

O UMAP é um método poderoso e moderno de redução de dimensionalidade não linear que:

  • constrói um grafo kNN difuso (fuzzy kNN graph) para capturar estrutura local de vizinhança,
  • aprende uma incorporação de baixa dimensionalidade otimizando um objetivo de alinhamento de grafos (graph alignment objective),
  • expõe hiperparâmetros intuitivos:
    • n_neighbors (trade-off entre local e global),
    • min_dist (compactação vs espalhamento de clusters),
  • frequentemente serve como um forte padrão para visualização de incorporações, com melhor escalabilidade e reusabilidade do que t-SNE, ao mesmo tempo em que é mais expressivo do que PCA.

Para obter os melhores resultados, escolha uma métrica consistente com seus dados, aplique um pré-processamento sensato (frequentemente incluindo escalonamento e, às vezes, PCA), ajuste n_neighbors/min_dist para corresponder às suas expectativas de “cluster vs contínuo” e evite superinterpretar distâncias globais em gráficos 2D.