¿Cómo implementar un algoritmo de clustering con K-Means en Python?
Hoy vamos a adentrarnos en la implementación del algoritmo K-Means, específicamente usando el método de mini lotes (MiniBatch K-Means), para un clustering efectivo y eficiente. Utilizaremos un conjunto de datos que contiene características de 85 diferentes caramelos. El objetivo: obtener un análisis detallado de cómo agrupar estos caramelos de manera significativa.
¿Qué es el conjunto de datos de caramelos?
El conjunto de datos de caramelos cuenta con 85 tipos diferentes y varias características:
Nombre del caramelo: Identificación del caramelo.
Atributos en composición: Si contiene chocolate, frutas, etc.
Porcentaje de azúcar: Cantidad relativa de azúcar respecto a otros caramelos.
Porcentaje de precio: Precio comparativo con los demás.
Preferencia del público: Proporción de veces que fue elegido en pruebas comparativas uno a uno.
¿Cómo preparamos los datos en Python?
Primero importamos las librerías necesarias y cargamos los datos en un DataFrame de pandas.
import pandas as pd
from sklearn.cluster import MiniBatchKMeans
# Cargar el archivo Candy.csv dentro del entorno de pandasdf = pd.read_csv('data/Candy.csv')print(df.head(10))# Verificar las primeras 10 filas
Es importante observar los datos para asegurarnos de haberlos cargado correctamente.
¿Qué es y cómo funciona MiniBatch K-Means?
MiniBatch K-Means es una variación del tradicional algoritmo K-Means, especialmente optimizado para funcionar en máquinas con recursos limitados. Funciona agrupando subconjuntos de datos (lotes) en vez de la totalidad, reduciendo así el uso de memoria y tiempo de cómputo.
¿Cómo configuramos y entrenamos el modelo?
En esta ocasión, vamos a configurar nuestro modelo para 4 clusters. Esta decisión se basa en la idea ficticia de una tienda que desea organizar sus dulces en 4 estanterías, basándose en sus similitudes.
# Configuración del modelokmeans = MiniBatchKMeans(n_clusters=4, batch_size=8)# Entrenar el modelo con los datoskmeans.fit(df.drop(columns=['nombre_caramelo']))
¿Cómo interpretamos los resultados?
Una vez entrenado el modelo, obtenemos:
Centros de cluster: Verificamos que se han creado 4 centros como deseamos.
print(kmeans.cluster_centers_)
Predicciones de cluster: Cada caramelo se categoriza en uno de los 4 clusters, facilitando la interpretación de a qué grupo se parece más un caramelo.
Exportar los resultados a un archivo para compartición o análisis futuro.
Graficar datos para visualizar los clusters, si deseamos un análisis visual más intuitivo.
df.to_csv('clustered_candy.csv')
Este ejemplo de K-Means culmina con la integración de los datos y sus clusters en un único archivo, facilitando el análisis posterior. ¡Ahora depende de ti explorar y seguir aprendiendo sobre métodos de clustering y sus aplicaciones en diferentes áreas!
Les comparto una gráfica con las variables del dataset candy pareadas.
import seaborn as sns
sns.pairplot(dataset, hue='group')
Por otra parte acá también les comparto enfocadas las variables, sugarpercent, pricepercent y winpercent. Se puede observar como el algoritmo de clustering puede generar los grupos que son imposibles de notar a simple vista.
Hola, compañeros. Aquí les dejo una visualización de los datos coloreados por el grupo al que pertenecen. Hice un scatter con las variables que pueden ver en los ejes, por supuesto que pueden existir otras formas de visualizar cambiando los ejes de la scatter.
Saludos! :)
puedes pasar el codigo por favor ? he intentado visualizarlos agrupados y no he podido
Hola, Javier. Claro! Aquí te comparto el código. En este caso use la librería de seaborn de python que sirve para graficar de manera fácil.
import seaborn as sns
sns.scatterplot(data=dataset, x="sugarpercent", y="winpercent", hue="group",palette="deep")
En este caso es importante que tengamos el dataset trabajado igual que en la clase para que todos los nombres coincidan y funcione el código. :)
Antes de implementar el algoritmo de clusterización es bueno normalizar los datos como habíamos visto en clases pasadas, ya que si se dan cuenta está tomando como referencia la columna con valores más grandes del dataframe, que en este caso es "winpercent" y clasificando por puntaje, y no es el objetivo del algoritmo.
import pandas as pd
import seaborn as sns
from xlsxwriter importWorkbookfrom sklearn.clusterimportMiniBatchKMeansfrom sklearn.preprocessingimportStandardScalerif __name__ =="__main__": dataset = pd.read_csv('./data/candy.csv')print(dataset.head(10))X_cols=list(set(dataset.columns)-set(['competitorname']))X= dataset[X_cols].values sc_x =StandardScaler()
#standarizacion de los datos
X_std= sc_x.fit_transform(X) kmeans =MiniBatchKMeans(n_clusters=4, batch_size=8).fit(X_std)print(f'Total de centros: {len(kmeans.cluster_centers_)}')print("="*64)print(f'Predicciones: {kmeans.predict(X_std)}') dataset['group']= kmeans.predict(X_std)print(dataset)print(dataset['group'].value_counts()) # Ahora mando los datos a un archivo excel :)with pd.ExcelWriter('data/candy_usuario.xlsx', engine="xlsxwriter")aswriter: dataset.to_excel(writer, sheet_name='usuario') # dataset.to_excel(r'data/candy_usuario.xlsx', sheet_name='usuario', index =False) #implementacion_k_means
# sns.scatterplot(data=dataset, x="sugarpercent", y="winpercent", hue="group", palette="deep") #
# sns.pairplot(dataset[['sugarpercent','pricepercent','winpercent','group']], hue='group')
les paso mi version del codigo:
import pandas as pd
from sklearn.clusterimportMiniBatchKMeansif __name__ =="__main__": path ='./K-Means/data/candy.csv' dataset = pd.read_csv(path)print(dataset.head(5)) x = dataset.drop('competitorname', axis=1) kmeans =MiniBatchKMeans(n_clusters=4, batch_size=8).fit(x)print('')print('Total de centros:',len(kmeans.cluster_centers_))print('')print('Predicciones:', kmeans.predict(x)) dataset['Grupo']= kmeans.predict(x)print(dataset) # Ahora mando los datos a un archivo excel :) writer = pd.ExcelWriter('./K-Means/data/candy_usuario.xlsx', engine='xlsxwriter') dataset.to_excel(writer, sheet_name='usuario') writer.save()
writer.save()
Genera:
FutureWarning: save is not part of the public API, usage can give in unexpected results and will be removed in a future version writer.save()
with pd.ExcelWriter('data/candy_usuario.xlsx', engine="xlsxwriter")aswriter: dataset.to_excel(writer, sheet_name='usuario')
Se me hace curioso el hecho de que la columna 'winpercent' parece ser la que hace todo el trabajo de agrupación. Si eliminamos esa columna, vemos con las gráficas que no se encuentra ningún patrón claro en el dataset.
También eliminé la columna 'winpercent' y con el algoritmo de Kmeans() sí me encontró el mismo patrón en 30 iteraciones:
!Kmeans
Parece que lo que no está funcionando adecuadamente, al menos para estos datos es el algoritmo de MiniBatchKMeans(), aunque reduciendo el batch a 1 parece que comienza a encontrar algún patrón.
Le pregunté a ChatGPT que me ampliara un poquito la información sobre MiniBatchKmeans y esta fue su respuesta:
MiniBatchKMeans es una variante del clásico algoritmo de agrupamiento K-means diseñada para funcionar eficientemente con conjuntos de datos grandes. K-means es un algoritmo de aprendizaje no supervisado utilizado para agrupar datos en K grupos según sus similitudes de características. Su objetivo es minimizar la suma de las distancias al cuadrado entre los puntos de datos y los centroides de sus respectivos grupos.
El algoritmo K-means estándar puede ser computacionalmente costoso, especialmente para conjuntos de datos grandes, ya que requiere calcular las distancias entre todos los puntos de datos y todos los centroides de los grupos en cada iteración. Esto puede ser problemático cuando se trabaja con conjuntos de datos grandes que no caben en la memoria.
MiniBatchKMeans aborda este problema utilizando mini-batches de datos para cada iteración, en lugar de utilizar todo el conjunto de datos. Se toma una muestra aleatoria de puntos de datos (mini-batch) y se actualizan los centroides de los grupos utilizando esta muestra en cada iteración. Este enfoque es más eficiente computacionalmente, ya que requiere menos cálculos de distancias y permite procesar conjuntos de datos grandes sin consumir una cantidad excesiva de memoria.
Beneficios clave de MiniBatchKMeans:
Mayor velocidad de cálculo: Al utilizar mini-batches, el algoritmo puede procesar conjuntos de datos grandes de manera más eficiente, lo que lo hace adecuado para escenarios de big data.
Escalabilidad: Puede manejar conjuntos de datos que no caben en la memoria, ya que opera con subconjuntos más pequeños de datos a la vez.
Eficiencia de memoria: Debido a su naturaleza iterativa, consume menos memoria en comparación con el algoritmo K-means estándar.
Sin embargo, existe un equilibrio con MiniBatchKMeans. El uso de mini-batches introduce cierto nivel de aleatoriedad, lo que puede resultar en asignaciones de grupos menos estables y soluciones potencialmente subóptimas en comparación con el algoritmo K-means clásico. No obstante, en la práctica, MiniBatchKMeans suele proporcionar buenos resultados de agrupamiento mientras reduce significativamente los requisitos computacionales.
En resumen, MiniBatchKMeans es una herramienta valiosa cuando se trabaja con conjuntos de datos grandes y recursos de memoria limitados, proporcionando una solución eficiente y escalable para tareas de agrupamiento.
from matplotlib import pyplot as plt
import pandas as pd
import plotly.expressas px
import plotly.graph_objectsas go
import seaborn as sns
from xlsxwriter importWorkbookfrom sklearn.clusterimportMiniBatchKMeansfrom sklearn.preprocessingimportStandardScalerfrom sklearn.decompositionimportPCAif __name__ =="__main__": dataset = pd.read_csv('./data/candy.csv')X_cols=list(set(dataset.columns)-set(['competitorname']))X= dataset[X_cols].values sc_x =StandardScaler()
#standarizacion de los datos
X_std= sc_x.fit_transform(X) kmeans =MiniBatchKMeans(n_clusters=4, batch_size=8).fit(X_std)print(f'Total de centros: {len(kmeans.cluster_centers_)}')print("="*64)print(f'Predicciones: {kmeans.predict(X_std)}') dataset['group']= kmeans.predict(X_std)print(dataset['group'].value_counts()) # Ahora mando los datos a un archivo excel :) # with pd.ExcelWriter('data/candy_usuario.xlsx', engine="xlsxwriter")aswriter: # dataset.to_excel(writer, sheet_name='usuario') # dataset.to_excel(r'data/candy_usuario.xlsx', sheet_name='usuario', index =False) #implementacion_k_means
# sns.scatterplot(data=dataset, x="sugarpercent", y="winpercent", hue="group", palette="deep") #
# sns.pairplot(dataset[['sugarpercent','pricepercent','winpercent','group']], hue='group')'''Realizado por mi para ver las graficas y los centroides de manera visual''' def pca_fun(n_components, data): pca =PCA(n_components=n_components).fit(data) data = pca.transform(data)return data
pca_data =pca_fun(2,X_std) kmeans =MiniBatchKMeans(n_clusters=4, batch_size=8).fit(pca_data) fig = px.scatter( x=pca_data[:,0], y=pca_data[:,1], color=kmeans.predict(pca_data)) # Aqui anexamos a la misma figura cada trazo
fig.add_trace(go.Scatter( x=kmeans.cluster_centers_[:,0], y=kmeans.cluster_centers_[:,1], mode='markers', marker=dict(size=20, color='white'), name='Centroides')) fig.update_layout(title=f'Visualizacion de centroides sobre PCA de 2 componentes, se escalo data antes de PCA', coloraxis_showscale=False) fig.show() ##################### PCA3 componentes
pca_data =pca_fun(3,X_std) kmeans =MiniBatchKMeans(n_clusters=4, batch_size=8).fit(pca_data) fig = px.scatter_3d( x=pca_data[:,0], y=pca_data[:,1], z=pca_data[:,2], color=kmeans.predict(pca_data)) # Aqui anexamos a la misma figura cada trazo
fig.add_trace(go.Scatter3d( x=kmeans.cluster_centers_[:,0], y=kmeans.cluster_centers_[:,1], z=kmeans.cluster_centers_[:,2], mode='markers', marker=dict(size=20, color='white'), name='Centroides')) fig.update_layout(title=f'Visualizacion de centroides sobre PCA de 3 componentes, se escalo data antes de PCA', coloraxis_showscale=False) fig.show()'''No funciona somoclu al parecer por el python usado.3.10.(no pienso bajar mi version de python ya que quiero aprender a usar match case) https://github.com/peterwittek/somoclu/issues/144, link de fuente para implementacion de esta libreria:https://www.kaggle.com/code/phyothuhtet/document-clustering-self-organizing-map-kmeans'''
# import somoclu
#
# def som(data): # som = somoclu.Somoclu(50,50, data=data, maptype="toroid") # %time som = som.train(data) # print("Comonent Planes") # return som
#
# som =som(pca_data) #
# #ExploringComponentPlanes # #labels is 0 to n(document-0,document-1,...documentn) # labels =range(0,pca_data.shape[0]) #
# # Step4:ExploringContentPlanes # som.view_component_planes() #
# # Step5:Exploring clusters by SOM reinforced withDoc2Vec # som.view_umatrix(bestmatches =True)
Para los que usan colab:
candy.to_excel( "candy.xlsx",index=False)
donde candy es el nombre de mi dataset y pongo index=False para que no me aparezca 0,1,2,,,,, a mi lado izquierdo del excel y tenga una mejor presentación
Como podemos medir el performance de este modelo?
Normalmente, la agrupación en clústeres se considera un método no supervisado, por lo que es difícil establecer una buena métrica de rendimiento (como también se sugirió en los comentarios anteriores).
No obstante, se puede extrapolar mucha información útil de estos algoritmos (por ejemplo, k-medias). El problema es cómo asignar una semántica a cada grupo y así medir el "rendimiento" de su algoritmo. En muchos casos, una buena forma de proceder es mediante una visualización de sus clústeres. Obviamente, si sus datos tienen características de alta dimensión, como sucede en muchos casos, la visualización no es tan fácil. Permítanme sugerir dos caminos a seguir, usando k-means y otro algoritmo de agrupamiento.
K-mean : en este caso, puede reducir la dimensionalidad de sus datos utilizando, por ejemplo, PCA . Con dicho algoritmo, puede trazar los datos en un gráfico 2D y luego visualizar sus grupos. Sin embargo, lo que ve en este gráfico es una proyección en un espacio 2D de sus datos, por lo que puede no ser muy preciso, pero puede darle una idea de cómo se distribuyen sus clústeres.
Self-organizing map: es un algoritmo de agrupamiento basado en redes neuronales que crea una representación discretizada del espacio de entrada de las muestras de entrenamiento, llamado mapa, y es, por lo tanto, un método para realizar la reducción de dimensionalidad ( SOM ). Puede encontrar un paquete de Python muy agradable llamado somoclu que tiene este algoritmo implementado y una forma fácil de visualizar el resultado. Este algoritmo también es muy bueno para la agrupación en clústeres porque no requiere una selección a priori del número de clústeres (en k-mean debe elegir k, aquí no).
Buena info! Gracias DataEngel :D
Si tengo un nuevo dulce es necesario agregarlo al dataframe y correr el algoritmo completo? o existe alguna forma de mirar a que grupo pertenece solamente?
haces kmeans.predict(nuevo_dulce), y eso te dará la predicción de a que grupo pertnece.
hola frida en kmeans.predict(nuevo_dulce) como pongo el parametro?? gracias
Ojo lo que esta haciendo de reemplazar la columna group por los valores predichos por el modelo lo esta haciendo porque K-means es un modelo de aprendizaje no supervisado, el modelo es el que se encarga de hacer la clasificacion.
Esta creando esa columna, no está reemplazando.
chambelan de caramelo
Estos modelos si bien pueden ayudar a encontrar grupos no recomiendo mucho elegir la cantidad de K a ojo , Esto al igual que los otros modelos Tambien se puede mirar que tan bien o no está el modelo por ejemplo para k= 4
Coeficiente de silueta : 0.21068614495211394
Profesor, ¿alguna idea de porqué utilizando el mismo dataset clasifica los datos de manera disinta?
En su ejemplo el dulce One dime está clasificado en el grupo "0" mientras que en mi caso lo clasifica en grupo "2"
¿Están usando Seeds? esa es la primera opción.
Te recomendaría fijar un seed, y luego verificar, igual sería bueno que comentes de qué video es que es el problema y cuáles son tus parámetros utilizados
@larispardo Lo resolví seteando un random_state fijo. Gracias
¿Por qué me marca "FutureWarning"? Y por si acaso, mi código es prácticamente igual al del maestro
Hola. Tengo una duda. Veo que el data set tiene datos métricos y no métricos. Que distancia usaste? Es que no veo la declaración explicita. En R se usa la distancia gower de la librería Daisy cuando son datos mixtos, pero aqui cuál se usa y se declara implícita (es decir la librería lo determina) o el analista lo hace? Gracias
No deberia marcar las iteraciones de kmeans?
En la clase se implementó el algoritmo Batch K-Means utilizando un conjunto de datos de caramelos. Se explicó cómo cargar los datos con pandas, preparar las columnas para el modelo, y luego se configuraron y entrenaron los K-Means definiendo cuatro grupos. Se verificaron los centros generados y se predijeron las etiquetas de cada caramelo. Finalmente, se añadieron las predicciones al DataFrame original y se discutió la importancia de agrupar datos similares para la toma de decisiones.