Desvendando a Clusterização em Python: Um Guia Prático

Guilherme Bernieri
Senior Sistemas
Published in
15 min readAug 11, 2023
Foto de Jason Leung na Unsplash

A clusterização é uma técnica de aprendizado não supervisionado usada na ciência de dados e aprendizado de máquina que agrupa objetos semelhantes em conjuntos, conhecidos como “clusters’’. Os objetos em um mesmo cluster são mais semelhantes entre si do que os de outros clusters, de acordo com algumas medidas de similaridade ou distância. Seja para agrupar clientes com comportamentos semelhantes para fazer recomendações de produtos, categorizar notícias ou textos com temas correlacionados, identificar padrões em imagens de produtos, ou até mesmo identificar outliers em conjuntos de dados, a clusterização é um recurso valioso.

Com a aplicação precisa de técnicas de clusterização, as empresas podem ajustar suas estratégias de marketing, gerenciamento de produtos, alocação de recursos e outras decisões críticas, resultando em uma redução significativa dos custos e aumento da eficiência. Além disso, a clusterização também permite que os negócios sejam mais proativos do que reativos, identificando grupos de clientes ou tendências emergentes e ajustando suas estratégias de acordo.

Neste artigo, você aprenderá a realizar essa tarefa de maneira bastante prática com o uso do scikit-learn, uma biblioteca Python para aprendizado de máquina! Aqui, discutiremos a implementação de algoritmos populares como K-means e Spectral Clustering, bem como a determinação do número ideal de clusters e a escolha de parâmetros para melhorar a eficácia do seu modelo de clusterização. Além disso, você aprenderá como visualizar os clusters formados de forma eficaz utilizando bibliotecas Python como Matplotlib e Seaborn. Seja você um iniciante tentando entender os conceitos básicos ou um profissional experiente procurando aprimorar suas habilidades, este artigo tem insights valiosos para todos.

Requisitos

Para seguir esse tutorial, vamos precisar instalar as seguintes bibliotecas.

!pip install pandas
!pip install numpy
!pip install seaborn
!pip install matplotlib
!pip install scikit-learn
!pip install ipython

Importações

Utilizaremos módulos essenciais da biblioteca scikit-learn:

  • sklearn.cluster para implementar algoritmos de clusterização como KMeans;
  • sklearn.manifold para redução de dimensionalidade usando TSNE e
  • sklearn.metrics para avaliar a qualidade dos clusters com o uso da função silhouette_score.

Essas ferramentas são fundamentais para a eficácia da implementação e avaliação da clusterização.

import sys
import time
import random
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans, MiniBatchKMeans, SpectralClustering
from sklearn.manifold import TSNE
from sklearn.metrics import silhouette_score
from sklearn.datasets import make_blobs
from IPython.display import clear_output

%matplotlib inline
print(f"Versão do Python: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")

Versão do Python: 3.11.3

Carregando os dados do dataset Fashion MNIST

Neste tutorial, utilizaremos o conjunto de dados Fashion MNIST, uma alternativa ao clássico dataset MNIST, que apresenta maior complexidade e relevância. Ele é composto por imagens de 28x28 pixels, em tons de cinza, de peças de roupas e acessórios, divididas em 10 categorias distintas. O dataset é balanceado, com 60.000 exemplos para treinamento e 10.000 exemplos para teste, tornando-o um recurso útil para a implementação e avaliação de algoritmos de aprendizado de máquina, incluindo a clusterização.

Mais detalhes sobre o dataset podem ser acessados em: https://www.kaggle.com/datasets/zalando-research/fashionmnist

O Fashion MNIST fornece uma divisão padrão dos dados de treinamento e teste. Neste tutorial, utilizaremos apenas os dados de treinamento, portanto, vamos carregar o respectivo arquivo.

fashion_mnist = pd.read_csv('./fashion_mnist/fashion-mnist_train.csv')

Vamos visualizar o formato do dataframe com os dados de treino.

fashion_mnist.shape

(60000, 785)

fashion_mnist.head()

Cada imagem é representada por uma linha do dataset contendo o label (rótulo) e uma coluna para cada pixel. Os valores de cada pixel podem variar de 0 a 255, onde 0 é a intensidade mínima (pixel desligado) e 255 é a intensidade máxima.

Como preparar os dados para o modelo

Primeiro vamos mapear os rótulos das categorias de imagens do Fashion MNIST.

label_map = {
0: 'Camisetas/Top',
1: 'Calças',
2: 'Suéteres',
3: 'Vestidos',
4: 'Casacos',
5: 'Sandálias',
6: 'Camisas',
7: 'Tênis',
8: 'Bolsas',
9: 'Botas'
}

Para facilitar a identificação dos registros, vamos substituir os valores na coluna label pelos nomes correspondentes a cada rótulo.

fashion_mnist['label'] = fashion_mnist['label'].map(label_map)
fashion_mnist.head()

Antes de continuar a preparação dos dados, vamos visualizar a distribuição das categorias das imagens.

label_counts = fashion_mnist['label'].value_counts()

plt.figure(figsize=(8,4))
label_counts.plot(kind='bar', color='skyblue')
plt.title('Distribuição das Categorias do Dataset Fashion MNIST')
plt.xlabel('Categorias')
plt.ylabel('Quantidade')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

Devido a grande quantidade de registros, vamos selecionar somente algumas categorias para otimizar o tempo de processamento.

labels_filter = ['Camisetas/Top', 'Camisas', 'Calças', 'Tênis', 'Botas', 'Bolsas']

fashion_mnist = fashion_mnist[fashion_mnist['label'].isin(labels_filter)].reset_index(drop=True)
fashion_mnist.shape

(36000, 785)

Para garantir que os rótulos das imagens não sejam utilizados no treinamento do modelo de clusterização, vamos separar o dataset de treinamento em features e labels.

features = fashion_mnist.drop(['label'], axis=1)
labels = fashion_mnist['label']

Como muitos algoritmos de clusterização são sensíveis à escala dos dados, será realizada uma normalização dividindo cada valor por 255. Esta técnica é comumente utilizada ao trabalhar com dados de imagem, onde a intensidade de cada pixel é representada por um valor entre 0 e 255. Dessa forma, a intensidade normalizada de cada pixel ficará na escala entre 0 e 1.

features_normalized = features.values / 255

Visualizando algumas imagens

Após processar os dados, vamos visualizar algumas imagens de cada categoria, selecionadas aleatoriamente do conjunto de dados. Para isso, remodelamos cada imagem, que inicialmente está em um array unidimensional, para a forma 28x28. Utilizamos a biblioteca Matplotlib para criar subplots em uma grade 2x3, cada um exibindo uma imagem em tons de cinza e titulada com o rótulo correspondente.

unique_labels = np.unique(labels)

samples = []

for label in unique_labels:
indices = np.where(labels == label)[0]
index = np.random.choice(indices)
samples.append(features_normalized[index])

fig, axs = plt.subplots(2, len(unique_labels)//2)

for i, (sample, ax) in enumerate(zip(samples, axs.flatten())):
sample = np.reshape(sample, (28,28))
ax.imshow(sample, cmap='Greys')
ax.set_title('label: {}'.format(unique_labels[i]))

plt.suptitle('Fashion MNIST')
plt.tight_layout()
plt.show()

Clusterização com K-means

O algoritmo K-means é um método popular e eficaz de clusterização utilizado em aprendizado de máquina. Ele é classificado como um algoritmo de aprendizado não supervisionado, pois não necessita de dados previamente rotulados para o treinamento. Em vez disso, ele procura identificar padrões e similaridades nos próprios dados. Uma particularidade do K-means é que o usuário deve definir previamente o número de clusters (K) a serem criados.

O funcionamento do K-means pode ser resumido em alguns passos principais:

1. Inicialização: Primeiro, o algoritmo escolhe aleatoriamente “K” pontos nos dados, que servirão como os centros iniciais dos clusters.

2. Atribuição: Cada ponto de dados é então atribuído ao cluster cujo centro está mais próximo, geralmente utilizando a distância euclidiana como medida.

3. Atualização: Os centros dos clusters são recalculados como a média (ou centroide) de todos os pontos atribuídos ao cluster.

4. Iteração: Os passos de atribuição e atualização são repetidos até que os centros dos clusters não se movam significativamente ou um número máximo de iterações seja atingido.

O algoritmo K-means é rápido e escalável, mas tem algumas limitações. Ele assume que os clusters são esféricos e de tamanho aproximadamente igual, o que pode não ser verdadeiro para todos os conjuntos de dados. Além disso, o resultado final pode variar dependendo dos centros de clusters iniciais, o que pode ser mitigado utilizando várias inicializações e escolhendo o resultado com a menor soma das distâncias quadradas (também conhecida como inércia).

Definindo o número ideal de clusters

Determinar o número ideal de clusters em um conjunto de dados é um dos desafios mais significativos no uso de algoritmos de clusterização, como o K-means. Essa dificuldade surge porque a qualidade do agrupamento não está necessariamente relacionada ao número de clusters: simplesmente aumentar o número de clusters não garante uma melhora na qualidade do agrupamento.

Dois métodos comumente utilizados para orientar a escolha do número de clusters são o método do cotovelo (Elbow) e o método da silhueta (Silhouette).

O método do cotovelo consiste em calcular a soma das distâncias quadradas intra-cluster (denotada como “inércia”) para cada K. Este valor geralmente diminui à medida que K aumenta, porque os pontos estão mais próximos dos centros de seus respectivos clusters. O “cotovelo” da curva formada pela inércia em função de K, geralmente, indica um bom número de clusters, pois é o ponto em que adicionar mais clusters não resulta em uma melhoria significativa.

O método da silhueta, por outro lado, mede quão bem cada ponto de dados se encaixa em seu cluster atribuído. O score da silhueta varia de -1 a 1, sendo 1 um ajuste perfeito e -1 o pior ajuste possível. Para cada K, o score da silhueta é calculado e armazenado.

Sendo assim, agora vamos implementar esses métodos para avaliar o número ideal de clusters do modelo. Faremos isso plotando a curva de Elbow e determinando o melhor número de clusters de acordo com Silhouette Score.

# Define o intervalo de valores k para testar
k_range = range(2, 15)

# Inicializa as listas para armazenar resultados
elbow = []
silhouette = []

# Calcula o KMeans para cada valor k
for k in k_range:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
kmeans.fit(features_normalized)

# Método do cotovelo
elbow.append(kmeans.inertia_)

# Método da silhueta
silhouette.append(silhouette_score(features_normalized, kmeans.labels_))

# Determina o melhor k com base na pontuação máxima da silhueta
best_k = k_range[np.argmax(silhouette)]

print('O número ideal de clusters é:', best_k)

O número ideal de clusters é: 8

O gráfico a seguir traz a curva do cotovelo gerada a partir das inércias dos clusters e uma linha tracejada indicando o número ideal de clusters considerando o método da silhueta.

fig, ax = plt.subplots()
ax.plot(k_range, elbow, 'bx-')
ax.set_xlabel('Número de clusters (k)')
ax.set_ylabel('Soma das distâncias quadradas (Elbow)')
ax.axvline(x=best_k, linestyle='--', color='red', label='Melhor número de clusters (Silhouette)')
ax.legend()
plt.title('Definição do Número de Clusters')
plt.tight_layout()
plt.show()

Podemos observar que o ponto em que as inércias começam a não ter uma redução significativa, à medida que o número de clusters aumenta, ocorre em k=9. Já o número ideal de clusters de acordo com o método da silhueta é em k=8. Sendo assim, um bom número de clusters a se considerar para o modelo seria 8 ou 9.

Treinamento do modelo

Agora que já identificamos o número de clusters adequado, vamos treinar o nosso modelo e avaliar os clusters gerados.

Utilizaremos o número de clusters determinado pelo método da silhueta (8 clusters), que foi armazenado na variável best_k, e os parâmetros padrões do algoritmo.

O parâmetro n_init, é responsável por determinar quantas vezes o algoritmo irá inicializar os centroides em pontos aleatórios para escolher o valor mais convergente, então quanto mais alto esse valor, maiores são as chances de ele encontrar pontos ótimos de centróides, porém maior será o tempo de treinamento necessário. Nesse caso, ao colocar o valor “auto(valor padrão do algoritmo), o algoritmo inicializará os centróides apenas uma vez.

kmeans = KMeans(n_clusters=best_k, random_state=42, n_init='auto')
kmeans.fit(features_normalized)

Visualização dos clusters

A vantagem de se utilizar um conjunto de dados de imagens, como o Fashion MNIST, é que podemos gerar uma visualização dos centróides de cada cluster. Isso nos permite visualizar uma “imagem média”, que serve como representação de cada cluster.

Para isso, vamos selecionar todas as imagens pertencentes a cada cluster e calcular a média dessas imagens ao longo do eixo 0. Ou seja, vamos calcular a média de todos os pixels de mesma posição em todas as imagens de cada cluster.

fig, axs = plt.subplots(2, 4, sharex=True, sharey=True)

for i in range(best_k):
images = features_normalized[kmeans.labels_ == i]
image = np.mean(images, axis=0)

ax = axs[i // 4, i % 4]
ax.imshow((image).reshape((28, 28)), cmap='Greys')
ax.set_title(f'cluster: {i}')

plt.tight_layout()
plt.suptitle('Clusters K-Means', fontsize=14)
plt.show()

Legal! Nosso modelo utilizando o K-means conseguiu fazer um agrupamento interessante das imagens. Podemos observar que cada cluster possui uma imagem de representação visualmente definida. É possível notar que, além das categorias que utilizamos para fazer o filtro inicial no conjunto de dados, Camisetas/Top, Camisas, Calças, Tênis, Botas e Bolsas, o modelo criou diferentes clusters para botas de cano baixo e botas de cano alto. Da mesma forma, parece que o modelo também distinguiu entre bolsas com alça e bolsas sem alça, mas vamos investigar isso melhor a seguir.

Para confirmar se as “imagens médias” definidas anteriormente realmente correspondem ao conteúdo dos clusters, vamos inspecionar alguns elementos de cada cluster.

Aqui será exibido apenas as imagens do cluster 6, mas você pode experimentar com os demais clusters.

cluster = 6

for i in range(0, 6):
images = features[kmeans.labels_ == cluster]
index = random.randint(0, len(images))
sample = np.reshape((images.iloc[index].values) / 255, (28,28))
plt.subplot(2, 3, i + 1)
plt.tight_layout()
plt.imshow(sample, 'Greys')

plt.tight_layout()
plt.suptitle(f'Cluster: {cluster}')
plt.show()

Para facilitar a identificação de cada cluster no futuro, vamos atribuir nomes para eles.

label_kmeans = {
0: 'Bolsas com alça',
1: 'Tênis',
2: 'Camisas',
3: 'Calças',
4: 'Botas cano baixo',
5: 'Camisetas/Top',
6: 'Bolsas sem alça',
7: 'Botas cano alto'
}

Visualizar as “imagens médias” dos clusters é um método bastante intuitivo para avaliar nossos agrupamentos. No entanto, o que fazer quando os dados que tentamos agrupar não são imagens? Nesse caso, podemos gerar um gráfico de dispersão (scatter plot) para visualizar a distribuição dos dados em um plano, vamos ver a seguir.

Nosso conjunto de dados, com suas 784 dimensões, sofre da maldição da dimensionalidade. Para plotarmos os pontos de dados em um espaço bidimensional, precisamos aplicar uma técnica de redução de dimensionalidade.

Vamos utilizar o t-SNE (t-Distributed Stochastic Neighbor Embedding), um algoritmo de aprendizado de máquina destinado à visualização de dados de alta dimensão em espaços de baixa dimensão. De maneira resumida, o t-SNE calcula as “vizinhanças” entre pontos no espaço original, transfere esses pontos para um espaço de baixa dimensão, mantendo as “vizinhanças”, e finalmente ajusta a distribuição dos pontos no espaço reduzido para se assemelhar à distribuição original.

tsne = TSNE(verbose=1, perplexity=50)
features_embedded = tsne.fit_transform(features.values)

E agora, após a redução da dimensionalidade, podemos plotar o gráfico de dispersão e comparar com as categorias originais das imagens.

fig, ax = plt.subplots(1,2)
fig.set_figwidth(15)
ax[1] = sns.scatterplot(x=features_embedded[:,0], y=features_embedded[:,1],
hue=labels.tolist(), legend='full', palette='nipy_spectral', ax=ax[1])
ax[0] = sns.scatterplot(x=features_embedded[:,0], y=features_embedded[:,1],
hue=pd.Series(kmeans.labels_).map(label_kmeans),
legend='full', palette='nipy_spectral', ax=ax[0])
ax[0].set_title('Clusters K-means')
ax[1].set_title('Categorias Originais')
plt.tight_layout()

Analisando o gráfico de dispersão, podemos observar que alguns clusters podem estar contendo imagens de outros clusters, como é o caso do cluster Calças, que parece estar misturando algumas imagens, principalmente do cluster Camisetas/Top e do cluster Camisas.

Podemos inspecionar o cluster Calças para verificar se a nossa observação faz sentido. Para isso, vamos visualizar algumas imagens aleatórias desse cluster.

cluster = 3

for i in range(0, 6):
images = features[kmeans.labels_ == cluster]
index = random.randint(0, len(images))
sample = np.reshape((images.iloc[index].values) / 255, (28,28))
plt.subplot(2, 3, i + 1)
plt.title('label: {}'.format(labels[images.index[index]]))
plt.tight_layout()
plt.imshow(sample, 'Greys')

plt.tight_layout()
plt.subplots_adjust(top=0.9)
plt.suptitle('Cluster: Calças')
plt.show()

Realmente, conforme verificamos anteriormente, existem algumas imagens que deveriam estar em outros clusters. Para tentar otimizar a precisão dos clusters, vamos experimentar uma variação do K-means que é desenvolvida para trabalhar com grandes conjuntos de dados.

Clusterização com Mini-Batch K-Means

O Mini-batch K-means é uma variação do tradicional algoritmo K-means. Este algoritmo é especialmente útil para conjuntos de dados grandes, pois é mais eficiente em termos de desempenho e custo computacional.

A execução do Mini-batch K-means pode ser compreendida em três etapas principais:

1. Seleção de Minibatch: Inicialmente, o algoritmo seleciona uma amostra aleatória dos dados, conhecida como minibatch. Essa seleção é feita em vez de usar todo o conjunto de dados, tornando o processo computacionalmente mais eficiente.

2. Atribuição de Clusters: A amostra selecionada é então atribuída aos clusters mais próximos, baseando-se na média dos pontos existentes nesse cluster. Os centróides dos clusters são então recalculados.

3. Iteração: Esse processo é repetido para diferentes minibatches no conjunto de dados até que a solução convirja, ou seja, até que os centróides dos clusters parem de mudar significativamente.

Uma vantagem significativa do Mini-batch K-means é que ele pode lidar com conjuntos de dados muito grandes de forma mais eficiente, comparado ao K-means tradicional. No entanto, é necessário que o usuário especifique o número de clusters e, além disso, o algoritmo pode ser sensível à inicialização e aos outliers. Devido à natureza estocástica do algoritmo, pode não encontrar a solução global ótima, mas geralmente encontra uma solução aceitável mais rapidamente do que o K-means tradicional.

Treinamento do modelo

Para comparar a qualidade dos clusters, vamos utilizar o mesmo número de clusters determinado pelo método da silhueta (8 clusters), que foi armazenado na variável best_k.

mb_kmeans = MiniBatchKMeans(n_clusters=best_k, random_state=42, n_init='auto')
mb_kmeans.fit(features_normalized)

Visualização dos clusters

Vamos visualizar novamente a “imagem média” que representa cada cluster.

fig, axs = plt.subplots(2, 4, sharex=True, sharey=True)

for i in range(best_k):
images = features_normalized[mb_kmeans.labels_ == i]
image = np.mean(images, axis=0)

ax = axs[i // 4, i % 4]
ax.imshow((image).reshape((28, 28)), cmap='Greys')
ax.set_title(f'cluster: {i}')

plt.tight_layout()
plt.suptitle('Clusters Mini-Batch K-Means', fontsize=14)
plt.show()

Interessante! Parece que nossos clusters perderam um pouco da sua capacidade de representação. O cluster 5 pode estar confundindo as imagens das categorias Camisas e Bolsas, enquanto o cluster 7 está misturando imagens das categorias Tênis e Camisas.

Vamos atribuir nomes aos novos clusters identificados.

label_mb_kmeans = {
0: 'Calças 1',
1: 'Bolsas',
2: 'Calças 2',
3: 'Camisetas/Top',
4: 'Botas cano baixo',
5: 'Camisas',
6: 'Botas cano alto',
7: 'Tênis'
}

Agora vamos visualizar como estão as distribuições dos clusters no gráfico de dispersão e comparar novamente com as categorias originais das imagens.

fig, ax = plt.subplots(1,2)
fig.set_figwidth(15)
ax[1] = sns.scatterplot(x=features_embedded[:,0], y=features_embedded[:,1],
hue=labels.tolist(), legend='full', palette='nipy_spectral', ax=ax[1])
ax[0] = sns.scatterplot(x=features_embedded[:,0], y=features_embedded[:,1],
hue=pd.Series(mb_kmeans.labels_).map(label_mb_kmeans),
legend='full', palette='nipy_spectral', ax=ax[0])
ax[0].set_title('Clusters Mini-batch K-means')
ax[1].set_title('Categorias Originais')
plt.tight_layout()

Pelo visto, ainda não chegamos a uma solução global ótima para nosso modelo de clusterização. Dessa forma, vamos experimentar uma técnica diferente de clusterização, baseada em grafos.

Clusterização com Spectral Clustering

O algoritmo Spectral Clustering é uma abordagem sofisticada e eficiente de clusterização, baseada em grafos.

A operação do Spectral Clustering pode ser simplificada nos seguintes passos principais:

1. Construção do Grafo: Primeiramente, o algoritmo cria um grafo ponderado a partir dos dados, onde cada ponto é um nó e os pesos das arestas representam a similaridade entre os pontos. O peso da aresta entre dois pontos é determinado com base na sua proximidade no espaço de características.

2. Cálculo da Matriz Laplaciana: O algoritmo então calcula a matriz Laplaciana do grafo. Esta matriz é uma representação do grafo que captura muitas de suas propriedades importantes.

3. Extração dos autovetores: Em seguida, o algoritmo extrai os K primeiros autovetores da matriz Laplaciana. Esses autovetores representam a estrutura de cluster do grafo.

4. Clustering dos autovetores: Os autovetores são então agrupados. Neste caso, em vez de usar o K-means tradicional, vamos utilizar o método cluster_qr. O método QR é robusto e pode lidar eficientemente com a multiplicidade dos autovetores.

5. Atribuição: Por fim, cada ponto de dados é atribuído ao cluster correspondente ao seu autovetor.

O algoritmo Spectral Clustering é poderoso e pode identificar clusters que não são necessariamente esféricos ou de tamanho igual, superando algumas das limitações do K-means. No entanto, pode ser mais computacionalmente intensivo, especialmente para conjuntos de dados grandes.

Treinamento do modelo

Agora, vamos treinar o nosso modelo! Devido às características do nosso conjunto de dados, ajustamos alguns parâmetros do algoritmo. O parâmetro affinity foi definido com a opção “nearest_neighbors, onde a matriz de afinidade é construída computando um grafo dos vizinhos mais próximos. E o parâmetro assign_labels foi definido com a opção “cluster_qr, onde os clusters são extraídos diretamente dos autovetores no agrupamento espectral.

spec = SpectralClustering(n_clusters=n_clusters, assign_labels='cluster_qr', affinity='nearest_neighbors', random_state=42)
spec.fit(features_normalized)

Visualização dos clusters

Novamente, vamos verificar a “imagem média” que representa cada cluster.

fig, axs = plt.subplots(2, 4, sharex=True, sharey=True)

for i in range(n_clusters):
images = features_normalized[spec.labels_ == i]
image = np.mean(images, axis=0)

if i == 6:
ax = axs[1, 2]
else:
ax = axs[i // 4, i % 4]

ax.imshow((image).reshape((28, 28)), cmap='Greys')
ax.set_title(f'cluster: {i}')

axs[1, 3].axis('off')

plt.tight_layout()
plt.suptitle('Clusters Spectral Clustering', fontsize=14)
plt.show()

Finalmente, temos uma representação que se aproxima muito das categorias originais do conjunto de dados. O modelo conseguiu generalizar melhor as imagens de botas e parece ter identificado melhor os padrões nas imagens de calças. No entanto, ele ainda persiste na divisão entre bolsas com alça e bolsas sem alça.

Vamos atribuir nomes aos clusters identificados.

label_spec = {
0: 'Bolsas sem alça',
1: 'Camisas',
2: 'Bolsas com alça',
3: 'Botas',
4: 'Camisetas/Top',
5: 'Calças',
6: 'Tênis'
}

E por fim, vamos plotar o gráfico de dispersão com os resultados da clusterização e comparar com as categorias originais.

fig, ax = plt.subplots(1,2)
fig.set_figwidth(15)
ax[1] = sns.scatterplot(x=features_embedded[:,0], y=features_embedded[:,1],
hue=labels.tolist(), legend='full', palette='nipy_spectral', ax=ax[1])
ax[0] = sns.scatterplot(x=features_embedded[:,0], y=features_embedded[:,1],
hue=pd.Series(spec.labels_).map(label_spec),
legend='full', palette='nipy_spectral', ax=ax[0])
ax[0].set_title('Clusters Spectral Clustering')
ax[1].set_title('Categorias Originais')
plt.tight_layout()

Conclusão

Excelente! Concluímos com sucesso a clusterização e chegamos a resultados bastante próximos das categorias originais das imagens. No entanto, é importante notar que, em situações reais, muitas vezes não teremos acesso às classes pré-definidas dos nossos dados para fazer essa comparação. Essa realidade reforça a importância de uma avaliação criteriosa dos clusters formados. A escolha apropriada dos algoritmos e dos parâmetros a serem utilizados nos dados é essencial para otimizar a eficácia do processo de clusterização. Lembre-se que, por mais que as técnicas e métodos possam ser genéricos, cada conjunto de dados é único e pode exigir ajustes e abordagens específicas. Portanto, a experimentação e o entendimento profundo dos seus dados e do contexto em que estão inseridos são ferramentas valiosas para obter os melhores resultados possíveis.

Referências

https://scikit-learn.org/stable/modules/clustering.html

https://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_silhouette_analysis.html

https://proceedings.neurips.cc/paper_files/paper/2004/hash/40173ea48d9567f1f393b20c855bb40b-Abstract.html

GERON, Aurélien. Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow: Concepts, Tools, and Techniques to Build Intelligent Systems. 2. ed. [S.l.]: O’Reilly Media, 2019.

--

--

Guilherme Bernieri
Senior Sistemas

Pesquisador | Inteligência Artificial | Tecnologia e Inovação