Passo 1: Preparação e Normalização
O PCA e o K-Means são sensíveis à escala dos dados. Como as medidas das pétalas e sépalas estão em centímetros, mas possuem intervalos diferentes, o primeiro passo é a Padronização (Standardization), garantindo que cada característica tenha média 0 e variância 1.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
# Carregando os dados
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
# Normalizando (essencial para PCA e K-Means)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(df)
Passo 2: Redução de Dimensionalidade (PCA)
Agora, transformamos as 4 dimensões originais em 2 Componentes Principais (PC1 e PC2). Isso nos permite ver o "mapa" das flores em um plano bidimensional.
# Aplicando o PCA
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
# Calculando a variância explicada
var_expl = pca.explained_variance_ratio_
print(f"Variância capturada: PC1 ({var_expl[0]:.2%}), PC2 ({var_expl[1]:.2%})")
Variância capturada: PC1 (72.96%), PC2 (22.85%)
O PC1 geralmente captura a "tamanho geral" da flor, enquanto o PC2 foca no contraste entre largura e comprimento.
Passo 3: Agrupamento (K-Means)
Com os dados simplificados, pedimos ao algoritmo para encontrar os 3 grupos naturais. Note que não fornecemos os rótulos originais das espécies para o algoritmo; ele trabalha de forma não supervisionada.
# Criando e treinando o modelo K-Means
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
clusters = kmeans.fit_predict(X_pca)
# Adicionando os resultados ao dataframe para visualização
df_plot = pd.DataFrame(X_pca, columns=['PC1', 'PC2'])
df_plot['Cluster'] = clusters
Passo 4: Visualização e Interpretação
Abaixo, plotamos o resultado. O gráfico mostra como o PCA separou os dados e como o K-Means definiu as fronteiras de cada grupo.
plt.figure(figsize=(10, 6))
sns.scatterplot(x='PC1', y='PC2', hue='Cluster', data=df_plot, palette='viridis', s=100)
# Plotando os centroides
centroids = kmeans.cluster_centers_
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', s=200, marker='X', label='Centroides')
plt.title('Agrupamento K-Means sobre Componentes Principais (PCA)')
plt.xlabel(f'PC1 ({var_expl[0]:.1%})')
plt.ylabel(f'PC2 ({var_expl[1]:.1%})')
plt.legend()
plt.show()
Análise dos Resultados
Separação Natural: Você notará que um dos clusters (geralmente a Setosa) fica isolado à esquerda. Isso indica que ela é morfologicamente muito distinta das outras duas.
Sobreposição: Os outros dois clusters (referentes a Versicolor e Virginica) costumam ficar mais próximos. Se algum ponto de um grupo estiver "dentro" da área do outro no gráfico, isso explica por que classificadores às vezes cometem erros nessas espécies.
Eficiência do PCA: Como PC1 e PC2 somam cerca de 95% da variância, o gráfico acima é uma representação extremamente fiel da realidade, apesar de termos descartado metade das variáveis originais.
O Hierarchical Clustering (Agrupamento Hierárquico) oferece uma perspectiva diferente do K-Means. Em vez de tentar encontrar centros de grupos, ele constrói uma hierarquia de similaridade. No dataset Iris, isso é fascinante porque revela quais espécies são "primas" próximas.
Como funciona o Dendrograma?
Imagine que cada flor começa como seu próprio cluster. O algoritmo identifica o par de flores mais parecido e os une. Ele repete isso até que todos os dados estejam sob um único grande "tronco". O Dendrograma é o mapa visual dessa árvore.
import numpy as np
from scipy.cluster.hierarchy import dendrogram, linkage
# Calculando a matriz de ligação (linkage matrix)
# O método 'ward' minimiza a variância dentro dos clusters que estão sendo unidos
Z = linkage(X_scaled, method='ward')
# Criando o Dendrograma
plt.figure(figsize=(12, 7))
plt.title('Dendrograma de Agrupamento Hierárquico - Iris Dataset')
plt.xlabel('Índice das Amostras (ou tamanho do grupo)')
plt.ylabel('Distância Euclidiana')
dendrogram(
Z,
truncate_mode='lastp', # Mostra apenas os últimos p grupos unidos
p=12, # Mostrar os últimos 12 nós para não poluir o gráfico
leaf_rotation=90.,
leaf_font_size=12.,
show_contracted=True,
)
# Linha de corte para 3 clusters
plt.axhline(y=10, color='r', linestyle='--')
plt.text(0, 11, 'Corte para 3 Clusters', color='r', fontweight='bold')
plt.show()
Diferença Prática: K-Means vs HierárquicoK-Means: É mais rápido para grandes conjuntos de dados, mas exige que você escolha o número de clusters ($k$) antecipadamente.
Hierárquico: É mais lento, porém mais rico em informações, pois não apenas agrupa, mas explica a estrutura de parentesco entre os dados.