Serie de Aprendizaje No Supervisado Explorando el Clustering Jerárquico
'Exploring Hierarchical Clustering Unsupervised Learning Series'
Vamos a explorar cómo funciona el clustering hierarchical y cómo construye clusters basados en distancias pareadas.
En mi último post de la Serie de Aprendizaje no Supervisado, exploramos uno de los métodos de clustering más famosos, el Clustering K-means. En este post, vamos a discutir los métodos detrás de otra importante técnica de clustering: ¡el clustering hierarchical!
Este método también se basa en distancias (euclideas, manhattan, etc.) y utiliza una representación jerárquica de los datos para combinar puntos de datos. A diferencia de k-means, no contiene ningún hiperparámetro con respecto al número de centroides (como k) que los científicos de datos puedan configurar.
En su mayoría, el clustering hierarchical se puede dividir en dos grupos: clustering aglomerativo y clustering divisivo. En el primero, los puntos de datos se consideran unidades individuales y se agregan a los puntos de datos cercanos en función de las distancias. En el segundo, consideramos todos los puntos de datos como un solo cluster y comenzamos a dividirlos en función de ciertos criterios. Como la versión aglomerativa es la más famosa y ampliamente utilizada (la implementación incorporada de sklearn sigue este protocolo), ese es el tipo de clustering hierarchical que vamos a explorar en este post.
En esta publicación del blog abordaremos el Clustering Hierarchical Aglomerativo en dos pasos:
- Primero, haremos un análisis detallado de cómo se construyen las jerarquías, utilizando clustering aglomerativo con el método promedio (uno de los métodos que podemos usar para construir la jerarquía de puntos de datos).
- Luego, veremos algunos ejemplos de cómo ajustar un clustering hierarchical en un conjunto de datos reales utilizando la implementación de sklearn. Aquí es donde detallaremos otros métodos que podemos usar para construir nuestras jerarquías (ward, mínimo, etc.)
¡Comencemos!
- Las habilidades blandas que necesitas para tener éxito como científ...
- Una guía para manejar variables categóricas en Python.
- Pruebas de Bootstrap para Principiantes
Ejemplo de Clustering Aglomerativo – Paso a Paso
En nuestro ejemplo paso a paso, vamos a utilizar un conjunto de datos ficticio con 5 clientes:

Imaginemos que tenemos una tienda con 5 clientes y queremos agrupar a estos clientes en función de sus similitudes. Tenemos dos variables que queremos considerar: la edad del cliente y sus ingresos anuales.
El primer paso de nuestro clustering aglomerativo consiste en crear distancias pareadas entre todos nuestros puntos de datos. Hagamos eso representando cada punto de datos por sus coordenadas en un formato [x, y]:
- Distancia entre [60, 30] y [60, 55]: 25.0
- Distancia entre [60, 30] y [30, 75]: 54.08
- Distancia entre [60, 30] y [41, 100]: 72.53
- Distancia entre [60, 30] y [38, 55]: 33.30
- Distancia entre [60, 55] y [30, 75]: 36.06
- Distancia entre [60, 55] y [41, 100]: 48.85
- Distancia entre [60, 55] y [38, 55]: 22.0
- Distancia entre [30, 75] y [41, 100]: 27.31
- Distancia entre [30, 75] y [38, 55]: 21.54
- Distancia entre [41, 100] y [38, 55]: 45.10
Aunque podemos usar cualquier tipo de métrica de distancia que queramos, usaremos la euclidea debido a su simplicidad. De las distancias pareadas que hemos calculado anteriormente, ¿cuál es la distancia más pequeña?
¡La distancia entre clientes de mediana edad que ganan menos de 90 mil dólares al año — clientes en las coordenadas [30, 75] y [38, 55]!
Revisando la fórmula para la distancia euclidiana entre dos puntos arbitrarios p1 y p2:

Visualicemos nuestra distancia más corta en la trama 2-D conectando a los dos clientes que están más cerca:

¡El siguiente paso del agrupamiento jerárquico es considerar a estos dos clientes como nuestro primer clúster!

A continuación, vamos a calcular las distancias entre los puntos de datos, de nuevo. Pero esta vez, los dos clientes que hemos agrupado en un solo clúster se tratarán como un solo punto de datos. Por ejemplo, consideremos el punto rojo debajo que se posiciona en el medio de los dos puntos de datos:

En resumen, para las siguientes iteraciones de nuestra solución jerárquica, no consideraremos las coordenadas de los puntos de datos originales (emojis) sino el punto rojo (el promedio entre esos puntos de datos). Esta es la manera estándar de calcular distancias en el método de enlace promedio.
Otros métodos que podemos usar para calcular distancias basadas en puntos de datos agregados son:
- Máximo (o enlace completo): considera el punto de datos más lejano en el clúster relacionado con el punto que estamos tratando de agregar.
- Mínimo (o enlace simple): considera el punto de datos más cercano en el clúster relacionado con el punto que estamos tratando de agregar.
- Ward (o enlace de Ward): minimiza la varianza en los clústeres con la siguiente agregación.
Hagamos una pequeña pausa en la explicación paso a paso para profundizar un poco más en los métodos de enlace ya que son cruciales en este tipo de agrupamiento. Aquí hay un ejemplo visual de los diferentes métodos de enlace disponibles en el agrupamiento jerárquico, para un ejemplo ficticio de 3 clústeres a fusionar:

En la implementación de sklearn, podremos experimentar con algunos de estos métodos de enlace y ver una diferencia significativa en los resultados de agrupamiento.
Volviendo a nuestro ejemplo, ahora generemos las distancias entre todos nuestros nuevos puntos de datos — recuerda que hay dos clústeres que se están tratando como uno solo a partir de ahora:

- Distancia entre [60, 30] y [60, 55]: 25.0
- Distancia entre [60, 30] y [34, 65]: 43.60
- Distancia entre [60, 30] y [41, 100]: 72.53
- Distancia entre [60, 55] y [34, 65]: 27.85
- Distancia entre [60, 55] y [41, 100]: 48.85
- Distancia entre [34, 65] y [41, 100]: 35.69
¿Cuál es la distancia más corta? Es la distancia entre los puntos de datos en las coordenadas [60, 30] y [60, 55]:

El siguiente paso es, naturalmente, unir estos dos clientes en un solo grupo:

¡Con este nuevo paisaje de grupos, calculamos nuevamente las distancias en parejas! Recuerda que siempre estamos considerando el promedio entre los puntos de datos (debido al método de enlace que elegimos) en cada grupo como punto de referencia para el cálculo de la distancia:
- Distancia entre [60, 42.5] y [34, 65]: 34.38
- Distancia entre [60, 42.5] y [41, 100]: 60.56
- Distancia entre [34, 65] y [41, 100]: 35.69
Curiosamente, los siguientes puntos de datos a agregar son los dos grupos ya que se encuentran en las coordenadas [60, 42.5] y [34, 65]:

Finalmente, terminamos el algoritmo agregando todos los puntos de datos en un solo grupo grande:

Con esto en mente, ¿dónde exactamente nos detenemos? Probablemente no sea una gran idea tener un solo grupo grande con todos los puntos de datos, ¿verdad?
Para saber dónde detenernos, hay algunas reglas heurísticas que podemos usar. Pero primero, necesitamos familiarizarnos con otra forma de visualizar el proceso que acabamos de hacer: el dendrograma:

En el eje y, tenemos las distancias que acabamos de calcular. En el eje x, tenemos cada punto de datos. Al subir desde cada punto de datos, llegamos a una línea horizontal: el valor del eje y de esta línea indica la distancia total que conectará los puntos de datos en los bordes.
¿Recuerdas a los primeros clientes que conectamos en un solo grupo? Lo que hemos visto en la trama 2D coincide con el dendrograma, ya que esos son exactamente los primeros clientes conectados usando una línea horizontal (subiendo el dendrograma desde abajo):

¡Las líneas horizontales representan el proceso de fusión que acabamos de hacer! Naturalmente, el dendrograma termina en una línea horizontal grande que conecta todos los puntos de datos.
Como acabamos de familiarizarnos con el dendrograma, ahora estamos listos para verificar la implementación de sklearn y usar un conjunto de datos reales para comprender cómo podemos seleccionar el número apropiado de grupos basándonos en este genial método de agrupamiento.
Implementación de Sklearn
Para la implementación de Sklearn, voy a utilizar el conjunto de datos de calidad de vinos disponible aquí.
wine_data = pd.read_csv('winequality-red.csv', sep=';')wine_data.head(10)

Este conjunto de datos contiene información sobre vinos (particularmente vinos tintos) con diferentes características como ácido cítrico, cloruros o densidad. La última columna del conjunto de datos se refiere a la calidad del vino, una clasificación realizada por un panel de jurados.
Dado que el agrupamiento jerárquico se ocupa de las distancias y vamos a utilizar la distancia euclidiana, necesitamos estandarizar nuestros datos. Comenzaremos usando un StandardScaler
encima de nuestros datos:
from sklearn.preprocessing import StandardScalersc = StandardScaler()wine_data_scaled = sc.fit_transform(wine_data)
¡Con nuestro conjunto de datos escalado, podemos ajustar nuestra primera solución de agrupamiento jerárquico! Podemos acceder al agrupamiento jerárquico creando un objeto AgglomerativeClustering
:
average_method = AgglomerativeClustering(n_clusters = None, distance_threshold = 0, linkage = 'average')average_method.fit(wine_data_scaled)
Déjame detallar los argumentos que estamos usando dentro de AgglomerativeClustering:
n_clusters=None
se utiliza como una forma de tener la solución completa de los clusters (y donde podemos producir el dendrograma completo).distance_threshold = 0
debe establecerse en la implementación desklearn
para que se produzca el dendrograma completo.linkage = 'average'
es un hiperparámetro muy importante. Recuerda que, en la implementación teórica, hemos descrito un método para considerar las distancias entre los clusters recién formados.average
es el método que considera el punto promedio entre cada nuevo cluster formado en el cálculo de nuevas distancias. En la implementación desklearn
, tenemos otros tres métodos que también hemos descrito:single
,complete
yward
.
Después de ajustar el modelo, es hora de graficar nuestro dendrograma. Para esto, voy a utilizar la función auxiliar proporcionada en la documentación de sklearn
:
from scipy.cluster.hierarchy import dendrogramdef plot_dendrogram(model, **kwargs): # Crear la matriz de enlace y luego graficar el dendrograma # crear los recuentos de muestras debajo de cada nodo counts = np.zeros(model.children_.shape[0]) n_samples = len(model.labels_) for i, merge in enumerate(model.children_): current_count = 0 for child_idx in merge: if child_idx < n_samples: current_count += 1 # nodo hoja else: current_count += counts[child_idx - n_samples] counts[i] = current_count linkage_matrix = np.column_stack( [model.children_, model.distances_, counts] ).astype(float) # Graficar el dendrograma correspondiente dendrogram(linkage_matrix, **kwargs)
Si graficamos nuestra solución de agrupamiento jerárquico:
plot_dendrogram(average_method, truncate_mode="level", p=20)plt.title('Dendrograma de Agrupamiento Jerárquico - Método Promedio')

El dendrograma no es genial ya que nuestras observaciones parecen estar un poco atascadas. A veces, los enlaces average
, single
y complete
pueden dar lugar a dendrogramas extraños, especialmente cuando hay valores atípicos fuertes en los datos. El método ward
puede ser apropiado para este tipo de datos, así que probemos ese método:
ward_method = AgglomerativeClustering(n_clusters = None, distance_threshold = 0, linkage = 'ward')ward_method.fit(wine_data_scaled)plot_dendrogram(ward_method, truncate_mode="level", p=20)

¡Mucho mejor! Observa que los clusters parecen estar mejor definidos según el dendrograma. El método ward intenta dividir los clusters minimizando la intra-varianza entre los clusters recién formados (https://online.stat.psu.edu/stat505/lesson/14/14.7), como se describe en la primera parte del post. El objetivo es que para cada iteración, los clusters agregados minimicen la varianza (distancia entre los puntos de datos y el nuevo cluster a formar).
¡De nuevo, cambiar los métodos se puede lograr cambiando el parámetro linkage
en la función AgglomerativeClustering
!
Como estamos contentos con la apariencia del dendrograma del método ward
, usaremos esa solución para nuestro perfil de cluster:

¿Puedes adivinar cuántos clusters debemos elegir?
Según las distancias, un buen candidato es cortar el dendrograma en este punto, donde cada cluster parece estar relativamente lejos del otro:

El número de líneas verticales que cruza nuestra línea son el número de clusters finales de nuestra solución. Elegir el número de clusters no es muy “científico” y se pueden lograr diferentes números de soluciones de clustering, dependiendo de la interpretación del negocio. Por ejemplo, en nuestro caso, cortar nuestro dendrograma un poco por encima y reducir el número de clusters de la solución final también puede ser una hipótesis.
Nos quedaremos con la solución de 7 clusters, así que ajustemos nuestro método ward
con esos n_clusters
en mente:
ward_method_solution = AgglomerativeClustering(n_clusters = 7, linkage = 'ward')wine_data['cluster'] = ward_method_solution.fit_predict(wine_data_scaled)
Como queremos interpretar nuestros clusters basados en las variables originales, usaremos el método predict en los datos escalados (las distancias se basan en el conjunto de datos escalados) pero agregaremos el cluster al conjunto de datos original.
Comparemos nuestros clusters usando las medias de cada variable condicionada a la variable cluster
:
wine_data.groupby([‘cluster’]).mean()

Curiosamente, podemos empezar a tener algunas ideas sobre los datos, por ejemplo:
- Los vinos de baja calidad parecen tener un gran valor de
dióxido de azufre total
– observe la diferencia entre el cluster de calidad más alta y el cluster de calidad más baja:

Y si comparamos la calidad
de los vinos en estos clusters:

Claramente, en promedio, el Cluster 2 contiene vinos de mayor calidad.
Otro análisis interesante que podemos realizar es una matriz de correlación entre los datos agrupados:

Esto nos da algunas buenas pistas de posibles cosas que podemos explorar (incluso para el aprendizaje supervisado). Por ejemplo, a nivel multidimensional, los vinos con mayores niveles de azufre
y cloruros
pueden agruparse juntos. Otra conclusión es que los vinos con mayor contenido de alcohol tienden a estar asociados con vinos de mayor calidad.
Conclusión
¡Eso es todo! Gracias por tomarte el tiempo de leer esta entrada de blog sobre aprendizaje no supervisado. Seguiré agregando más algoritmos de aprendizaje no supervisado a esta serie para mostrar diferentes tipos de métodos que podemos usar para conocer la estructura de nuestros datos.
Naturalmente, el clustering jerárquico tiene sus pros y contras que podemos discutir:
- Una gran desventaja del algoritmo es que puede requerir demasiadas heurísticas para llegar a una solución final. Se pueden aplicar una combinación de análisis de dendrogramas, análisis basados en distancia o métodos de coeficientes de silueta para llegar a un número de clusters que tenga sentido. Además, no se debe descartar cruzar estos enfoques técnicos con algún conocimiento empresarial sobre los datos para evitar caer en algún tipo de trampa de clustering.
- En el lado positivo, el enfoque de clustering jerárquico es muy explicativo, lo que ayuda a descubrir estructuras ocultas en los datos.
- Además, el clustering jerárquico no sufre del problema de inicialización del centroide, algo que puede ser una ventaja para algunos conjuntos de datos.
El clustering jerárquico es un método de clustering muy famoso que se ha aplicado para múltiples aplicaciones tan diversas como:
- Segmentación de clientes;
- Análisis de valores atípicos;
- Análisis de datos de expresión génica multidimensionales;
- Clustering de documentos;
Es un método muy interesante que los científicos de datos deberían tener en su caja de herramientas. Siéntete libre de probarlo en tu próximo proyecto y mantente atento a más publicaciones sobre esta Serie de Aprendizaje No Supervisado.
Si deseas asistir a mis cursos de Python, siéntete libre de unirte a mi curso gratuito aquí ( Introducción a Python en 2 horas para personas ocupadas ) o a una versión más larga de 16 horas ( Curso completo de Python para principiantes ). Mis cursos de Python son adecuados para desarrolladores principiantes / intermedios y me encantaría tenerte en mi clase.
Los datos utilizados en esta publicación están bajo una licencia Creative Commons Attribution 4.0 International (CC BY 4.0) como se muestra en el siguiente enlace: https://archive.ics.uci.edu/dataset/186/wine+quality