bibliotecas a usar

library(factoextra)
## Loading required package: ggplot2
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(cluster)
library(dendextend)
## 
## ---------------------
## 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
library(corrplot)
## corrplot 0.92 loaded

Capitulo 7

Agglomerative Clustering

El Agglomerative clustering es el tipo mas común de agrupamiento de datos en base a similitudes de los mismos datos. Esto tambien se conoce como AGNES (Agglomeraative Nesting). Al momento de suministrar los datos se tratan como independientes hasta el momento que se relacionan de a pares y forman un agrupamiento de datos muy grandes que se conoce como Dendrogram

Algorithm

Las agrupaciones aglomeradas funcionan de una manera “bottom-up”, esto quiere decir que viene desde lo micro hasta lo mas grande y macro, como se dijó anteriormente, al principio se trata cada una de las agrupaciones como individual, esto se puede asemejar a hojas; posterior a esto al unirse varias agrupaciones forman “nodos” hasta que las agrupaciones son tan grandes que se unen en una misma “raíz”. La operacion inversa al AGNES es DIANA (Division Analysis). Funciona de una forma “top-down” y esto quiere decir que empieza desde las “raices” y las va subdiviendo de a dos hasta que termina con las “hojas”

Step to agglomerative hierarchical clustering

Para crear un AGNES es necesario seguir estos pasos:

  1. Preparar los datos
  2. Computar y establecer las similitudes entre pares de datos
  3. Usar funciones enlazadoras que unan los pares de datos y formen el arbol de datos
  4. Determinar donde cortar el arbol jerarquico en agrupaciones.

Data structure and preparation

Todos los datos deben ser matrices con:

  • Filas que representen las observaciones individuales
  • Columnas que representen variables

Para este caso usaremos los datos contenidos en USArrests.

data("USArrests")
df <- scale(USArrests)
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

Similarity measures

Para determinar que agrupaciones deben ser combinadas se debe medir las similitudes entre los datos. En el caso de R se puede usar euclidean para conocer la distancia de los datos dentro de la matriz, esto se usa a continuacion para conocer la simillitud de los datos contenidos en USArrests.

res.dist <- dist(df, method = "euclidean")
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

Como vemos en el chunk anterior, se puede facilmente ver la distancia entre datos si estos se unen en una matriz nueva en la que la distancia entre la fila i se cuantifica con la columna j. Como se mide la distancia entre todos los datos, tambien se compara los datos entre ellos y por supuesto el resultado de su diferencia es 0 como se puede ver el la fila 1 y columna 1, estos datos no se tienen en cuenta y se procede a unir los datos mas parecidos en busca del arbol jerarquico.

Linkage

Como se dijo anteriormente, las funciones enlazadoras unen pares de datos en base a la distancia que hay entre ellos formando agrupaciones, porterior a esto, enlaza estas agrupaciones pequeñas en unas agrupaciones cada vez mas grandes que forman al final un arbol de agrupaciones. En el siguiente chunk se puede ver como usan la funncion hclust para unir los pares de datos mas cercanos contenidos en la matriz generada anteriormente.

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

Dendrogram

Los Dendrogram se refieren a la representación grafica del arbol jerarquico. En R pueden graficarse con muchas funciones, sin embargo, en esta ocasion se usa la función fviz_dend que recoge los datos de salida de hclust y los grafica.

library("factoextra")
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 <]8;;https://github.com/kassambara/factoextra/issueshttps://github.com/kassambara/factoextra/issues]8;;>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

En esta grafica podemos observar como cada serie de dato que forman las hojas son unidos hasta formar ramas que a su vez se unen para generar la raiz del arbol en la parte superior. En esta grafica la altura representa la similitud, por ente, entre mas alta sea la union significa que son menos similares los datos o las agrupaciones. Esto se coonoce como cophenetic distance entre los objetos.

Verify the cluster tree

Para verificar que el arbol jerarquico refleje verdaderamente las distancias medidas con anterioridad de los datos se puede comparar la distancia cophenetic con la distancia medida para generar la matriz, si la division entre estos dos se acerca a 1 se puede confirmar que el arbol es completamente valido, a continuacion se usa la funcion cophenetic para realizar la valoración.

res.coph <- cophenetic(res.hc)
cor(res.dist, res.coph)
## [1] 0.6975266

Como vemos, el dato es inferior a 0.75, por ende, hay una diferencia marcada y puede mejorarse, para hacer esto se usa de nuevo la funcion hclust y se usa el tipo de enlace average para commprobar si presenta una mejoria y por último, se compara otra vez la distancia original con la distancia cophenetic.

res.hc2 <- hclust(res.dist, method = "average")
cor(res.dist, cophenetic(res.hc2))
## [1] 0.7180382

Podemos ver que hubo una pequeña mejoria, lo que nos muestra ademas que el tipo de enlace average es mejor y mas util para unir datos.

Cut the dendrogram into different groups

El problema principal con los arboles jerarquicos es que no se puede saber cuantas agrupaciones (cluster) hay o donde cortar el dendrogram para formar clusters. Para resolver este problema esta la función cutree que divide el arbol en clusters especificados por nosotros mismos, por ejemplo, en este caso serían 4 grupos que se pueden observar en los siguientes vectores

grp <- cutree(res.hc, k = 4)
head(grp, n = 4)
##  Alabama   Alaska  Arizona Arkansas 
##        1        2        2        3
table(grp)
## grp
##  1  2  3  4 
##  7 12 19 12
rownames(df) [grp == 1]
## [1] "Alabama"        "Georgia"        "Louisiana"      "Mississippi"   
## [5] "North Carolina" "South Carolina" "Tennessee"

El resultado final del “corte” del arbol se puede graficar facilmente por la biblioteca factoextra usando la libreria fviz_dend como se ve a continuación

fviz_dend(res.hc, k = 4,
          cex = 0.5,
          k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
          color_labels_by_k = TRUE,
          rect = TRUE
          ) 

Por otro lado, usando la misma biblioteca pero la función fviz_cluster podemos ver la misma particion en forma de diagrama de dispersión en que las observaciones son representadas como puntos en el diagrama y un marco se dibuja al rededor de cada cluster.

fviz_cluster(list(data = df, cluster = grp),
             palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
             ellipse.type = "convex",
             repel = TRUE,
             show.clust.cent = FALSE, ggtheme = theme_minimal())

Cluster R package

En R existe la biblioteca cluster la cual posee las funciones agnes y diana que realizan todo el trabajo de realizacion del arbol y division del mismo, por ende, no es necesario aplicar las distancias de separacion ni usar la funcion hclust, pues en estas dos funciones realiza todo el trabajo. En el siguiente chunk se muestra un ejemplo de la biblioteca con la base de datos USArrests.

library("cluster")
res.agnes <- agnes(x = USArrests,
                   metric = "euclidian",
                   method = "ward"
                   )
res.diana <- diana(x = USArrests,
                   metric = "euclidean"
                   )
fviz_dend(res.agnes, cex = 0.6, k = 4)

Luego de usar las funciones agnes y diana se puede graficar facilmente el dendrogram que genera usando la funcion fviz_dend usada con anterioridad y como se puede observar en la grafica de arriba

Aplication of hierarchical clustering to gene expression data analysis

En el “gene expression data analysis” la agrupación de los datos es de los principales pasos para explorar los datos. En este caso el interes principal es cuales grupos de “genes” o grupos de muestras poseen similares “patrones de expresion genetica”. Para realizar esto se usan los recursos estudiados al inicio del capitulo, con la medición de la distancia euclidian se pueden ver patrones que ayudan a la creación de un arbol jerarquico que conlleva una union de los datos mediante funciones enlazadoras. De la misma forma que con los datos, dividir el arbol en clusters es dificil, para esto se realizan analisis preliminares a los datos para poder intrerpretar y dividir de forma apropiada los clusters

Summary

Como hemos visto a lo largo del capitulo el “Hierarchical clustering” es un metodo de analisis de agrupaciones, el cual produce una reprentación de un “arbol” de los datos (dendrogram), dichos datos estan unidos en base a la similitud de pares de datos. Para generar arboles jerarquicos en R se inicia midiendo que tan diferentes son los datos con la funcion dist y generando una matriz con la información de las diferencias, luego, con una funcion enlazadora como hclust se unen los pares de datos que menor diferncia posean y por último, se puede graficar usando la funcion fviz_dend y si se quiere “cortar” el arbol para agruparlo en diferentes clusters se puede emplear cutree.

Capitulo 8

Comparing Dendograms

Despues de mostrar como generar y crear Hierarchical clustering podemos enfocarnos en comparar dos dendrograms usando la biblioteca dendextend. Esta biblioteca provee muchas funciones para comparar dendrograms, pero solo se hablara de dos de ellas:

  • tanglegram para hacer una comparaci+on visual de los dendrogram y
  • cor.dendlist para hacer una computación de la relacion de dos matrices y gennerar así una comparacion

Data preparation

De nuevo, se usara la base de datos USArrests para generar las comparaciones entre dendrograms.

df <- scale(USArrests)
set.seed(123)
ss<- sample(1:50, 10)
df <- df[ss,]

Para hacer los diagramas facilmente diferenciables se usará solo 10 observaciones escogidas al azar entre las 50 observaciones usando la función sample

Comparing dendograms

Para comparar dos dendrograms se empieza creando una lista con los dendrograms a comparar creando dos hierarchical clustering (HC) usando dos funciones enlazadoras, luego, se transforman los dos HC en dendrograms y se añaden a una lista que los contenga, todo este proceso se ve a continuacion.

library(dendextend)
res.dist <- dist(df, method = "euclidean")
hc1 <- hclust(res.dist, method = "average")
hc2 <- hclust(res.dist, method = "ward.D2")
dend1 <- as.dendrogram (hc1)
dend2 <- as.dendrogram (hc2)
dend_list <- dendlist(dend1, dend2)

Visual comparison of two dendrograms

Para comparar visualmente dos dendrograms, se usa la función tanglegramm como se dijo con anterioridad, la cual grafica los dos dendrogram lado a lado con sus etiquetas conectadas por lineas. Para medir la similitud de los dendrograms se usa la funnción entanglement, la cual realiza una medición de entre 0 y 1. Entre mas bajo sea el nivel de dicha medicion mejor será la alineacion y similitud de los dos dendrogram. a coontinuacion se usa la funncion tanglegram para correlacionar los dos dendrogram.

tanglegram(dend1, dend2)

tanglegram(dend1, dend2,
           highlight_distinct_edges = FALSE,
           common_subtrees_color_lines = FALSE,
           common_subtrees_color_branches = TRUE,
           main = paste("Entanglement =", round(entanglement(dend_list), 2))
           )

Como podemos ver en esta grafica, se puede alterar tanto como se desee la funcion tanglegram para personalizarla a las necesidades de cada persona

Correlation matrix between a list of dendrograms

Para poder relacionar matrices de dendrogram se usa en este caso la funcion cor.dendlist la cual computa la distancia “baker” o la distancia “cophenetic” dentro de la lista de dendrograms. Los datos pueden variar entre 0 y 1, en el cual un numero cercano a 0 significa que los arboles no son estadisticamente similares. En las dos matrices a continuacion se observa como se usan ambos metodos para conocer lo parecidos que son los dos arboles.

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

Otra forma de realizar la misma operacion que vimos antes es de esta forma, en las cuales los vectores resultantes es la operacion al comparaar los dos arboles

cor_cophenetic(dend1, dend2)
## [1] 0.9925544
cor_bakers_gamma(dend1, dend2)
## [1] 0.9895528

En el caso que necesitemos comparar multiples dendrograms se puede usar el operador logico %>% para realizar funciones a la vez, como se ve a continuacion, tambien es util para simplificar el codigo.

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
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)
corrplot(cors, "pie", "lower")

En esta grafica vemos como por medio de la biblioteca corrplot y la funcion corrplot se puede observar las relaciones que existen en cada comparacion de forma practica y util, en este caso, usando un grafico circular.

Fin de la presentación