Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Image: ubuntu2004
El Algoritmo de K Means
El problema de agrupamiento es uno de los problemas más importantes del reconocimiento de patrones; se trata de encontrar estructura en una colección de datos. Una definición vaga de agrupamiento podría ser “el proceso de organizar objetos en grupos cuyos miembros son similares de alguna manera”. Por lo tanto, un grupo es una colección de objetos que son "similares" entre ellos y son "diferentes" a los objetos que pertenecen a otros grupos. Uno de los algoritmos más usados para resolver este problema es el algoritmo de K Means.
¿Qué es K Means?
Es un algoritmo para buscar una cantidad, dada por nosotros, de patrones en un conjunto de datos. Este algoritmo aunque es sencillo, es bastante potente por los resultados que genera. Supongamos que tenemos 10,000 datos y tenemos que clasificar cada dato en al menos 5 categorías, encontrando algún criterio de clasificación. Esta tarea tal cual sería super difícil, requeriría muchísimos análisis de distintos tipos para que encontráramos algún patrón, y esto tardaría varios días o semanas. Sin embargo, podemos ejecutar K-Means para que encuentre 5, 6 o tantas clasificaciones como queramos y aunque sean muchos datos, puede encontrar las categorías que deseemos usando criterios estadísticos en su comportamiento. Por esto es un algoritmo muy valorado en la ciencia de datos.
Entendamos el algoritmo
Antes de programarlo, primero comprendamos conceptualmente cómo funciona el algoritmo de K Means. K means imagina cada grupo como un sistema solar. La estrella alrededor de la que gira todo (todas los datos) en el grupo se conoce como centroide del grupo.
Entonces, dado un conjunto de centroides y sus coordenadas, podemos averiguar fácilmente a qué grupo pertenece cada dato calculando a qué centroide está más cerca (en términos de distancia euclidiana).
Pero, ¿cómo decidimos dónde están los centroides? Ahí es donde entra el algoritmo de K means. Primero, elegimos un valor para , el número de centroides, supongamos que . Luego, podemos elegir 3 puntos al azar y asignarlos para que sean nuestros centroides iniciales. Y usando nuestros centroides iniciales elegidos al azar, podemos crear 3 grupos. Suena un poco tonto, ¿verdad? ¿De qué sirve elegir centroides aleatorios y crear grupos aleatorios?
Aquí está el truco: las medias de nuestros grupos se convierten en nuestros nuevos centroides (para cada grupo, calculamos la media y la media, y esa es la coordenada de nuestro nuevo centroide). Y siempre que nuestros centroides iniciales seleccionados al azar fueran incluso ligeramente diferentes entre sí, los nuevos centroides (las medias del grupo) serán más óptimos que nuestros centroides iniciales; donde la optimalidad se define como maximizar la similitud dentro del grupo y la diferencia entre los grupos.
Una vez que tenemos nuestros nuevos centroides, podemos reasignar los datos en función de los nuevos centroides. Dado que los centroides se volvieron un poco más óptimos, nuestros grupos también deberían mejorar (en términos de homogeneidad dentro del grupo y varianza entre los grupos). Y ahora podemos volver a calcular nuevos centroides a partir de las medias de las coordenadas de los grupos reasignados. Estos centroides habrán mejorado nuevamente sobre sus predecesores, y podemos seguir repitiendo este proceso hasta que el algoritmo converja.
Los datos
Para mostrar el algoritmo ocuparemos un conjunto de datos que corresponde a puntos de la forma .
Y vamos a determinar una variable que corresponderá al número de categorías que vamos a ocupar para agrupar los datos
Centroides aleatorios iniciales
Ahora vamos a generar los centroides iniciales de manera aleatoria. Para esto primero determinaremos los valores mínimos y máximos de y .
Ahora generaremos los centroides de manera aleatoria, para ello generaremos un entero entre el valor mínimo y máximo de y un entero entre el valor mínimo y máximo de , los juntaremos en un punto, y los pondremos en una lista llamada mu
Veamos donde quedaron los centroides
Calculando los grupos
Para ayudarnos a calcular los grupos primero hagamos una función que nos diga la distancia (euclidiana) entre dos puntos.
Ahora necesitamos una función que, dado un conjunto de centroides, pueda decirnos a qué grupo pertenece cada dato. La siguiente función usa for anidados para calcular la distancia entre cada dato y cada centroide (usando nuestra función distancia). Luego, asigna cada dato a un grupo según el centroide al que esté más cercano. El resultado es la lista de las asignaciones de grupo de cada dato.
Llamemos Asignacion a la primera asignación de los datos a los centroides
Ahora en una lista llamada datos_divididos partamos el conjunto de datos de acuerdo con su centroide
Veamos como agrupó los datos
Calculando los nuevos centroides
Ahora necesitamos una función para el paso de actualización donde asignamos nuevos centroides. La siguiente función parte los datos de acuerdo al grupo que pertenecen. Luego toma los datos que pertenecen a un cierto grupo y calcular la media de dichos. Estas medias calculadas serán nuestros nuevos centroides.
Calculamos los nuevos centroides
Veamos como son los nuevos centroides
Corramos K Means
Vayamos con 3 grupos todavía (). Después de esto, ejecutamos un ciclo for 50 veces (50 es suficiente para la convergencia en este caso) donde calculamos repetidamente nuevos centroides (usando actualiza_centroides) y nuevos grupos (usando asignar_grupo) para que podamos obtener grupos óptimos. Recuerda que al repetir este proceso de calcular las medias de los grupos (también conocidos como nuevos centroides) y asignar nuevos grupos basados en estos nuevos centroides, es como el algoritmo converge a los grupos finales. Este proceso puede tardar algunos minutos.
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-6-0577dd3546dc> in <module>()
44 points(mu[Integer(0)], color="purple", size=Integer(80), marker="D") + points(datos_divididos[Integer(0)], color="purple", size=Integer(25)) + points(mu[Integer(1)], color="green", size=Integer(80), marker="D") + points(datos_divididos[Integer(1)], color="green", size=Integer(25)) +points(mu[Integer(2)], color="red", size=Integer(80), marker="D") + points(datos_divididos[Integer(2)], color="red", size=Integer(25))
45
---> 46 Mu=actualiza_centroides(datos, Asignacion, K)
47
48 datos_divididos=[ [datos[i] for i in srange(len(datos)) if Asignacion[i]==j ] for j in srange(K) ]
NameError: name 'actualiza_centroides' is not defined
Conclusiones
Obviamente, podemos hacer mucho más, incluido agregar más información (en este caso fue solo peso y altura, pero podríamos agregar cintura y/o cuello), ajustar (el número de grupos), determinar el número de veces que debemos iterar para que converja el algoritmo y tratar de comprender mejor la identidad y las características clave de cada grupo. Pero eso será en otra ocasión. Espero que al terminar esta práctica, se hayan llevado una idea de cómo es el problema de agrupamiento y cómo K Means usa un algoritmo maravillosamente simple para producir resultados geniales.
Ejercicio
Para esta práctica deberás recopilar dos datos distintos sobre una colección de, al menos, 100 objetos (en la explicación los datos fueron peso y altura y los objetos fueron personas) Estos datos deberán ser expresados con números enteros (si es necesario convierte los datos a una unidad de medida adecuada). Es importante que los datos sean variables que se puedan medir, es decir NO ocupes cosas como categorías o clases.
Después ejecuta el algoritmo de K Medias para algún cierto valor de K que consideres pueda ser adecuado e interpreta cual fue la clasificación que hizo el algoritmo. Postea el tipo de datos que obtuviste, una imagen de la clasificación obtenida y tus conclusiones sobre los grupos que generó el algoritmo.