Machine Learning: Redução de Dimensionalidade

Última atualização: 2026-08-26

No espaço de alta dimensionalidade, cada ponto está longe de todos os outros — a redução de dimensionalidade não é apenas compressão, é uma forma de revelar a verdadeira estrutura dos seus dados.

1. O que você vai aprender


2. A história real de um cientista de dados

(1) O problema: dados de comportamento de usuário de 50 dimensões que você não consegue ver ou entender

Bob coletou 50 features de comportamento de usuário (duração da sessão, contagem de cliques, taxas de engajamento por categoria, e assim por diante), mas não tinha como entender intuitivamente como os usuários estavam distribuídos — tabelas eram ilegíveis, gráficos de dispersão se limitam a duas dimensões, e os resultados de agrupamento eram difíceis de validar. Dados de alta dimensionalidade são uma caixa-preta para a intuição humana.

(2) A solução: PCA + t-SNE

PCA comprime os dados para duas dimensões preservando a variância máxima, e t-SNE mapeia a estrutura local em um plano 2D — tornando os dados de alta dimensionalidade algo que você pode realmente ver.

PYTHON
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler

X_scaled = StandardScaler().fit_transform(X_50d)

# PCA: rápido, preserva variância global
X_pca = PCA(n_components=2).fit_transform(X_scaled)

# t-SNE: lento, preserva estrutura local
X_tsne = TSNE(n_components=2, perplexity=30).fit_transform(X_scaled)

(3) O resultado: um gráfico 2D revela instantaneamente três grupos naturais de usuários

Após a redução de dimensionalidade, Bob conseguiu ver três grupos distintos de usuários de relance — alto valor, ativos e dormentes — que se alinhavam bem com seus resultados de agrupamento e permitiram à equipe de negócios entender a distribuição dos dados em segundos.


3. A maldição da dimensionalidade

(1) Fenômenos contraintuitivos em espaços de alta dimensionalidade

▶ Exemplo: Um experimento da maldição da dimensionalidade

PYTHON
import numpy as np

rng = np.random.default_rng(42)

for dim in [2, 10, 50, 100, 500]:
    n = 1000
    X = rng.uniform(0, 1, (n, dim))

    # Calcular distâncias par a par
    from sklearn.metrics import pairwise_distances
    dists = pairwise_distances(X)

    np.fill_diagonal(dists, np.inf)
    min_dist = dists.min()
    max_dist = dists.max()
    ratio = (max_dist - min_dist) / max_dist

    print(f"Dim={dim:4d}: min={min_dist:.3f}, max={max_dist:.3f}, "
          f"intervalo_relativo={ratio:.4f}")

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso
Dimensões Distância Mín Distância Máx Intervalo Relativo Significado
2 0,02 1,41 0,99 Distâncias são significativas
10 0,78 1,87 0,58 Distâncias começam a falhar
50 2,42 3,28 0,26 Distâncias são quase inúteis
100 3,54 4,05 0,13 Todas as distâncias convergem
500 8,11 8,47 0,04 Completamente quebradas

4. PCA (Análise de Componentes Principais)

(1) Como o PCA funciona

O PCA usa a decomposição em autovalores para encontrar as direções de variância máxima (os componentes principais) e projeta os dados em um espaço de menor dimensionalidade.

100%
graph TB
    INPUT[Dados Padronizados] --> COV[Calcular Matriz de Covariância]
    COV --> EIG[Decomposição em Autovalores]
    EIG --> SELECT[Selecionar Top K Autovetores]
    SELECT --> PROJECT[Projetar Dados em K Dimensões]
    PROJECT --> OUTPUT[Representação de Baixa Dimensão]

▶ Exemplo: Redução por PCA e razão de variância explicada

PYTHON
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
import numpy as np

X, y = load_iris(return_X_y=True)

# Padronizar primeiro (PCA é sensível à escala)
X_scaled = StandardScaler().fit_transform(X)

# PCA com todos os componentes para ver a variância explicada
pca_full = PCA()
pca_full.fit(X_scaled)

print("Razão de variância explicada:")
for i, (evr, cum) in enumerate(zip(pca_full.explained_variance_ratio_,
                                     pca_full.explained_variance_ratio_.cumsum())):
    print(f"  PC{i+1}: {evr:.3f} (cumulativa: {cum:.3f})")

# Reduzir para 2D
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
print(f"\n2D PCA preserva {pca.explained_variance_ratio_.sum():.1%} da variância")

# Visualizar
fig, ax = plt.subplots(figsize=(8, 6))
for target in np.unique(y):
    mask = y == target
    ax.scatter(X_pca[mask, 0], X_pca[mask, 1], label=load_iris().target_names[target], s=40)
ax.set_xlabel(f"PC1 ({pca.explained_variance_ratio_[0]:.1%})")
ax.set_ylabel(f"PC2 ({pca.explained_variance_ratio_[1]:.1%})")
ax.set_title("PCA do Conjunto de Dados Iris")
ax.legend()
plt.tight_layout()
plt.savefig("pca_iris.png", dpi=150)

Saída:

TEXT 📖 Somente leitura
Razão de variância explicada:

(2) Escolhendo quantos componentes manter

▶ Exemplo: Gráfico de variância explicada cumulativa

PYTHON
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
n, p = 500, 50
X = rng.standard_normal((n, p))
# Tornar as primeiras 5 dimensões com mais sinal
X[:, :5] *= 3

X_scaled = StandardScaler().fit_transform(X)
pca = PCA().fit(X_scaled)

fig, ax = plt.subplots(figsize=(10, 5))
cumvar = pca.explained_variance_ratio_.cumsum()
ax.plot(range(1, len(cumvar)+1), cumvar, "b-o", markersize=3)
ax.axhline(0.95, color="red", linestyle="--", label="95% da variância")
ax.axhline(0.90, color="orange", linestyle="--", label="90% da variância")
ax.set_xlabel("Número de Componentes")
ax.set_ylabel("Variância Explicada Cumulativa")
ax.set_title("Variância Explicada pelo PCA")
ax.legend()
n_95 = (cumvar < 0.95).sum() + 1
print(f"Componentes para 95% da variância: {n_95}")
plt.tight_layout()
plt.savefig("pca_variance.png", dpi=150)

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso
Limiar Significado Resultado típico
90% Mantém o sinal principal 5–15 componentes (para 50 dimensões)
95% Mantém mais detalhes 10–25 componentes (para 50 dimensões)
99% Quase sem perdas 20–40 componentes (para 50 dimensões)

5. Visualização por Manifold com t-SNE

(1) Como o t-SNE funciona

O t-SNE preserva as relações de vizinhança local, minimizando a divergência KL entre similaridades par a par nos espaços de alta e baixa dimensionalidade.

▶ Exemplo: Visualização com t-SNE

PYTHON
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
import numpy as np

X, y = load_digits(return_X_y=True)
X_scaled = StandardScaler().fit_transform(X)

# t-SNE com diferentes perplexity
fig, axes = plt.subplots(1, 3, figsize=(18, 5))

for ax, perplexity in zip(axes, [5, 30, 50]):
    tsne = TSNE(n_components=2, perplexity=perplexity, random_state=42, init="pca")
    X_tsne = tsne.fit_transform(X_scaled)

    scatter = ax.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap="tab10", s=5, alpha=0.7)
    ax.set_title(f"t-SNE (perplexity={perplexity})")
    ax.set_xlabel("t-SNE 1")
    ax.set_ylabel("t-SNE 2")

plt.tight_layout()
plt.savefig("tsne_perplexity.png", dpi=150)

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso

(2) Pontos de atenção com o t-SNE

Consideração Notas
perplexity Tipicamente 5–50. Menor → foca em vizinhos próximos; maior → foca na estrutura global
Semente aleatória Sementes diferentes podem dar resultados diferentes — fixe random_state
Não usar downstream O t-SNE não preserva distâncias, então é inadequado como entrada para um modelo
Lento para calcular Para grandes conjuntos de dados (>10k), reduza com PCA primeiro, depois execute t-SNE
Tamanho do cluster não tem significado O t-SNE pode exagerar ou diminuir os tamanhos relativos dos clusters

▶ Exemplo: Acelerando o t-SNE com pré-processamento PCA

PYTHON
from sklearn.manifold import TSNE
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import numpy as np

rng = np.random.default_rng(42)
X = rng.standard_normal((5000, 50))

# t-SNE direto (lento)
# tsne = TSNE(n_components=2, random_state=42)
# X_tsne = tsne.fit_transform(X)  # Muito lento em 5000x50!

# Melhor prática: PCA primeiro, depois t-SNE
X_scaled = StandardScaler().fit_transform(X)
X_pca_30 = PCA(n_components=30).fit_transform(X_scaled)  # PCA rápido para 30D
X_tsne = TSNE(n_components=2, perplexity=30, random_state=42,
              init="pca", learning_rate="auto").fit_transform(X_pca_30)

print(f"Shape PCA→t-SNE: {X_tsne.shape}")

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso

6. Prática: Redução de Dimensionalidade para Comportamento de Usuário em E-commerce

▶ Exemplo: Features de usuário de 50 dimensões → visualização 2D

PYTHON
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
n = 3000

# Gerar dados de comportamento de usuário de 50 dimensões com 3 grupos naturais
group1 = rng.normal(loc=2, scale=1, size=(800, 50))   # Usuários de alto valor
group2 = rng.normal(loc=0, scale=1.5, size=(1200, 50)) # Usuários regulares
group3 = rng.normal(loc=-2, scale=0.8, size=(1000, 50)) # Usuários dormentes
X = np.vstack([group1, group2, group3])

# Adicionar dimensões de ruído
X[:, 20:] += rng.normal(0, 3, (n, 30))

# Padronizar
X_scaled = StandardScaler().fit_transform(X)

# PCA para 2D
X_pca = PCA(n_components=2).fit_transform(X_scaled)

# t-SNE para 2D (com pré-processamento PCA)
X_pca30 = PCA(n_components=30).fit_transform(X_scaled)
X_tsne = TSNE(n_components=2, perplexity=30, random_state=42,
              init="pca", learning_rate="auto").fit_transform(X_pca30)

# Rótulos K-Means para referência
labels = KMeans(n_clusters=3, random_state=42, n_init=10).fit_predict(X_scaled)

# Visualizar
fig, axes = plt.subplots(1, 2, figsize=(16, 6))

for ax, X_2d, title in [(axes[0], X_pca, "PCA"), (axes[1], X_tsne, "t-SNE")]:
    scatter = ax.scatter(X_2d[:, 0], X_2d[:, 1], c=labels, cmap="Set1", s=8, alpha=0.6)
    ax.set_title(title)
    ax.set_xlabel(f"{title} 1")
    ax.set_ylabel(f"{title} 2")

plt.tight_layout()
plt.savefig("user_behavior_dim_reduction.png", dpi=150)

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso

(1) PCA vs t-SNE vs UMAP

Aspecto PCA t-SNE UMAP
O que preserva Variância global Vizinhanças locais Global + local
Velocidade Rápido (<1s) Lento (minutos) Médio (segundos)
Reprodutibilidade Determinístico Dependente de seed Dependente de seed
Interpretabilidade Alta (variância explicada) Baixa Média
Uso downstream ✅ Usável como features ❌ Apenas visualização ⚠️ Precisa de validação
Mapeamento de novos dados ✅ transform ❌ Precisa rerodar ✅ transform

❓ Perguntas Frequentes

P: Posso usar dados reduzidos por PCA para treinar modelos? R: Sim. Os componentes principais do PCA podem ser usados como entrada para modelos, e são especialmente úteis em cenários de alta dimensionalidade com poucas amostras. Lembre-se: ajuste o PCA no conjunto de treino e apenas transforme o conjunto de teste.

P: Por que o t-SNE não pode ser usado como features de modelo? R: O t-SNE não preserva relações de distância global, e não consegue transformar novos dados (você precisa recomputar do zero a cada vez). É adequado apenas para visualização, não como entrada de modelo.

P: Como escolher o parâmetro perplexity? R: O intervalo típico é 5–50. Para conjuntos de dados pequenos (~1k), use 5–20; para dados grandes (10k+), use 30–50. Teste alguns valores e escolha o que produzir os clusters mais nítidos.

P: PCA exige padronização? R: Com certeza. PCA maximiza a variância, então se suas features estão em escalas diferentes (por exemplo, idade vs. renda), as features de alta variância dominarão os componentes principais. Sempre execute StandardScaler antes do PCA.

P: O que torna o UMAP melhor que o t-SNE? R: Três vantagens — 1) é 10–100x mais rápido; 2) preserva mais estrutura global; 3) suporta transformação de novos dados. A desvantagem é que você precisa instalá-lo separadamente com pip install umap-learn.

P: Quanta informação é perdida na redução de dimensionalidade? R: Depende de quantos componentes você mantém. Reter 95% da variância geralmente significa perder apenas cerca de 5% da informação — e o que é descartado pode ser apenas ruído. Use cumsum(explained_variance_ratio_) para decidir.


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Execute o PCA no conjunto de dados Iris para reduzi-lo a 2 dimensões, plote um gráfico de dispersão e anote a razão de variância explicada. Dica: PCA(n_components=2) + scatter.
  2. Intermediário (Dificuldade ⭐⭐): Nos dados load_digits (64 dimensões), primeiro reduza para 30 dimensões com PCA, depois para 2 dimensões com t-SNE. Compare o tempo de execução e a qualidade da visualização do t-SNE direto versus PCA + t-SNE. Dica: meça o tempo com time.time().
  3. Desafio (Dificuldade ⭐⭐⭐): Gere dados de 50 dimensões com 3 grupos de usuários, reduza para 2D usando PCA, t-SNE e UMAP respectivamente, e avalie com agrupamento K-Means (ARI/NMI) para determinar qual método melhor preserva a estrutura original dos grupos. Dica: sklearn.metrics.adjusted_rand_score.

← Anterior: Aprendizado por Ensemble | Próximo: Fundamentos de NLP →

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%