SingularCode

Algoritmo Kmeans

Algoritmo K-means

O algoritmo K-means é uma técnica de aprendizado de máquina não supervisionado, amplamente utilizada para a tarefa de agrupamento (ou “clustering”). O objetivo do K-means é dividir um conjunto de dados (N) em (K) grupos distintos (ou “clusters”), de forma que cada ponto pertença ao grupo cuja média (ou “centroide”) é a mais próxima possível. Este algoritmo é particularmente útil para identificar padrões subjacentes nos dados e para organizar grandes volumes de dados em categorias significativas, facilitando a análise e a interpretação.

Funcionamento do Algoritmo K-means:

  1. Inicialização: Primeiro, escolhem-se (K) pontos aleatórios dos dados como os centroides iniciais.
  2. Atribuição: Cada ponto do conjunto de dados é atribuído ao cluster cujo centroide é o mais próximo. A proximidade é geralmente medida usando a distância Euclidiana, embora outras métricas também possam ser utilizadas.
  3. Atualização do Centroide: Os centroides dos clusters são recalculados como a média de todos os pontos atribuídos ao cluster.
  4. Iteração: Os passos 2 e 3 são repetidos até que os centroides não se movam significativamente entre as iterações, o que indica que o algoritmo convergiu.

Exemplo de Aplicação em Python:

Vamos considerar um exemplo simples usando a biblioteca scikit-learn, que é uma das bibliotecas de aprendizado de máquina mais populares em Python. Suponha que temos um conjunto de dados bidimensional e queremos agrupá-los em (K=3) clusters.

Dados fixos:

#Carregar Bibliotecas
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

#Transformando dados em uma matriz
base_salario = np.array([[20,1000],[27,1200],[21,2900],[35,1850],[46,900],
                        [53,950],[55,2000],[47,2100],[52,3000],[32,5900],
                        [39,4100],[41,5100],[39,7000],[48,5000],[48,6500]])

#Plotando os pontos
grafico = px.scatter(x = base_salario[:,0], y = base_salario[:,1])
grafico.show()

#Deixar os valores na mesma escala (escalonados), Existe uma grande diferença entre a idade e o salario
scaler_salario = StandardScaler()
base_salario_escalonado = scaler_salario.fit_transform(base_salario)
base_salario_escalonado

#Enviar os dados para o algoritmo Kmeans
kmeans_salario = KMeans(n_clusters=3)
kmeans_salario.fit(base_salario_escalonado)

#Mostrar os centroides. Será exibido de forma escalonada
centroides_escalonados = kmeans_salario.cluster_centers_
centroides_escalonados

#Centroides convertidos não escalonada
centroides = scaler_salario.inverse_transform(centroides_escalonados)
centroides

#Mostrar os rótulos
rotulos = kmeans_salario.labels_
rotulos

#Gerar o gráfico
grafico1 = px.scatter(x = base_salario[:,0], y = base_salario[:,1], color=rotulos)
grafico2 = px.scatter(x = centroides[:,0], y = centroides[:,1], size=[1,1,1])
grafico3 = go.Figure(data = grafico1.data + grafico2.data)
grafico3.show()

Dados Aleatórios:

#Carregar Bibliotecas
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans

#Dados Aleatórios
X_random, k_random = make_blobs(n_samples=200, centers=5, random_state=1)

#Valores de x,y
X_random

#Valores de k
k_random

#Plotando os pontos
grafico = px.scatter(x = X_random[:,0], y = X_random[:,1])
grafico.show()

#Enviar os dados para o algoritmo Kmeans
kmeans_salario = KMeans(n_clusters=5)
kmeans_salario.fit(X_random)

#Mostrar os centroides. Será exibido de forma escalonada
centroides = kmeans_salario.cluster_centers_
centroides

#Mostrar os rótulos
rotulos = kmeans_salario.labels_
rotulos

#Gerar o gráfico
grafico1 = px.scatter(x = base_salario[:,0], y = base_salario[:,1], color=rotulos)
grafico2 = px.scatter(x = centroides[:,0], y = centroides[:,1], size=[1,1,1,1,1])
grafico3 = go.Figure(data = grafico1.data + grafico2.data)
grafico3.show()

Aplicações do K-means:

O K-means pode ser aplicado a uma ampla gama de problemas, como:

Segmentação de Mercado: Agrupar clientes com características semelhantes para campanhas de marketing direcionadas.

Organização de Inventário: Agrupar produtos em categorias baseadas em características ou comportamento de compra.

Detecção de Anomalias: Identificar padrões incomuns ou outliers.

Agrupamento de Documentos: Agrupar documentos com temas ou palavras-chave semelhantes para facilitar a organização ou a busca.

O algoritmo K-means é apreciado por sua simplicidade e eficácia, mas é importante notar que ele tem algumas limitações, como a sensibilidade à escolha dos centroides iniciais e a dificuldade em lidar com clusters de formas não esféricas ou tamanhos variados

Dataset Iris:

#Carregar Pandas
import pandas as pd
data = pd.read_csv('iris.csv')
data.head() #Mostra os primeiros registros do dataframe
data
list(data.columns) #Mostra os nomes das colunas do dataframe
data.info()

features = data.iloc[:,:-1] #todas as linhas (:) e todas as colunas exceto a última (:-1)
target = data.iloc[:,-1] #todas as linhas (:) e apenas a última coluna (-1)
print(features)
print(target)

X = data.iloc[:,0:4].values  #Separa somente as colunas das características
X

from sklearn.manifold import TSNE # Classe para redução da dimensionalidade
#Reduz de 4 para 2 características
X_reduzido = TSNE(n_components = 2).fit_transform(X)
X_reduzido

#Transforma as amostras obtidas pelo TSNE em dataframe
data_reduzido = pd.DataFrame(X_reduzido)
data_reduzido

#Extrai a coluna dos rótulos das classes
classes = data.iloc[:,4]
classes

#Reúne as amostras e os rótulos das classes
data_reduzido.insert(2, 'classe', classes)
data_reduzido

#Altera os nomes das colunas
data_reduzido = data_reduzido.rename(columns = {0: "carac_0", 1: "carac_1"})
data_reduzido

import seaborn as sns
#Plota as amostras reduzidas em 2D
sns.scatterplot(x = data_reduzido['carac_0'], y = data_reduzido['carac_1'],hue = data_reduzido.classe, style = data_reduzido.classe)

from sklearn.cluster import KMeans #Importação do algoritmo k-means
kmeans = KMeans(n_clusters = 3, init = 'random', n_init = 10, max_iter = 300, tol = 1e-04, random_state = 0) # Parametrização do modelo
kmeans.fit(X_reduzido) # Computa os centroides do clusters
predicao = kmeans.predict(X_reduzido) # Associa os objetos aos índices da classe

from sklearn.metrics import silhouette_score
score = silhouette_score(X_reduzido, predicao)
print('Silhouette Score: %.3f' % score)

from matplotlib import pyplot as plt
sns.scatterplot(x=X_reduzido[:,0], y=X_reduzido[:,1], hue=predicao, style=predicao)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=250, marker='*', c='red', edgecolor='black', label='centroids')
plt.legend(scatterpoints=1)
plt.grid()
plt.show()

O Silhouette Score é uma métrica usada para calcular a eficácia da clusterização, ou seja, o quão bem cada objeto foi classificado em seu cluster em comparação com outros clusters. Essa métrica fornece uma perspectiva sobre a separação de distância entre os clusters resultantes. O valor do Silhouette Score varia de -1 a 1, onde um valor alto indica que o objeto está bem combinado com seu próprio cluster e mal combinado com os clusters vizinhos.

 

Interpretação do Silhouette Score

Próximo de +1: Um valor próximo de +1 indica que o ponto está longe dos clusters vizinhos, ou seja, está bem posicionado dentro de seu próprio cluster e longe dos outros clusters. Isso sugere uma clusterização apropriada e clara.

Próximo de 0: Um valor próximo de 0 indica que o ponto está próximo à fronteira de decisão entre dois clusters vizinhos. Isso pode sugerir que a atribuição de clusters pode ser arbitrária, pois o ponto está igualmente distante de ambos os clusters.

Próximo de -1: Um valor próximo de -1 indica que o ponto foi atribuído ao cluster errado, estando mais próximo dos pontos de outro cluster

 

O que significa um Silhouette Score de 0.68?

Um Silhouette Score de 0.68 é considerado bom e indica que, em média, os pontos estão bem atribuídos aos seus clusters, com uma boa separação entre os clusters. Isso significa que a maioria dos pontos está mais próxima dos pontos dentro de seu próprio cluster do que dos pontos em clusters diferentes, sugerindo que a clusterização foi, em grande parte, bem-sucedida.

No entanto, é importante notar que esse valor é uma média, e pode haver variações individuais dentro dos clusters. Alguns pontos ainda podem estar mal posicionados ou mais próximos de outros clusters.

Dataset Wine:

Para aplicar o algoritmo K-means no dataset wine do sklearn, primeiro precisamos carregar esse dataset. O dataset wine é um conjunto de dados clássico que contém os resultados de uma análise química de vinhos cultivados em uma mesma região da Itália, mas derivados de três diferentes cultivares. O conjunto de dados consiste em 13 características diferentes medidas para cada amostra de vinho, com 178 amostras:

  • alcohol (álcool)
  • malic_acid (ácido málico)
  • ash (cinzas)
  • alcalinity_of_ash (alcalinidade das cinzas)
  • magnesium (magnésio)
  • total_phenols (fenóis totais)
  • flavonoids (flavonóides)
  • nonflavanoid_phenols (fenóis não flavonóides)
  • proanthocyanins (proantocinidinas)
  • color_intensity (intensidade de cor)
  • hue (matiz)
  • od280/od315_of_diluted_wines (od280/od315 de vinhos diluídos)
  • proline (proline)

Vamos seguir os passos para aplicar o K-means a este dataset:

  1. Carregar o dataset wine.
  2. Pré-processar os dados, se necessário (por exemplo, escalonamento dos dados).
  3. Aplicar o algoritmo K-means.
  4. Visualizar os resultados
import pandas as pd
data = pd.read_csv('wine.csv')
data.head() #Mostra os primeiros registros do dataframe
data
list(data.columns) #Mostra os nomes das colunas do dataframe
data.info()

features = data.iloc[:,1:] #todas as colunas começando da segunda coluna até a última
target = data.iloc[:,0] #todas as linhas (:) e apenas a primiera coluna
print(features)
print(target)

X = data.iloc[:,1:14].values  #Separa somente as colunas das características
X

from sklearn.manifold import TSNE # Classe para redução da dimensionalidade
#Reduz de 4 para 2 características
X_reduzido = TSNE(n_components = 2).fit_transform(X)
X_reduzido


#Transforma as amostras obtidas pelo TSNE em dataframe
data_reduzido = pd.DataFrame(X_reduzido)
data_reduzido

#Extrai a coluna dos rótulos das classes
classes = data.iloc[:,0]
classes

#Reúne as amostras e os rótulos das classes
data_reduzido.insert(2, 'wine', classes)
data_reduzido

#Altera os nomes das colunas
data_reduzido = data_reduzido.rename(columns = {0: "carac_0", 1: "carac_1"})
data_reduzido

import seaborn as sns
#Plota as amostras reduzidas em 2D
sns.scatterplot(x = data_reduzido['carac_0'], y = data_reduzido['carac_1'],hue = data_reduzido.wine, style = data_reduzido.wine)

from sklearn.cluster import KMeans #Importação do algoritmo k-means
kmeans = KMeans(n_clusters = 3, init = 'random', n_init = 10, max_iter = 300, tol = 1e-04, random_state = 0) # Parametrização do modelo
kmeans.fit(X_reduzido) # Computa os centroides do clusters
predicao = kmeans.predict(X_reduzido) # Associa os objetos aos índices da classe

from sklearn.metrics import silhouette_score
score = silhouette_score(X_reduzido, predicao)
print('Silhouette Score: %.3f' % score)

from matplotlib import pyplot as plt
sns.scatterplot(x=X_reduzido[:,0], y=X_reduzido[:,1], hue=predicao, style=predicao)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=250, marker='*', c='red', edgecolor='black', label='centroids')
plt.legend(scatterpoints=1)
plt.grid()
plt.show()

Interpretando um Silhouette Score de 0.62:

Um Silhouette Score de 0.62 é geralmente considerado um bom valor, indicando que, em média, os clusters estão bem definidos e separados. Pontos dentro de um cluster estão relativamente próximos uns dos outros, e há uma boa distância entre os clusters. Isso significa que a clusterização conseguiu agrupar os dados de uma maneira que os membros de cada cluster são mais semelhantes entre si do que com membros de outros clusters, o que é um indicativo de uma clusterização eficaz.

No entanto, é importante notar que o Silhouette Score fornece uma visão geral da qualidade da clusterização, mas não deve ser o único critério para avaliar a eficácia de um modelo de clusterização. Outros fatores, como conhecimento do domínio e objetivos específicos do projeto, também devem ser considerados na avaliação de um modelo de clusterização.

Atualizado em: 07/04/2024 por Nelson H. Koshoji