Capítulo 4
Agrupación de K-medias

La metodología de agrupación mediante K-medias, formulada por MacQueen en 1967, sobresale como el principal algoritmo de aprendizaje no supervisado empleado para dividir un conjunto específico de datos en k grupos (o clústeres), donde k es establecido de antemano por el analista. Su función primordial consiste en la categorización de elementos en diversos grupos, con el objetivo de maximizar la semejanza intraclase (alta concordancia entre elementos dentro del mismo grupo) y minimizar la semejanza interclase (baja concordancia entre elementos de grupos diferentes). Durante este procedimiento, cada grupo se caracteriza a través de su centroide, que representa la media de los puntos asignados a ese grupo.

4.1 Principios fundamentales de K-means

La esencia subyacente en la agrupación de k-medias radica en la formación de grupos de manera que se minimice la variabilidad total dentro de cada grupo, conocida como variabilidad total intra-grupo. Existen diversos algoritmos de k-medias disponibles, siendo el algoritmo convencional el de Hartigan-Wong (1979). Este algoritmo define la variabilidad total intra-grupo como la suma de las distancias al cuadrado de las distancias euclidianas entre los elementos y el respectivo centroide.

4.2 Algoritmos K-means

El algoritmo K-medias se puede resumir de la siguiente manera:

  1. Especifique el número de clusters (K) que se crearán (por el analista)

  2. Seleccione aleatoriamente k objetos del conjunto de datos como centros o medios del grupo inicial.

  3. Asigna cada observación a su centroide más cercano, según la distancia euclidiana entre el objeto y el centroide.

  4. Para cada uno de los k grupos, actualice el centroide del grupo calculando los nuevos valores medios de todos los puntos de datos del grupo. El centoide de un grupo K-ésimo es un vector de longitud p que contiene las medias de todas las variables para las observaciones en el grupo K-ésimo; p es el número de variables.

  5. Minimizar iterativamente el total dentro de la suma del cuadrado. Es decir, repita los pasos 3 y 4 hasta que las asignaciones del clúster dejen de cambiar o se alcance el número máximo de iteraciones. De forma predeterminada, el software R utiliza 10 como valor predeterminado para el número máximo de iteraciones.

4.3 Calculo de la agrupación de k-medias en R
4.3.1 Datos

Para llevar a cabo la agrupación de k-medias en R, se empleará el conjunto de datos de muestra “USArrests”. Es esencial preparar los datos según las indicaciones del capítulo 2, asegurándose de que solo incluyan variables continuas, ya que el algoritmo k-medias se basa en promedios variables.

Con el objetivo de evitar que el algoritmo dependa de una escala arbitraria, se procede a escalar los datos mediante la función scale() en R. El proceso se lleva a cabo de la siguiente manera:

data("USArrests")
df <- scale(USArrests)    
#Visualiza las primeras 3 filas de los datos
head(df,n=3)
##             Murder   Assault   UrbanPop         Rape
## Alabama 1.24256408 0.7828393 -0.5209066 -0.003416473
## Alaska  0.50786248 1.1068225 -1.2117642  2.484202941
## Arizona 0.07163341 1.4788032  0.9989801  1.042878388
4.3.2 Paquetes de R requeridos y funciones

La función estándar de R para la agrupación de k-medias es kmeans() [paquete de estadísticas], cuyo formato simplificado es el siguiente:

• x: matriz numérica, marco de datos numérico o un vector numérico.

• centers: los valores posibles son el número de conglomerados (k) o un conjunto de centros de conglomerados iniciales (distintos). Si es un número, se elige como centros iniciales un conjunto aleatorio de filas (distintas) en x.

• iter.max: el número máximo de iteraciones permitidas. El valor predeterminado es 10.

• nstart: el número de particiones iniciales aleatorias cuando los centros son un número.

A menudo se recomienda probar nstart > 1.Para crear un hermoso gráfico de los clusters generados con la función kmeans(), usaremos el paquete factoextra.

#Cargando factroextra
library(factoextra)
## Warning: package 'factoextra' was built under R version 4.3.2
## Loading required package: ggplot2
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
4.3.3 Estimación del número óptimo de conglomerados

La agrupación en clústeres k-means requiere que los usuarios especifiquen la cantidad de clústeres que se generarán. Una pregunta fundamental es: ¿Cómo elegir el número correcto de conglomerados esperados (k)?

En el capítulo sobre estadísticas de evaluación y validación de conglomerados, se abordarán diversos métodos. Se propone una solución simple que implica calcular la agrupación de k-medias con distintos valores de grupos k. Luego, se representa la suma de los cuadrados dentro del grupo (wss) en función del número de conglomerados. La posición de una curva (punto de inflexión) en el gráfico generalmente se considera un indicador del número adecuado de conglomerados.

Una alternativa práctica para estimar el número óptimo de clústeres es la función R fviz_nbclust() del paquete factoextra.

fviz_nbclust(df, kmeans, method = "wss") +
geom_vline(xintercept = 4, linetype = 2)

El gráfico de arriba representa la varianza dentro de los grupos. Disminuye a medida que kaumenta, pero se puede ver una curvatura (o “codo”) en k = 4. Esta curvatura indica que los grupos adicionales más allá del cuarto tienen poco valor. En la siguiente sección, clasificaremos las observaciones en 4 racimos.

4.3.4 Cálculo del agrupamiento de k-medias

Como el algoritmo de agrupamiento de k-medias comienza con k centroides seleccionados aleatoriamente, siempre se recomienda usar la función set.seed() para establecer una semilla para el algoritmo aleatorio de R.

generador de números. El objetivo es hacer reproducibles los resultados, de modo que el lector de este artículo obtenga exactamente los mismos resultados que los que se muestran a continuación.

El siguiente código R realiza agrupación de k-medias con k = 4:

set.seed(123)
km.res<- kmeans(df,4,nstart=25)

Dado que el resultado final de la agrupación de k-medias puede ser influenciado por las asignaciones iniciales aleatorias, hemos especificado nstart como 25. Esto indica que R realizará 25 asignaciones iniciales aleatorias diferentes y seleccionará los resultados más óptimos, los cuales tienen la variación más baja dentro del grupo. El valor predeterminado de nstart en R es uno, pero se recomienda encarecidamente aumentar este valor, por ejemplo, a 25 o 50, al realizar la agrupación de k-medias para obtener resultados más estables y confiables.

print(km.res)
## K-means clustering with 4 clusters of sizes 8, 13, 16, 13
## 
## Cluster means:
##       Murder    Assault   UrbanPop        Rape
## 1  1.4118898  0.8743346 -0.8145211  0.01927104
## 2 -0.9615407 -1.1066010 -0.9301069 -0.96676331
## 3 -0.4894375 -0.3826001  0.5758298 -0.26165379
## 4  0.6950701  1.0394414  0.7226370  1.27693964
## 
## Clustering vector:
##        Alabama         Alaska        Arizona       Arkansas     California 
##              1              4              4              1              4 
##       Colorado    Connecticut       Delaware        Florida        Georgia 
##              4              3              3              4              1 
##         Hawaii          Idaho       Illinois        Indiana           Iowa 
##              3              2              4              3              2 
##         Kansas       Kentucky      Louisiana          Maine       Maryland 
##              3              2              1              2              4 
##  Massachusetts       Michigan      Minnesota    Mississippi       Missouri 
##              3              4              2              1              4 
##        Montana       Nebraska         Nevada  New Hampshire     New Jersey 
##              2              2              4              2              3 
##     New Mexico       New York North Carolina   North Dakota           Ohio 
##              4              4              1              2              3 
##       Oklahoma         Oregon   Pennsylvania   Rhode Island South Carolina 
##              3              3              3              3              1 
##   South Dakota      Tennessee          Texas           Utah        Vermont 
##              2              1              4              3              2 
##       Virginia     Washington  West Virginia      Wisconsin        Wyoming 
##              3              3              2              2              3 
## 
## Within cluster sum of squares by cluster:
## [1]  8.316061 11.952463 16.212213 19.922437
##  (between_SS / total_SS =  71.2 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

La salida impresa muestra:

El grupo means o centers: una matriz, cuyas filas son el número del grupo (1 a 4) y las columnas son variables.

El vector de agrupamiento: un vector de números enteros (de 1:k) que indica el grupo al que se asigna cada punto.

Es posible calcular la media de cada variable por conglomerados utilizando los datos originales:

aggregate(USArrests, by=list(cluster=km.res$cluster),mean)
##   cluster   Murder   Assault UrbanPop     Rape
## 1       1 13.93750 243.62500 53.75000 21.41250
## 2       2  3.60000  78.53846 52.07692 12.17692
## 3       3  5.65625 138.87500 73.87500 18.78125
## 4       4 10.81538 257.38462 76.00000 33.19231

Si desea agregar las clasificaciones de puntos a los datos originales, utilice este:

dd<- cbind(USArrests, cluster=km.res$cluster)
head(dd)
##            Murder Assault UrbanPop Rape cluster
## Alabama      13.2     236       58 21.2       1
## Alaska       10.0     263       48 44.5       4
## Arizona       8.1     294       80 31.0       4
## Arkansas      8.8     190       50 19.5       1
## California    9.0     276       91 40.6       4
## Colorado      7.9     204       78 38.7       4
4.3.5 Accediendo a los resultados de la función kmeans()

La función kmeans() devuelve una lista de componentes, que incluye:

cluster: Un vector de números enteros (de 1:k) que indica el cluster al que se asigna cada punto

Centers: una matriz de centros de conglomerados (medios de conglomerados)

totss: La suma total de cuadrados (TSS), es decir (x,-)². TSS mide la varianza total de los datos. • insidess: Vector de suma de cuadrados dentro del grupo, un componente por grupo

tot.withinss: suma total de cuadrados dentro del grupo, es decir, sum(withinss)

Betweenss: suma de cuadrados entre grupos, es decir, totss-tot.withinss

size: el número de observaciones en cada grupo

Se puede acceder a estos componentes de la siguiente manera:

#Numero de cluster para cada observación
km.res$cluster
##        Alabama         Alaska        Arizona       Arkansas     California 
##              1              4              4              1              4 
##       Colorado    Connecticut       Delaware        Florida        Georgia 
##              4              3              3              4              1 
##         Hawaii          Idaho       Illinois        Indiana           Iowa 
##              3              2              4              3              2 
##         Kansas       Kentucky      Louisiana          Maine       Maryland 
##              3              2              1              2              4 
##  Massachusetts       Michigan      Minnesota    Mississippi       Missouri 
##              3              4              2              1              4 
##        Montana       Nebraska         Nevada  New Hampshire     New Jersey 
##              2              2              4              2              3 
##     New Mexico       New York North Carolina   North Dakota           Ohio 
##              4              4              1              2              3 
##       Oklahoma         Oregon   Pennsylvania   Rhode Island South Carolina 
##              3              3              3              3              1 
##   South Dakota      Tennessee          Texas           Utah        Vermont 
##              2              1              4              3              2 
##       Virginia     Washington  West Virginia      Wisconsin        Wyoming 
##              3              3              2              2              3
head(km.res$cluster, 4)
##  Alabama   Alaska  Arizona Arkansas 
##        1        4        4        1
#Tamaño de cluster
km.res$size
## [1]  8 13 16 13
#cluster means
km.res$centers
##       Murder    Assault   UrbanPop        Rape
## 1  1.4118898  0.8743346 -0.8145211  0.01927104
## 2 -0.9615407 -1.1066010 -0.9301069 -0.96676331
## 3 -0.4894375 -0.3826001  0.5758298 -0.26165379
## 4  0.6950701  1.0394414  0.7226370  1.27693964
4.3.6 Visualización de grupos de k-medias

Visualizar los resultados de la agrupación de k-medias es esencial para evaluar el número óptimo de conglomerados y comparar análisis de agrupación. La representación gráfica se realiza mediante un diagrama de dispersión, coloreando cada punto según su asignación de grupo.

Cuando los datos tienen más de dos variables, surge la pregunta sobre qué variables elegir para el diagrama de dispersión xy. Una solución eficaz implica reducir la dimensionalidad mediante técnicas como el Análisis de Componentes Principales (PCA), generando dos nuevas variables representativas.

En resumen, al trabajar con conjuntos de datos multidimensionales, se puede realizar PCA y representar los puntos de datos en función de los dos primeros componentes principales. La función fviz_cluster() del paquete factoextra facilita esta visualización, tomando los resultados de k-medias y los datos originales como argumentos. En el gráfico resultante, las observaciones se representan mediante puntos, utilizando componentes principales si el número de variables es mayor que 2. Además, se ofrece la opción de trazar elipses de concentración alrededor de cada grupo, proporcionando una representación visual clara de la estructura de los conglomerados.

fviz_cluster(km.res, data = df,
palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
ellipse.type = "euclid", # Concentration ellipse
star.plot = TRUE, # Add segments from centroids to items
repel = TRUE, # Avoid label overplotting (slow)
ggtheme = theme_minimal()
)

4.4 Ventajas y desventajas de la agrupación K-means

Entre las ventajas de la agrupación, K-medias destaca por su simplicidad y velocidad, siendo un algoritmo eficiente incluso para conjuntos de datos extensos. Su capacidad para manejar grandes volúmenes de datos contribuye a su escalabilidad, convirtiéndolo en una opción viable para aplicaciones prácticas.

Por otra parte, la principal desventaja es la necesidad de que el analista determine previamente el número de clústeres (k), una elección que puede resultar desafiante sin un conocimiento profundo de los datos. La sensibilidad a la inicialización aleatoria de los centros de clúster también plantea problemas, ya que diferentes ejecuciones pueden producir soluciones diversas. Además, la influencia de valores atípicos y la dependencia del orden de los datos son aspectos que deben abordarse.

Para superar la dificultad en la elección de k, se sugiere calcular K-medias para diversos valores de k y seleccionar el óptimo mediante la comparación de resultados de agrupación. La inicialización múltiple del algoritmo con diferentes centros de clúster ayuda a mitigar la variabilidad en los resultados. En cuanto a la sensibilidad a valores atípicos, se propone el uso del algoritmo PAM, menos propenso a distorsiones causadas por datos atípicos. Estas estrategias abordan las limitaciones inherentes de K-medias y mejoran su robustez y aplicabilidad en diversas situaciones.

4.5 Alternativa a la agrupación de k-means

Una opción robusta como alternativa a la agrupación de k-medias es PAM, que se fundamenta en la noción de medoides. Como se explorará en el próximo capítulo, la realización de la agrupación de clústeres mediante PAM se logra mediante el uso de la función pam() del paquete de clústeres. Adicionalmente, la función pamk() del paquete fpc ofrece una herramienta integral para PAM, incluyendo la impresión del número sugerido de grupos basado en el ancho promedio óptimo de la silueta.

4.6 Resumen

La agrupación de k-medias es una técnica que clasifica observaciones en k grupos según su similitud, siendo cada grupo representado por el valor medio de sus puntos, conocido como centroide. La implementación del algoritmo K-means en R, a través de la función kmeans() del paquete de estadísticas, requiere que los usuarios especifiquen la cantidad deseada de clústeres.

Después de calcular la agrupación, la visualización de los resultados se facilita mediante la función fviz_cluster() del paquete factoextra en R. Este proceso ofrece una manera efectiva de explorar y comprender la estructura de los clústeres generados, permitiendo la interpretación visual de los resultados del análisis de agrupación de k-medias.

Capítulo 5
K-medoids

LEl algoritmo k-medoids, relacionado con la agrupación k-medias (véase capítulo 4), divide un conjunto de datos en k grupos o clusters. En este enfoque, cada grupo está representado por un punto de datos específico, denominado medoide del cúmulo. El término “medoide” se refiere a un objeto dentro del grupo cuya disimilitud promedio con los demás miembros del grupo es mínima, siendo este el punto más céntrico del cluster. A diferencia de la agrupación k-medias, donde el centro del grupo es el valor medio de todos los puntos, los medoides son objetos representativos de cada grupo.

K-medoides, una sólida alternativa a k-medias, se destaca por su menor sensibilidad al ruido y a los valores atípicos, ya que utiliza medoides en lugar de medias como centros de grupo. Para implementar este algoritmo, es necesario especificar k, el número de clusters a generar, de manera similar al clustering k-medias. Un método efectivo para determinar el número óptimo de conglomerados es el método de silueta, explicado en las secciones siguientes. El algoritmo PAM (Partitioning Around Medoids, Kaufman & Rousseeuw, 1990) es la implementación más común del enfoque de agrupación de k-medoides.

5.1 Concepto PAM

El empleo de medias en la agrupación de k-medias conlleva una alta sensibilidad a los valores atípicos, lo que podría tener un impacto significativo en la asignación de observaciones a los conglomerados. Con el objetivo de abordar esta vulnerabilidad, el algoritmo PAM se presenta como una alternativa más robusta y resistente.

5.2 Algoritmo PAM

El algoritmo PAM busca k medoides representativos en el conjunto de datos y asigna cada observación al medoide más cercano. A través de un proceso de intercambio, llamado SWAP, se intenta mejorar la calidad de la agrupación intercambiando medoides y objetos no seleccionados. El objetivo es encontrar k objetos representativos que minimicen la suma de las diferencias entre las observaciones y sus medoides más cercanos. En resumen, el algoritmo PAM se desarrolla en dos fases: identificación de medoides y fase de intercambio.

En el algoritmo PAM, se inicia seleccionando k objetos como medoides o, si se proporcionan, se utilizan como tales. Posteriormente, se calcula la matriz de disimilitud si no se ha proporcionado previamente. A continuación, cada objeto se asigna a su medoide más cercano. Para cada grupo, se verifica si algún objeto del grupo reduce el coeficiente de disimilitud promedio; en caso afirmativo, se elige la entidad que maximiza esta disminución como medoide para el grupo. Este proceso se repite hasta que al menos un medoide cambia, momento en el cual se vuelve a asignar cada objeto a su medoide más cercano. El algoritmo concluye cuando no hay cambios en los medoides.

5.2 Computando PAM en R
5.3.1 Datos

Usaremos los conjuntos de datos de demostración “USArrests”, que comenzamos escalando (Capítulo 2) usando la función R scale() de la siguiente manera:

# Calculando PAM 
data("USArrests") # Carga del data set
df <- scale(USArrests) 
head(df, n = 3) # Ver primeras 3 filas
##             Murder   Assault   UrbanPop         Rape
## Alabama 1.24256408 0.7828393 -0.5209066 -0.003416473
## Alaska  0.50786248 1.1068225 -1.2117642  2.484202941
## Arizona 0.07163341 1.4788032  0.9989801  1.042878388
5.3.2 Paquetes y funciones requeridas
library(cluster)
library(factoextra)
5.3.3 Estimación del número óptimo de conglomerados

Para determinar el número óptimo de grupos, empleamos el método de silueta promedio en la estimación del algoritmo PAM. Este método implica calcular el PAM con distintos valores de grupos, seguido por la representación gráfica de la silueta promedio en función del número de conglomerados. La silueta media es un indicador de la calidad del agrupamiento, donde un ancho de silueta promedio elevado denota una agrupación efectiva. La identificación del número óptimo de conglomerados, k, se basa en maximizar la silueta promedio dentro de un rango de valores posibles para k, siguiendo la propuesta de Kaufman y Rousseeuw (1990). La función R fviz_nbclust() del paquete factoextra brinda una solución práctica para esta estimación.

Según el siguiente gráfico, el número sugerido de grupos es 2. En la siguiente sección clasificaremos las observaciones en 2 grupos.

fviz_nbclust(df,pam, method="silhouette")+
  theme_classic()

5.3.4 Cálculo de la agrupación PAM

El siguiente código R calcula el algoritmo PAM con k=2.

pam.res <- pam(df,2)
print(pam.res)
## Medoids:
##            ID     Murder    Assault   UrbanPop       Rape
## New Mexico 31  0.8292944  1.3708088  0.3081225  1.1603196
## Nebraska   27 -0.8008247 -0.8250772 -0.2445636 -0.5052109
## Clustering vector:
##        Alabama         Alaska        Arizona       Arkansas     California 
##              1              1              1              2              1 
##       Colorado    Connecticut       Delaware        Florida        Georgia 
##              1              2              2              1              1 
##         Hawaii          Idaho       Illinois        Indiana           Iowa 
##              2              2              1              2              2 
##         Kansas       Kentucky      Louisiana          Maine       Maryland 
##              2              2              1              2              1 
##  Massachusetts       Michigan      Minnesota    Mississippi       Missouri 
##              2              1              2              1              1 
##        Montana       Nebraska         Nevada  New Hampshire     New Jersey 
##              2              2              1              2              2 
##     New Mexico       New York North Carolina   North Dakota           Ohio 
##              1              1              1              2              2 
##       Oklahoma         Oregon   Pennsylvania   Rhode Island South Carolina 
##              2              2              2              2              1 
##   South Dakota      Tennessee          Texas           Utah        Vermont 
##              2              1              1              2              2 
##       Virginia     Washington  West Virginia      Wisconsin        Wyoming 
##              2              2              2              2              2 
## Objective function:
##    build     swap 
## 1.441358 1.368969 
## 
## Available components:
##  [1] "medoids"    "id.med"     "clustering" "objective"  "isolation" 
##  [6] "clusinfo"   "silinfo"    "diss"       "call"       "data"

La salida impresa del algoritmo PAM incluye dos elementos clave: la matriz del grupo de medoides, donde cada fila representa un medoide y las columnas son variables, y el vector de agrupamiento, un conjunto de números enteros (de 1 a k) que señala a qué grupo se asigna cada punto. Si se desea incorporar estas clasificaciones directamente a los datos originales, puede utilizar la siguiente instrucción:

dd<-cbind(USArrests, cluster=pam.res$cluster)
head(dd, n=3)
##         Murder Assault UrbanPop Rape cluster
## Alabama   13.2     236       58 21.2       1
## Alaska    10.0     263       48 44.5       1
## Arizona    8.1     294       80 31.0       1
5.3.5 Accediendo a los resultados de la función pam()

La función pam() produce un objeto de clase “pam”, cuyos componentes fundamentales son la lista de medoides que representan los grupos y el vector de agrupamiento que asigna cada objeto a su respectivo grupo. Estos resultados brindan una visión detallada de la estructura de los grupos y la asignación de objetos en el conjunto de datos analizado.

pam.res$medoids #Cluster medoids
##                Murder    Assault   UrbanPop       Rape
## New Mexico  0.8292944  1.3708088  0.3081225  1.1603196
## Nebraska   -0.8008247 -0.8250772 -0.2445636 -0.5052109
head(pam.res$clustering) #Números cluster
##    Alabama     Alaska    Arizona   Arkansas California   Colorado 
##          1          1          1          2          1          1
5.3.6 Visualización de clústeres PAM

Para representar gráficamente los resultados de la partición en clústeres PAM, emplearemos la función fviz_cluster() del paquete factoextra. Esta función genera un diagrama de dispersión que coloreará los puntos de datos según los números de grupo asignados. En situaciones donde los datos abarcan más de dos variables, se implementa el algoritmo de Análisis de Componentes Principales (PCA) para reducir la dimensionalidad de los datos. En este contexto, las dos primeras dimensiones principales se utilizan para visualizar los datos de manera efectiva.

fviz_cluster(pam.res,
palette = c("#00AFBB", "#FC4E07"), # color palette
ellipse.type = "t", # Concentration ellipse
repel = TRUE, # Avoid label overplotting (slow)
ggtheme = theme_classic()
)

5.2 Resumen

El algoritmo K-medoids, conocido como PAM, presenta una sólida alternativa a k-means para la segmentación de conjuntos de datos en grupos de observaciones. En este enfoque, cada grupo se representa mediante un objeto seleccionado internamente denominado medoide, que corresponde al punto más central del grupo. La implementación de PAM requiere que el usuario especifique el número adecuado de clústeres, estimándolo con la función fviz_nbclust del paquete factoextra en R. La función pam() del paquete de clústeres se emplea para calcular PAM, utilizando el formato pam(x, k), donde “x” representa los datos y “k” indica el número de clústeres a generar. Tras realizar la agrupación PAM, la visualización de los resultados se facilita mediante la función fviz_cluster del paquete factoextra, utilizando el formato fviz_cluster(pam.res), donde pam.res representa los resultados de PAM.

Capítulo 6
cLARA - Clustering Large Applications

CLARA (Clustering Large Applications, Kaufman y Rousseeuw, 1990) constituye una extensión de los métodos k-medoids, como se detalla en el Capítulo 5, diseñada para abordar conjuntos de datos que implican una cantidad considerable de objetos, superando varias miles de observaciones. El objetivo principal es mitigar la carga computacional y los desafíos de almacenamiento de la RAM. Para lograrlo, CLARA implementa un enfoque de muestreo.

6.1 Concepto CLARA

En lugar de buscar medoides para todo el conjunto de datos, CLARA adopta un enfoque de muestreo, considerando una pequeña muestra de datos con tamaño fijo. Aplica el algoritmo PAM del Capítulo 5 para obtener un conjunto óptimo de medoides para la muestra, evaluando la calidad de estos medoides mediante la disimilitud promedio con cada objeto en el conjunto de datos completo, definido como la función de costo. CLARA repite los procesos de muestreo y agrupamiento varias veces para reducir el sesgo de muestreo, y los resultados finales corresponden al conjunto de medoides que minimiza el costo.

6.2 Algoritmo CLARA

El algoritmo se inicia dividiendo de manera aleatoria los conjuntos de datos en múltiples subconjuntos, cada uno con un tamaño fijo o tamaño de muestra. Luego, se aplica el algoritmo PAM en cada subconjunto para seleccionar los k objetos representativos, es decir, los medoides. Cada observación en el conjunto de datos completo se asigna al medoide más cercano. Posteriormente, se calcula la media (o suma) de las disimilitudes entre las observaciones y sus respectivos medoides, sirviendo como medida de la calidad de la agrupación. Se conserva el conjunto de subdatos cuya media (o suma) es mínima, y se realiza un análisis más detallado de la partición final.

6.3 Computando CLARA en R

Para calcular el algoritmo CLARA en R, los datos deben prepararse como se indica en el Capítulo 2. Aquí, generaremos un conjunto de datos aleatorios. Para que el resultado sea reproducible, comenzamos usando la función set.seed().

set.seed(1234)
#Generación de 500 objetos, dividos en dos clusters
df <- rbind(cbind(rnorm(200,0,8), rnorm(200,0,8)),
cbind(rnorm(300,50,8), rnorm(300,50,8)))

#Especificar los nombres de columnas y filas
colnames(df)<- c("x", "y")

rownames(df) <- paste0("S",1:nrow(df))

#Previsualización de datos
head(df, nrow=6)
##             x        y
## S1  -9.656526 3.881815
## S2   2.219434 5.574150
## S3   8.675529 1.484111
## S4 -18.765582 5.605868
## S5   3.432998 2.493448
## S6   4.048447 6.083699
6.3.2 Paquetes de R y funciones requeridas

La función clara() [paquete de clúster] se puede utilizar para calcular CLARA. El formato simplificado es el siguiente:

library(cluster)
library(factoextra)
6.3.3 Estimación del número óptimo de conglomerados

Para estimar el número óptimo de clusters en sus datos, es posible utilizar el método de silueta promedio como se describe en el capítulo de clustering de PAM (Capítulo 5). La función R fuiz_nbclust() [paquete factoextra] proporciona una solución para facilitar este paso.

fviz_nbclust(df, clara, method="silhouette")+
  theme_classic()

Según el gráfico, el número sugerido de grupos es 2. En la siguiente sección, clasificaremos las observaciones en 2 grupos.

6.3.4 Computación CLARA

El siguiente código R calcula el algoritmo PAM con k=2.

#Computación CLARA
clara.res <- clara(df, 2, samples=50, pamLike = TRUE)

#Componentes de clara.res
print(clara.res)
## Call:     clara(x = df, k = 2, samples = 50, pamLike = TRUE) 
## Medoids:
##              x         y
## S121 -1.531137  1.145057
## S455 48.357304 50.233499
## Objective function:   9.87862
## Clustering vector:    Named int [1:500] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ...
##  - attr(*, "names")= chr [1:500] "S1" "S2" "S3" "S4" "S5" "S6" "S7" ...
## Cluster sizes:            200 300 
## Best sample:
##  [1] S37  S49  S54  S63  S68  S71  S76  S80  S82  S101 S103 S108 S109 S118 S121
## [16] S128 S132 S138 S144 S162 S203 S210 S216 S231 S234 S249 S260 S261 S286 S299
## [31] S304 S305 S312 S315 S322 S350 S403 S450 S454 S455 S456 S465 S488 S497
## 
## Available components:
##  [1] "sample"     "medoids"    "i.med"      "clustering" "objective" 
##  [6] "clusinfo"   "diss"       "call"       "silinfo"    "data"

La salida de la función clara() presenta componentes clave, incluyendo los medoides que representan los clusters y el vector de clustering que asigna a cada objeto un número de cluster. Adicionalmente, se proporcionan las etiquetas o estuches que numeran las observaciones en la mejor muestra, es decir, la muestra utilizada por el algoritmo CLARA para la partición final. Si se desea incorporar estas clasificaciones directamente a los datos originales, se puede utilizar la instrucción proporcionada.

dd <- cbind(df, cluster=clara.res$cluster)
head(dd, n=4)
##             x        y cluster
## S1  -9.656526 3.881815       1
## S2   2.219434 5.574150       1
## S3   8.675529 1.484111       1
## S4 -18.765582 5.605868       1
#Medoids
clara.res$medoids
##              x         y
## S121 -1.531137  1.145057
## S455 48.357304 50.233499
#Clustering
head(clara.res$clustering, 10)
##  S1  S2  S3  S4  S5  S6  S7  S8  S9 S10 
##   1   1   1   1   1   1   1   1   1   1
6.3.5 Visualización de CLARA clusters

Para visualizar los resultados de la partición, usaremos la función fviz_cluster() [paquete factoextra]. Dibuja un diagrama de dispersión de puntos de datos coloreados por números de grupo.

fviz_cluster(clara.res,
palette = c("#00AFBB", "#FC4E07"), # color palette
ellipse.type = "t", # Concentration ellipse
geom = "point", pointsize = 1,
ggtheme = theme_classic()
)

6.4 Resumen

CLARA (Clustering Large Applications), una extensión del método de clustering PAM (Partitioning Around Medoids) diseñada para grandes conjuntos de datos, busca reducir el tiempo de cálculo en este contexto. Similar a otros algoritmos de partición, requiere que el usuario especifique la cantidad adecuada de clústeres, una estimación posible mediante la función fviz_nbclust del paquete factoextra en R. La función clara() del paquete de clústeres se emplea para calcular CLARA, con el formato clara(x, k, pamLike = TRUE), donde “x” representa los datos y “k” indica el número de clusters a generar. Después de realizar el cálculo con CLARA, los resultados se pueden visualizar utilizando la función fviz_cluster() del paquete factoextra, con el formato fviz_cluster(clara.res), donde clara.res representa los resultados obtenidos con CLARA.

Parte III: Agrupación jerárquica

Figura cap 6.1

La agrupación jerárquica, también conocida como análisis de conglomerados jerárquicos (HCA), ofrece un enfoque distinto para la clasificación de objetos basado en su similitud, en contraste con la agrupación con particiones. Una característica distintiva es que no requiere la especificación previa del número de clústeres a generar. Este método puede dividirse en dos categorías: el agrupamiento aglomerativo, que parte considerando cada observación como un clúster propio y fusiona sucesivamente los clústeres más similares hasta formar un solo clúster grande, y el agrupamiento divisivo, que comienza con un único grupo que incluye todas las observaciones y se divide sucesivamente en grupos más heterogéneos. El resultado final de la agrupación jerárquica se presenta como un árbol, también conocido como dendrograma.

Figura cap 6.2

El dendrograma, una estructura jerárquica multinivel, permite decidir en qué nivel cortar el árbol para formar grupos de objetos de datos. Este capítulo se centra en visualizar la disimilitud entre objetos utilizando dendrogramas. Se describen algoritmos de agrupamiento jerárquico con scripts R para calcular y visualizar resultados, incluyendo técnicas para segmentar dendrogramas en grupos, comparar dos dendrogramas y manejar grandes conjuntos de datos.

Capítulo 7
Agrupación aglomerativa

La agrupación aglomerativa, también conocida como AGNES (Anidación Aglomerativa), es el enfoque más común para agrupar objetos jerárquicamente según su similitud. Este algoritmo inicia considerando cada objeto como un grupo individual y fusiona progresivamente pares de grupos hasta formar un único grupo que incluye todos los objetos. El resultado es un dendrograma, una representación jerárquica de los objetos.

7.1 Algoritmo

La agrupación aglomerativa procede “ascendiendo”, considerando inicialmente cada objeto como un grupo individual (hoja). En cada paso, se fusionan los dos grupos más similares para formar un nuevo grupo más grande (nodo), y este proceso continúa hasta que todos los objetos pertenecen a un solo grupo grande (raíz). En contraste, la agrupación divisiva, también conocida como DIANA (Análisis Divisivo), funciona “de arriba hacia abajo”, comenzando con la raíz, donde todos los objetos están en un solo grupo, y divide sucesivamente grupos más heterogéneos en cada iteración.

Figura cap 6.2

7.2 Pasos para la agrupación jerárquica aglomerativa

En la agrupación jerárquica aglomerativa en R, se siguen los siguientes pasos: primero, se preparan los datos; luego, se calculan las medidas de (des)similitud entre cada par de objetos en el conjunto de datos. A continuación, se emplea la función de vinculación para construir un árbol jerárquico de grupos, donde objetos o grupos cercanos se vinculan según la información de distancia. Finalmente, se determina el punto de corte en el árbol jerárquico para formar grupos, logrando así una partición de los datos.

7.2.1 Estructura de datos y preparación

Los datos deben ser una matriz numérica con:

• Filas que representan observaciones (individuos).

• Columnas que representan variables.

#Carga de datos
data("USArrests")

#Estandarizar los datos
df <- scale(USArrests)

#Muestra las primeras 6 filas
head(df, nrow=6)
##                Murder   Assault   UrbanPop         Rape
## Alabama    1.24256408 0.7828393 -0.5209066 -0.003416473
## Alaska     0.50786248 1.1068225 -1.2117642  2.484202941
## Arizona    0.07163341 1.4788032  0.9989801  1.042878388
## Arkansas   0.23234938 0.2308680 -1.0735927 -0.184916602
## California 0.27826823 1.2628144  1.7589234  2.067820292
## Colorado   0.02571456 0.3988593  0.8608085  1.864967207
7.2.2 Medidas de similitud

En el contexto de la agrupación jerárquica, es crucial evaluar la similitud entre objetos o grupos para determinar las fusiones o divisiones adecuadas. Se dispone de diversos métodos para medir la (des)similitud, como las distancias euclidiana y de Manhattan detalladas en el Capítulo 3. En el entorno R, la función dist() permite calcular estas distancias entre cada par de objetos en un conjunto de datos, generando así una matriz de distancia o disimilitud que sirve como base para las decisiones de agrupamiento.

#df= los datos estandarizados
res.dist <- dist(df, method="euclidean")

Reformateamos los resultados de la función dist() en una matriz con as.matrix() para visualizar claramente la información de distancia entre objetos en el conjunto de datos original. Cada celda (i, j) representa la distancia entre el objeto i y el objeto j. El código R siguiente muestra las primeras 6 filas y columnas de la matriz de distancia.

as.matrix(res.dist)[1:6, 1:6]
##             Alabama   Alaska  Arizona Arkansas California Colorado
## Alabama    0.000000 2.703754 2.293520 1.289810   3.263110 2.651067
## Alaska     2.703754 0.000000 2.700643 2.826039   3.012541 2.326519
## Arizona    2.293520 2.700643 0.000000 2.717758   1.310484 1.365031
## Arkansas   1.289810 2.826039 2.717758 0.000000   3.763641 2.831051
## California 3.263110 3.012541 1.310484 3.763641   0.000000 1.287619
## Colorado   2.651067 2.326519 1.365031 2.831051   1.287619 0.000000
7.2.3 Vinculación

La información de distancia proporcionada por la función dist() se utiliza en la vinculación para agrupar objetos en pares similares, formando grupos que luego se vinculan para crear estructuras jerárquicas más extensas. Este procedimiento se repite hasta que todos los objetos del conjunto de datos original están interconectados en un árbol jerárquico. hclust() puede ser utilizado de la siguiente manera:

res.hc <- hclust(d= res.dist, method="ward.D2")

Las diferentes técnicas de vinculación en la agrupación jerárquica incluyen la vinculación máxima, mínima, media, centroide y el método de varianza mínima de Ward. La vinculación máxima utiliza la distancia máxima entre elementos de dos conglomerados, produciendo grupos más compactos. La vinculación mínima utiliza la distancia mínima, generando grupos más largos y dispersos. La vinculación media utiliza la distancia promedio, mientras que la vinculación centroide utiliza la distancia entre los centroides de los conglomerados. El método de varianza mínima de Ward minimiza la varianza total dentro de cada conglomerado, fusionando en cada paso el par con la distancia mínima.

7.2.3 Dendograma

Los dendrogramas corresponden a la representación gráfica del árbol jerárquico generado por la función hclust(). El dendrograma se puede producir en R usando la función base plot(res.hc), donde res.hc es la salida de hclust(). Aquí, usaremos la función fuiz_dend()[ en el paquete factoextra R] para producir un hermoso dendrograma. Primero instale factoextra escribiendo esto: install.packages(“factoextra”); A continuación visualice el dendrograma de la siguiente manera:

#cex: label size
fviz_dend(res.hc, cex= 0.5)
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## ℹ The deprecated feature was likely used in the factoextra package.
##   Please report the issue at <https://github.com/kassambara/factoextra/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

En el dendrograma que se muestra arriba, cada hoja corresponde a un objeto. A medida que ascendemos en el árbol, los objetos que son similares entre sí se combinan en ramas, que a su vez se fusionan a mayor altura.

7.3 Verificación del árbol del clúster

Las diferentes técnicas de vinculación en la agrupación jerárquica incluyen la vinculación máxima, mínima, media, centroide y el método de varianza mínima de Ward. La vinculación máxima utiliza la distancia máxima entre elementos de dos conglomerados, produciendo grupos más compactos. La vinculación mínima utiliza la distancia mínima, generando grupos más largos y dispersos. La vinculación media utiliza la distancia promedio, mientras que la vinculación centroide utiliza la distancia entre los centroides de los conglomerados. El método de varianza mínima de Ward minimiza la varianza total dentro de cada conglomerado, fusionando en cada paso el par con la distancia mínima.

res.coph <- cophenetic(res.hc)

#correlación
#la distancia original
cor(res.dist, res.coph)
## [1] 0.6975266
res.hc2 <- hclust(res.dist, method="average")
cor(res.dist, cophenetic(res.hc2))
## [1] 0.7180382
7.4 Cortar el dendograma en diferentes grupos

Cortar el dendrograma para formar grupos en la agrupación jerárquica plantea el desafío de determinar el número de grupos y la altura adecuada para el corte. La función cutree() de R, aplicada al árbol generado por hclust(), facilita este proceso al permitir especificar el número deseado de grupos o la altura de corte. Al ejecutar cutree(), se obtiene un vector que asigna a cada observación el número correspondiente al grupo al que pertenece.

#Cortar en 4 grupos
grp<- cutree(res.hc, k=4)
head(grp, n=4)
##  Alabama   Alaska  Arizona Arkansas 
##        1        2        2        3
#numero de miembros en cada cluster
table(grp)
## grp
##  1  2  3  4 
##  7 12 19 12
#Obtener los nombres de los miembros de cluster 1
rownames(df)[grp==1]
## [1] "Alabama"        "Georgia"        "Louisiana"      "Mississippi"   
## [5] "North Carolina" "South Carolina" "Tennessee"
#Cortar en cuatro grupos y colores por grupo
fviz_dend(res.hc, k = 4, # Cut in four groups
cex = 0.5, # label size
k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
color_labels_by_k = TRUE, 
rect = TRUE 
)

#Usando la función fviz_cluster()
fviz_cluster(list(data = df, cluster = grp),
palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
ellipse.type = "convex", # Concentration ellipse
repel = TRUE, # Avoid label overplotting (slow)
show.clust.cent = FALSE, ggtheme = theme_minimal())

7.5 Cluster R package

El paquete cluster de R facilita la realización de análisis de clusters en R. Proporciona las funciones agnes() y diana() para calcular clustering aglomerativo y divisivo, respectivamente. Estas funciones realizan todos los pasos necesarios para usted. No es necesario ejecutar las funciones scale(), dist() y hclust() por separado. Las funciones se pueden ejecutar de la siguiente manera:

# Cluster R package
res.agnes <- agnes(x = USArrests, # data matrix
stand = TRUE, # Estandarización de datos
metric = "euclidean", 
method = "ward" 
)

res.diana <- diana(x = USArrests, # data matrix
stand = TRUE, # Estandarización de datos
metric = "euclidean" 
)

fviz_dend(res.agnes, cex = 0.6, k = 4)

7.6 Aplicación de agrupamiento jerárquico al análisis de datos de expresión genética

En el análisis de datos de expresión genética, el agrupamiento jerárquico se emplea como una etapa inicial para investigar los datos. El objetivo es identificar posibles grupos de genes o muestras que presenten patrones similares de expresión genética. En este contexto, se han propuesto diversas medidas de distancia (ver Capítulo 3) para evaluar la similitud o disimilitud entre los ítems, facilitando así la decisión sobre qué ítems deben agruparse.

7.6 Resumen

La agrupación jerárquica es un enfoque de análisis de conglomerados que genera una representación en forma de árbol, conocida como dendrograma, para un conjunto de datos. En este dendrograma, los objetos están conectados entre sí según su nivel de similitud. En R, para llevar a cabo un análisis de conglomerados jerárquico, se inicia calculando la matriz de distancias mediante la función dist(). Posteriormente, esta matriz se utiliza en la función hclust() para obtener el árbol jerárquico. Para una visualización efectiva del dendrograma, se puede emplear la función fviz_dend() del paquete R factoextra. Además, es posible dividir el árbol en grupos definidos por una altura específica utilizando la función cutree().

Capítulo 8
Comparación de dendogramas

Tras abordar el cálculo del agrupamiento jerárquico en el Capítulo 7, se presenta ahora la comparación de dos dendrogramas mediante el uso del paquete dendextend en R. Este paquete ofrece diversas funciones para esta tarea, destacando especialmente dos de ellas: tanglegram(), que facilita la comparación visual de dos dendrogramas, y cor.dendlist(), destinada a calcular una matriz de correlación entre dendrogramas.

8.1 Principios fundamentales de K-means

Usaremos los conjuntos de datos de USArrests base R y comenzaremos estandarizando las variables usando la función scale() de la siguiente manera:

df <- scale(USArrests)

#Contiene 10 filas
set.seed(123)
ss<- sample(1:50, 10)
df<- df[ss,]
8.2 Comparación dendograms

Comenzamos creando una lista de dos dendrogramas calculando la agrupación jerárquica (HC) utilizandodos métodos de vinculación diferentes (“promedio” y “ward.D2”). A continuación, transformamoslos resultados como dendrogramas y creamos una lista para contener los dos dendrogramas.

install.packages(“dendextend”)

library(dendextend)
## Warning: package 'dendextend' was built under R version 4.3.2
## 
## ---------------------
## Welcome to dendextend version 1.17.1
## Type citation('dendextend') for how to cite the package.
## 
## Type browseVignettes(package = 'dendextend') for the package vignette.
## The github page is: https://github.com/talgalili/dendextend/
## 
## Suggestions and bug-reports can be submitted at: https://github.com/talgalili/dendextend/issues
## You may ask questions at stackoverflow, use the r and dendextend tags: 
##   https://stackoverflow.com/questions/tagged/dendextend
## 
##  To suppress this message use:  suppressPackageStartupMessages(library(dendextend))
## ---------------------
## 
## Attaching package: 'dendextend'
## The following object is masked from 'package:stats':
## 
##     cutree
res.dist<-dist(df,method="euclidean")

hc1<- hclust(res.dist, method="average")
hc2<- hclust(res.dist, method="ward.D2")

#Creación de dos dendograms
dend1 <- as.dendrogram (hc1)
dend2 <- as.dendrogram (hc2)

#Creación lista
dend_list <- dendlist(dend1, dend2)
8.2.1 Comparación visual de dos dendogramas

En el contexto de la comparación visual de dos dendrogramas, emplearemos la función tanglegram() del paquete dendextend. Esta función traza ambos dendrogramas uno al lado del otro, conectando sus etiquetas con líneas. La calidad de la alineación de los dos árboles puede evaluarse mediante la función entrelazamiento(), donde un coeficiente más bajo indica una mejor alineación, variando entre 1 (entrelazamiento total) y 0 (sin entrelazamiento).

tanglegram(dend1, dend2)

tanglegram(dend1, dend2,
highlight_distinct_edges = FALSE, # Turn-off dashed lines
common_subtrees_color_lines = FALSE, # Turn-off line colors
common_subtrees_color_branches = TRUE, # Color common branches
main = paste("Entanglement =", round(entanglement(dend_list), 2))
)

8.2.2 Matriz de correlación entre una lista de dendrograma

La función cor.dendlist() se utiliza para calcular la matriz de correlación “Baker” o “Cophenetic” entre una lista de árboles. El valor puede oscilar entre -1 y 1. Un valor cercano a 0 significa que los dos árboles no son estadísticamente similares.

cor.dendlist(dend_list, method = "cophenetic")
##           [,1]      [,2]
## [1,] 1.0000000 0.9925544
## [2,] 0.9925544 1.0000000
cor.dendlist(dend_list, method = "baker")
##           [,1]      [,2]
## [1,] 1.0000000 0.9895528
## [2,] 0.9895528 1.0000000
cor_cophenetic(dend1, dend2)
## [1] 0.9925544
cor_bakers_gamma(dend1, dend2)
## [1] 0.9895528
# Creación de múltiples dendrograms
dend1 <- df %>% dist %>% hclust("complete") %>% as.dendrogram
dend2 <- df %>% dist %>% hclust("single") %>% as.dendrogram
dend3 <- df %>% dist %>% hclust("average") %>% as.dendrogram
dend4 <- df %>% dist %>% hclust("centroid") %>% as.dendrogram
# Correlación matrix
dend_list <- dendlist("Complete" = dend1, "Single" = dend2,
"Average" = dend3, "Centroid" = dend4)
cors <- cor.dendlist(dend_list)
round(cors, 2)
##          Complete Single Average Centroid
## Complete     1.00   0.46    0.45     0.30
## Single       0.46   1.00    0.23     0.17
## Average      0.45   0.23    1.00     0.31
## Centroid     0.30   0.17    0.31     1.00
library(corrplot)
## Warning: package 'corrplot' was built under R version 4.3.2
## corrplot 0.92 loaded
corrplot(cors, "pie", "lower")

Capítulo 9
Visualización de dendrogramas

En capítulos previos, se explicó que un dendrograma es una representación en forma de árbol de datos generados mediante métodos de agrupamiento jerárquico, como se detalló en el Capítulo 7. Este artículo presenta código en R para la visualización y personalización de dendrogramas, además de ofrecer información sobre cómo guardar y ampliar un dendrograma extenso. El proceso comienza con el cálculo de la agrupación jerárquica utilizando conjuntos de datos de USArrests.

#Cargar datos
data(USArrests)

#Computación distancias y clustering
dd <- dist(scale(USArrests), method="euclidean")
hc <- hclust(dd, method= "ward.D2")

Para visualizar el dendrograma, usamos los siguientes paquetes y funciones de R:

install.packages(c("factoextra", "dendextend"))
## Warning: packages 'factoextra', 'dendextend' are in use and will not be
## installed
9.1 Visualizando dendrogramas

Usaremos la función fviz_dend()[en el paquete R factoextra] para crear fácilmente un dendrograma usando el gráfico base de R o ggplot2. También proporciona una opción para dibujar dendrogramas circulares y árboles de tipo filogénico. Para crear dendrogramas básicos, escriba esto:

library(factoextra)
fviz_dend(hc, cex=0.5)

fviz_dend(hc, cex=0.5,
          main= "dendrogram - ward.D2",
          xlab= "Objects", ylab= "Distance", sub="")

fviz_dend(hc, cex=0.5, horiz=TRUE)

También es posible cortar el árbol a una altura determinada para dividir los datos en múltiples grupos como se describe en el capítulo anterior: Agrupación jerárquica (Capítulo 7). En este caso, es posible colorear las ramas por grupos y agregar un rectángulo alrededor de cada una.

للPara cambiar el tema de la trama, utilice el argumento ggtheme, que permite que los valores incluyan los temas oficiales de gg-plot2 [theme_gray(), theme_bw(), theme_minimal(), theme_classic(), theme_void()] o cualquier otro tema de ggplot2 definido por el usuario.

fviz_dend(hc, k = 4, # Cut in four groups
cex = 0.5, # label size
k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
color_labels_by_k = TRUE, # color labels by groups
ggtheme = theme_gray() # Change theme
)

Los valores permitidos para k_color incluyen paletas de cerveza del paquete RColor Brewer (p. ej. “RdBu”, “Blues”, “Dark2”, “Set2”, …;) y paletas de revistas científicas de gasci R paquete (por ejemplo: “npg”, “aaas”, “lancet”, “jco”, “ucscgb”, “uchicago”, “simpsons” y “rickandmorty”). En el código R a continuación, cambiaremos los colores del grupo usando la paleta de colores “jco”:

#
fviz_dend(hc, cex = 0.5, k = 4, # Cut in four groups
k_colors = "jco")

#Si quieres dibujar un dendrograma horizontal con rectangulos alrededor de los clusters, usa esto:

fviz_dend(hc, k = 4, cex = 0.4, horiz = TRUE, k_colors = "jco",
rect = TRUE, rect_border = "jco", rect_fill = TRUE)

#Si prefieres una figura o dendrograma circular usa la opción type="circular"

fviz_dend(hc, cex = 0.5, k = 4,
k_colors = "jco", type = "circular")

#Para trazar un árbol de tipo filogénico, use type = "phylogenic" y repel = TRUE (para evitar que las etiquetas se sobrecarguen). Esta funcionalidad requiere el paquete R igraph. Asegúrese de que esté instalado antes de escribir el siguiente código R.

library(igraph)
## Warning: package 'igraph' was built under R version 4.3.2
## 
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union
library(factoextra)

# Suponiendo que 'hc' es el objeto de análisis jerárquico de agrupamiento previamente creado

# Visualización de un dendrograma filogenético
fviz_dend(hc, k = 4, k_colors = "jco", type = "phylogenic", repel = TRUE)

El diseño predeterminado para los árboles filogénicos es “layout.auto”. Los valores permitidos son uno de: c(“layout.auto”, “layout_with_drl”, “layout_as_tree”, “layout.gem”, “layout.mds”, “layout_with_lgl”). Para leer más sobre estos diseños, lea la documentación del paquete igraph R.

fviz_dend(hc,k=4, 
          k_colors="jco",
          type="phylogenic", repeal=TRUE,
          phylo_layout = "layout.gem")

9.2 Caso de dendrograma con grandes conjuntos de datos

Cuando realiza el análisis de agrupación jerárquica en un conjunto de datos extenso, puede resultar beneficioso ampliar el dendrograma o representar únicamente un subconjunto de éste. Otra opción viable es generar el dendrograma en una página de gran tamaño en formato PDF, lo cual permite su ampliación sin sufrir pérdida de resolución.

9.2.1 Ampliar el dendrograma

Si desea ampliar los primeros grupos, es posible utilizar la opción xlim e ylim para limitar el área de trazado. Por ejemplo, escriba el siguiente código:

fviz_dend(hc, xlim = c(1, 20), ylim = c(1, 8))

9.2.2 Trazar un subárbol de dendrogramas

Para trazar un subárbol, seguiremos el procedimiento siguiente:

  1. Cree el dendrograma completo usando fviz_dend() y guarde el resultado en un objeto, llamado dend_plot, por ejemplo.

  2. Utilice la función base de R cut.dendrogram() para cortar el dendrograma, a una altura determinada (h), en múltiples subárboles. Esto devuelve una lista con los componentes Supper y $lower, el primero es una versión truncada del árbol original, también de clase dendrograma, el segundo una lista con las ramas obtenidas al cortar el árbol, cada una un dendrograma.

  3. Visualice subárboles usando fviz_dend().

#Trazar un subárbol de dendrogramas
# Crea un gráfico de todo el dendrograma,
# y extrae los datos del dendrograma
dend_plot <- fviz_dend(hc, k = 4, 
cex = 0.5, 
k_colors = "jco"
)
dend_data <- attr(dend_plot, "dendrogram") # Extraer datos de dendrograma
# Cortar el dendrograma a la altura h = 10
dend_cuts <- cut(dend_data, h = 10)
# Visualiza la versión truncada que contiene
# dos ramas
fviz_dend(dend_cuts$upper)
## Warning in min(-diff(our_dend_heights)): ningún argumento finito para min;
## retornando Inf

#Grafica el dendrograma entero
print(dend_plot)

fviz_dend(dend_cuts$lower[[1]], main = "Subtree 1")

fviz_dend(dend_cuts$lower[[2]], main = "Subtree 2")

#Además puedes graficar arboles circulares de la siguiente manera:

fviz_dend(dend_cuts$lower[[2]], type = "circular")

9.2.3 Guardar el dendrograma en una página PDF grande

Si tiene un dendrograma grande, puede guardarlo en una página PDF grande, que se puede ampliar sin pérdida de resolución.

pdf("dendrogram.pdf", width=30, height=15)
p<- fviz_dend(hc, k=4, cex=1, k_colors="jco")
print(p)
dev.off
## function (which = dev.cur()) 
## {
##     if (which == 1) 
##         stop("cannot shut down device 1 (the null device)")
##     .External(C_devoff, as.integer(which))
##     dev.cur()
## }
## <bytecode: 0x00000204a83ebaf8>
## <environment: namespace:grDevices>
9.3 Manipulación de dendrogramas usando dendextend

El paquete dendextend facilita la modificación visual de dendrogramas y la comparación entre ellos. En esta sección, utilizamos el operador de encadenamiento (%>%) para simplificar el código, convirtiendo múltiples operaciones en una forma más legible y estructurada. Este operador transforma expresiones del tipo x %>% f(y) en f(x, y), permitiendo la lectura secuencial de las operaciones de izquierda a derecha y de arriba a abajo. Los siguientes códigos R ilustran de manera equivalente esta idea.

#Codigo estandar de R para creación de dendrograma
data <- scale(USArrests)
dist.res <- dist(data)
hc <- hclust(dist.res, method = "ward.D2")
dend <- as.dendrogram(hc)
plot(dend)

#Codigo de R para creación de dendrograma usando el operador chaining
library(dendextend)
dend <- USArrests[1:5,] %>% # data
scale %>% # Scale the data
dist %>% # calculate a distance matrix,
hclust(method = "ward.D2") %>% # Hierarchical clustering
as.dendrogram # Turn the object into a dendrogram.
plot(dend)

Funciones para personalizar dendrogramas: la función set() [en el paquete dendextend] se puede utilizar para cambiar los parámetros de un dendrograma.

Posibles valores para el argumento que incluyen:

Figura cap 6.1

#Ejemplo
library(dendextend)
mycols <- c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07")
dend <- as.dendrogram(hc) %>%
set("branches_lwd", 1) %>% 
set("branches_k_color", mycols, k = 4) %>% 
set("labels_colors", mycols, k = 4) %>% 
set("labels_cex", 0.5) 
fviz_dend(dend)

9.4 Resumen

En este contexto, se detallan diversas funciones y paquetes para la visualización y personalización de dendrogramas. Entre ellos, destaca fviz_dend() del paquete R factoextra, que ofrece soluciones prácticas para trazar dendrogramas de manera sencilla y estéticamente atractiva. Esta función es versátil, permitiendo la creación de dendrogramas tanto rectangulares como circulares, así como la representación de árboles filogenéticos. Además, se menciona el paquete dendextend, el cual proporciona métodos flexibles para la personalización de dendrogramas, ofreciendo opciones adicionales para adaptar la apariencia según las necesidades específicas del usuario. También se describe cómo realizar la representación gráfica de subconjuntos de dendrogramas extensos, destacando la capacidad de estos paquetes para abordar situaciones con conjuntos de datos de gran tamaño.

Capítulo 10
Heatmap: Estático e interactivo

El mapa de calor, también conocido como imagen de color falso, ofrece una representación visual de la agrupación jerárquica en datos. Este método transforma los valores de los datos en una escala de colores, permitiendo la observación simultánea de grupos de muestras y características. La agrupación jerárquica se aplica a las filas y columnas de la matriz de datos, reorganizando estas filas y columnas según los resultados de la agrupación. Este proceso posiciona las observaciones similares en proximidad. Los bloques de valores “altos” y “bajos” aparecen contiguos en la matriz de datos. Posteriormente, se utiliza un esquema de colores para la visualización final de la matriz de datos. Esta representación facilita la identificación de variables que pueden ser características distintivas de cada grupo de muestras.

10.1 Paquetes y funciones R para dibujar heatmaps

Existe una gran cantidad de paquetes y funciones de R para dibujar mapas de calor estáticos e interactivos, que incluyen:

• heatmap() [función base de R, paquete de estadísticas]: dibuja un mapa de calor simple

• heatmap.2) [paquete gplots R]: dibuja un mapa de calor mejorado en comparación con la función base de R.

• pheatmap() [paquete pheatmap R]: dibuja bonitos mapas de calor y proporciona más control para cambiar la apariencia de los mapas de calor. d3heatmap() [paquete d3heatmap R]: dibuja un mapa de calor interactivo/en el que se puede hacer clic.

• Heatmap() [paquete ComplexHeatmap R/Bioconductor]: dibuja, anota y organiza mapas de calor complejos (muy útil para el análisis de datos genómicos)

Aquí, comenzamos describiendo las 5 funciones R para dibujar mapas de calor. A continuación, nos centraremos en el paquete Complex Heatmap, que proporciona una solución flexible para organizar y anotar múltiples mapas de calor. También permite visualizar la asociación entre diferentes datos de diferentes fuentes.

10.2 Preparación de datos

Usamos datos de mtcars como conjunto de datos de demostración. Comenzamos estandarizando los datos para que las variables sean comparables:

df <- scale(mtcars)
10.3 R base de heatmap: heatmap()

Se puede utilizar la función R heatmap() incorporada [en el paquete de estadísticas]. Un formato simplificado es:

#Default plot
heatmap(df, scale= "none")

#Es posible especificar la paleta de colores usando el argumento col, la cual puede ser definida de la siguiente manera:

#Usando custom colors
col<- colorRampPalette(c("red", "white", "blue"))(256)

#Usando la paleta de color RColorBrewer
library("RColorBrewer")
col <- colorRampPalette(brewer.pal(10, "RdYlBu"))(256)

# Usar RColorBrewer color palette names
library("RColorBrewer")
col <- colorRampPalette(brewer.pal(10, "RdYlBu"))(256)
heatmap(df, scale = "none", col =  col, 
        RowSideColors = rep(c("blue", "pink"), each = 16),
        ColSideColors = c(rep("purple", 5), rep("orange", 6)))

10.4 Mapas de calor mejorados: heatmap.2()

La función heatmap.2() [en el paquete gplots] proporciona muchas extensiones a la función estándar R heatmap() presentada en la sección anterior.

# install.packages("gplots")
library("gplots")
## Warning: package 'gplots' was built under R version 4.3.2
## 
## Attaching package: 'gplots'
## The following object is masked from 'package:stats':
## 
##     lowess
heatmap.2(df, scale = "none", col = bluered(100), 
          trace = "none", density.info = "none")

Se pueden utilizar otros argumentos, entre ellos:

• labRow, laboratorio Col

• hclustfun: hclustfun=función(x) hclust(x, método=“ward”)

En el código R anterior, la función bluered() [en el paquete gplots] se usa para generar.Un conjunto de colores que varían suavemente. También puede utilizar las siguientes funciones del generador de colores:

• panel de color (n, bajo, medio, alto)

  • n: número deseado de elementos de color que se generarán

  • bajo, medio, alto: colores a utilizar para los valores más bajo, medio y más alto, mid puede omitirse.

• rojoverde(n), verderojo(n), azulrojo(n) y rojoazul(n)

10.5 Heatmaps estéticos: pheatmap()

Primero, instale el paquete pheatmap: install.packages(“pheatmap”); luego escribe esto:

library("pheatmap")
## Warning: package 'pheatmap' was built under R version 4.3.2
pheatmap(df, cutree_rows = 4)

Hay argumentos disponibles para cambiar la métrica de agrupación predeterminada (“euclidiana”) y el método (“completo”). También es posible anotar filas y columnas utilizando variables de agrupación.

10.7 Heatmaps usando dendextend

El paquete dendextend se puede utilizar para mejorar funciones de otros paquetes. Los datos de mtcars se utilizan en las siguientes secciones. Comenzaremos definiendo el orden y la apariencia de las filas y columnas usando dendextend. Estos resultados se utilizan en otras funciones de otros paquetes.

library(dendextend)
# ordenar por filas
Rowv  <- mtcars %>% scale %>% dist %>% hclust %>% as.dendrogram %>%
   set("branches_k_color", k = 3) %>% set("branches_lwd", 1.2) %>%
   ladderize
# Ordenar por columnas
Colv  <- mtcars %>% scale %>% t %>% dist %>% hclust %>% as.dendrogram %>%
   set("branches_k_color", k = 2, value = c("orange", "blue")) %>%
   set("branches_lwd", 1.2) %>%
   ladderize
10.8 Complejo heatmap

ComplexHeatmap es un paquete R/bioconductor, desarrollado por Zuguang Gu, que proporciona una solución flexible para organizar y anotar múltiples mapas de calor. También permite visualizar la asociación entre diferentes datos de diferentes fuentes.

10.8.1 Heatmap simple

Puedes diseñar un heatmap simple de la siguiente manera:

#install.packages("ComplexHeatmap")
#install.packages("devtools")  
#devtools::install_github("jokergoo/ComplexHeatmap")

library(ComplexHeatmap)
## Loading required package: grid
## ========================================
## ComplexHeatmap version 2.15.4
## Bioconductor page: http://bioconductor.org/packages/ComplexHeatmap/
## Github page: https://github.com/jokergoo/ComplexHeatmap
## Documentation: http://jokergoo.github.io/ComplexHeatmap-reference
## 
## If you use it in published research, please cite either one:
## - Gu, Z. Complex Heatmap Visualization. iMeta 2022.
## - Gu, Z. Complex heatmaps reveal patterns and correlations in multidimensional 
##     genomic data. Bioinformatics 2016.
## 
## 
## The new InteractiveComplexHeatmap package can directly export static 
## complex heatmaps into an interactive Shiny app with zero effort. Have a try!
## 
## This message can be suppressed by:
##   suppressPackageStartupMessages(library(ComplexHeatmap))
## ========================================
## ! pheatmap() has been masked by ComplexHeatmap::pheatmap(). Most of the arguments
##    in the original pheatmap() are identically supported in the new function. You 
##    can still use the original function by explicitly calling pheatmap::pheatmap().
## 
## Attaching package: 'ComplexHeatmap'
## The following object is masked from 'package:pheatmap':
## 
##     pheatmap
Heatmap(df, 
        name = "mtcars", #title of legend
        column_title = "Variables", row_title = "Samples",
        row_names_gp = gpar(fontsize = 7) # Text size for row names
        )

Para especificar colores personalizados, debe utilizar la función color Ramp2() [paquete circular], de la siguiente manera:

install.packages(RcolorBrewer)

library(circlize)
## Warning: package 'circlize' was built under R version 4.3.2
## ========================================
## circlize version 0.4.15
## CRAN page: https://cran.r-project.org/package=circlize
## Github page: https://github.com/jokergoo/circlize
## Documentation: https://jokergoo.github.io/circlize_book/book/
## 
## If you use it in published research, please cite:
## Gu, Z. circlize implements and enhances circular visualization
##   in R. Bioinformatics 2014.
## 
## This message can be suppressed by:
##   suppressPackageStartupMessages(library(circlize))
## ========================================
## 
## Attaching package: 'circlize'
## The following object is masked from 'package:igraph':
## 
##     degree
mycols <- colorRamp2(breaks= c(-2,0, 2),
                     color= c("green", "white", "red"))
Heatmap(df,name="mtcars", col= mycols)

#Usando la paleta de color deRColorBrewer 
library("circlize")
library("RColorBrewer")
Heatmap(df, name = "mtcars",
        col = colorRamp2(c(-2, 0, 2), brewer.pal(n=3, name="RdBu")))

#Modificación de la apariencia de dendogramas usando la función color_branches()
library(dendextend)
row_dend = hclust(dist(df)) # row clustering
col_dend = hclust(dist(t(df))) # column clustering
Heatmap(df, name = "mtcars", 
        row_names_gp = gpar(fontsize = 6.5),
        cluster_rows = color_branches(row_dend, k = 4),
        cluster_columns = color_branches(col_dend, k = 2))
10.8.2 División del heatmap por filas

En la sección 10.8.2, la división del mapa de calor por filas se aborda mediante dos enfoques: el uso del algoritmo k-means o una variable de agrupación. Cuando se opta por k-means, es crucial emplear la función set.seed() para garantizar la reproducibilidad precisa de los resultados en momentos posteriores. Para dividir el dendrograma utilizando k-medias, se recomienda escribir el código correspondiente.

set.seed(2)
Heatmap(df, name = "mtcars", k = 2)

Para dividir por una variable de agrupación, utilice el argumento dividir. En el siguiente ejemplo, usaremos los niveles de la variable de factor cyl [en el conjunto de datos de mtcars] para dividir el mapa de calor por filas. Recuerde que la columna cyl corresponde al número de cilindros.

Heatmap(df, name = "mtcars", split = mtcars$cyl,
        row_names_gp = gpar(fontsize = 7))

Tenga en cuenta que la división también puede ser una división de las filas del mapa de calor en el marco de datos en el que haya diferentes combinaciones de niveles.

10.8.3 Anotación Heatmap

La clase HeatmapAnnotation se utiliza para definir anotaciones en filas o columnas. Para el siguiente ejemplo, transpondremos nuestros datos para tener las observaciones en columnas y las variables en filas.

df <- t(df)
10.8.3.1 Anotación simple

El vector, que contiene valores discretos o continuos, se utiliza para anotar filas o columnas. Usaremos las variables cualitativas cyl (niveles = “4”, “5” y “8”) y am (niveles = “0” y “1”), y la variable continua mpg para anotar columnas. definido de la siguiente manera:

Para cada una de estas 3 variables, hay colores personalizados.

annot_df <- data.frame(cyl =mtcars$cyl, am= mtcars$am, mpg = mtcars$mpg)
col=list(cyl = c("4"= "green", "6"="gray", "8"="darkred"),
         am=c("0"= "yellow", "1"="orange"),
         mpg= circlize::colorRamp2(c(17,25),
                                   c("lightblue", "purple")) )

Figura cap 6.1

10.8.3.2 Complejo de antonación

En esta sección veremos cómo combinar mapas de calor y algunos gráficos básicos para mostrar la distribución de datos. Para gráficos de anotaciones simples, se pueden utilizar las siguientes funciones: anno_points(), anno_barplot(), anno_boxplot(), anno_density() y anno_histogram().

A continuación se muestra un ejemplo:

.hist = anno_histogram(df, gp = gpar(fill = "lightblue"))
.density = anno_density(df, type = "line", gp = gpar(col = "blue"))
ha_mix_top = HeatmapAnnotation(
  hist = .hist, density = .density,
  height = unit(3.8, "cm")
  )
# Definir algunos gráficos
.violin = anno_density(df, type = "violin", 
                       gp = gpar(fill = "lightblue"), which = "row")
.boxplot = anno_boxplot(df, which = "row")
ha_mix_right = HeatmapAnnotation(violin = .violin, bxplt = .boxplot,
                              which = "row", width = unit(4, "cm"))
# Combinar la anotación con el heatmap
Heatmap(df, name = "mtcars", 
        column_names_gp = gpar(fontsize = 8),
        top_annotation = ha_mix_top) + ha_mix_right
10.8.3.3 Combinación de múltiples heatmaps

Para combinar múltiples heatmaps, sigue los pasos que se muestran a continuación.

# Suponiendo que 'df' es tu conjunto de datos
# Heatmap con k-means clustering (km = 3)
ht1 = Heatmap(df, name = "ht1", km = 3, column_names_gp = gpar(fontsize = 9))

# Heatmap adicional
ht2 = Heatmap(df, name = "ht2", 
        col = circlize::colorRamp2(c(-2, 0, 2), c("green", "white", "red")),
        column_names_gp = gpar(fontsize = 9))

# Combine los dos mapas de calor
combined_heatmap = ht1 %v% ht2

Figura cap 6.1

10.9 Aplicación a la matriz de expresión génica

En los datos de expresión genética, las filas son genes y las columnas son muestras. Se puede adjuntar más información sobre los genes después del mapa de calor de expresión, como la longitud del gen y el tipo de genes.

expr <- readRDS(paste0(system.file(package = "ComplexHeatmap"),
                      "/extdata/gene_expression.rds"))
mat <- as.matrix(expr[, grep("cell", colnames(expr))])
type <- gsub("s\\d+_", "", colnames(mat))
ha = HeatmapAnnotation(
  df = data.frame(type = type),
   annotation_height = unit(4, "mm")
  )

Heatmap(mat, name = "expression", km = 5, top_annotation = ha,
    show_row_names = FALSE, show_column_names = FALSE) +
Heatmap(expr$length, name = "length", width = unit(5, "mm"),
    col = circlize::colorRamp2(c(0, 100000), c("white", "orange"))) +
Heatmap(expr$type, name = "type", width = unit(5, "mm")) +
Heatmap(expr$chr, name = "chr", width = unit(5, "mm"),
    col = circlize::rand_color(length(unique(expr$chr))))
## There are 23 unique colors in the vector `col` and 23 unique values in
## `matrix`. `Heatmap()` will treat it as an exact discrete one-to-one
## mapping. If this is not what you want, slightly change the number of
## colors, e.g. by adding one more color or removing a color.

También es posible visualizar alteraciones genómicas e integrar diferentes niveles moleculares (expresión génica, metilación del ADN,…).

10.10 Resumen

En R, puedes crear mapas de calor utilizando la función base heatmap.2() del paquete gplots para opciones básicas y control sobre parámetros gráficos. También, la función heatmap() en el mismo paquete es una alternativa básica.

Para mapas de calor más complejos y versátiles, el paquete Complex Heatmap proporciona la función Heatmap(). Esta opción es especialmente útil en campos como la genómica, permitiendo la creación, anotación y organización de mapas de calor más elaborados. La elección entre estas funciones dependerá de la complejidad y control deseados en la visualización.