Vimos na base iris que, por conhecimento do "negócio" temos 3 classes (tiposd e flor), mas digamos que estivessemos entre muitas outras classes possíveis e quissemos saber qual melhor K, pesquisie algumas formas:
Silhouette Score
Davies-Bouldin
Calinski-Harabasz
Visualização (PCA, t-SNE, UMAP)
No teste com a base iris sempre apontou k=2, o que não é a realidade.
Na prática, alguém escolhe k não apenas matemáticamente, mas com conhecimento do negócio, pode ser que se deseje k 2,3,5,10 conforme o caso. Por exemplo, mesmo que aparente 2, a seleção pode ser 3. Mesmo que um silhoute mostre 7 um cliente pode preferir 5 grupos de um problema.
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics import (
silhouette_score,
davies_bouldin_score,
calinski_harabasz_score
)
from sklearn.decomposition import PCA
import pandas as pd
import matplotlib.pyplot as plt
# ======================
# Carregar e preparar dados
# ======================
iris = load_iris()
X = iris.data
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# ======================
# Testar vários valores de K
# ======================
resultados = []
for k in range(2, 11):
modelo = AgglomerativeClustering(
n_clusters=k,
linkage='ward'
)
labels = modelo.fit_predict(X_scaled)
silhouette = silhouette_score(X_scaled, labels)
davies = davies_bouldin_score(X_scaled, labels)
calinski = calinski_harabasz_score(X_scaled, labels)
resultados.append([
k,
silhouette,
davies,
calinski
])
# ======================
# Exibir métricas
# ======================
df_metricas = pd.DataFrame(
resultados,
columns=[
"k",
"Silhouette",
"Davies-Bouldin",
"Calinski-Harabasz"
]
)
print(df_metricas)
# Melhor K por cada métrica
print("\nMelhor Silhouette:")
print(df_metricas.loc[df_metricas["Silhouette"].idxmax()])
print("\nMelhor Davies-Bouldin:")
print(df_metricas.loc[df_metricas["Davies-Bouldin"].idxmin()])
print("\nMelhor Calinski-Harabasz:")
print(df_metricas.loc[df_metricas["Calinski-Harabasz"].idxmax()])
# ======================
# Escolha do K
# ======================
k_escolhido = 3 #PORQUE CONHECEMOS A BASE DE DADOS, O NEGÓCIO, O PROBLEMA, MATEMATIMENTE DEU "ERRADO" FICOU 2
modelo_final = AgglomerativeClustering(
n_clusters=k_escolhido,
linkage='ward'
)
labels = modelo_final.fit_predict(X_scaled)
# ======================
# PCA para visualização
# ======================
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
plt.figure(figsize=(8, 6))
scatter = plt.scatter(
X_pca[:, 0],
X_pca[:, 1],
c=labels
)
plt.title(
f"Agglomerative Clustering (k={k_escolhido})"
)
plt.xlabel("PCA 1")
plt.ylabel("PCA 2")
plt.colorbar(scatter, label="Cluster")
plt.show()