AnĂ¡lisis de cluster

Tagore. ClasificaciĂ³n de los versos de GitanyalĂ­ usando anĂ¡lisis de cluster (MĂ©todo: Agnes)

Pre-procesamientos

Clasificar los poemas comienza con el proceso de tokenizado y de separaciĂ³n de la identificaciĂ³n de los poemas del cuerpo del texto. En esa oportnidad seguirĂ© el procedimiento que describo a continuaciĂ³n:

#extraigo el texto que me interesa
tagore_clasificacion <- tagore$text[c(5:36, 39:69,
                  72:102, 105:138, 141:169,
                  172:203, 206:232, 235:266,
                  269:299, 302:332, 335:370,
                  373:408, 411:447, 450:485,
                  488:528, 531:569, 572:601,
                  604:635, 638:674, 677:710,
                  713:746, 749:779, 782:809,
                  812:845, 848:876, 879:911,
                  914:946, 949:976, 979:1012,
                  1015:1045, 1048:1074)]

# creo la variable  "poem_number"

tagore_clasificacion %>% 
      mutate(poem_number = str_extrac(text,
                                      "\\d+")) %>% 
      fill(poem_number) %>% 
      filter(text = str_extrac(text, "[a-zA-Z]+"))
head(tagore_clasificacion)
##                                                                                   text
## 1                                                                                     
## 2     Fue tu voluntad hacerme infinito. Este frĂ¡gil vaso mĂ­o tĂº lo derramas una y otra
## 3                                           vez, y lo vuelves a llenar con nueva vida.
## 4    TĂº has llevado por valles y colinas esta flautilla de caña, y has silbado en ella
## 5                                                         melodĂ­as eternamente nuevas.
## 6 Al contacto inmortal de tus manos, mi corazoncito se dilata sin fin en la alegrĂ­a, y
##   poem_number
## 1           1
## 2           1
## 3           1
## 4           1
## 5           1
## 6           1

Procedo a tokenizar. No es necesario extraer las palabras funcionales. Este anĂ¡lisis lo reservo para el momento de extraer las palabras mĂ¡s frecuentes en cada cluster

takore_tokens <- tagore_clasificacion %>% 
      unnest_tokens(palabras, text)

AnĂ¡lisis de cluster jerĂ¡rquico. Agnes

El df tokenizado debe convertirse en matriz, insumo para el anĂ¡lisis de cluster

#llevo los caracteres a nombre de filas

tagore_wider_2 <- data.frame(tagore_wider_2,
      row.names = tagore_wider_2$poem_number)

Ya tengo adelantado el cĂ¡lculo de la matriz de distancias, asĂ­c como el mĂ©thodo de aglomeraciĂ³n. SeguirĂ© con la visualiaciĂ³n del dendrograma, el anĂ¡lisis de la cualidad de la aglomeraciĂ³n y, si Ă©sta es mayor a 0.75, procederĂ¡ a curtar el dendrograma, y a visualizarlo.

fviz_dend(tagore_hcl, cex = 0.5)

Verifico la calidad de la aglomeraciĂ³n

tagore_coph <- cophenetic(tagore_hcl) 

cor(tagore1_dist, tagore_coph)
## [1] 0.8555866

El resultado anterior indica que el resultado de la aglomeraciĂ³n refleja la data de la distancia bastante bien. Corto entonces el dendrograma para encontrar el nĂºmero de cluster. Voy a pedir, al azar, sin ningĂºn criterio firme para esta decisiĂ³n, 6 grupos

tagore_grp <- cutree(tagore_hcl, k = 6)

# miembros de cada grupo

table(tagore_grp)
## tagore_grp
##  1  2  3  4  5  6 
## 92  4  2  1  1  1
tagore_grp <- cutree(tagore_hcl, k = 4)

# miembros de cada grupo

table(tagore_grp)
## tagore_grp
##  1  2  3  4 
## 92  7  1  1

Seis conglomerados construye muchos grupos con un sĂ³lo elemento, y dos con cuatro y tres elementos respectivamente. Por otra parte, cuatro conglomerados parece ofrecerme una mejor particiĂ³n. El resultado refleja lo que ya veĂ­a en el grafo textual: un enorme componente gigante, con algunos poemas que tienen un contenido muy particular. y por tanto, se separan de ese gran componente en el que los poemas comparten similitudes entre sus contenidos.

Voy a examinar los miembros de los grupos con menos elementos

# nombre de los miembros del grupo 2
rownames(tagore_wider_2)[tagore_grp == 2]
## [1] "27" "41" "47" "48" "52" "60" "64"
rownames(tagore_wider_2)[tagore_grp == 3]
## [1] "51"
rownames(tagore_wider_2)[tagore_grp == 4]
## [1] "77"

Los elementos que no estĂ¡n en estos tres grupos forman parte del conglomerado 1.

VisualizaciĂ³n

Con la funciĂ³n fviz_dend puedo obtener la visualizaciĂ³n. Esta funciĂ³n corre de manera automĂ¡tica un PCA si el nĂºmero de variables es mayor a 2, con lo cual se obtiene un nĂºmero reducido de dimensiones, con lo que se facilita tanto la visulizaciĂ³n como la interpretaciĂ³n

Preparo las paletas

turpial<- c("#1a1414", "#ba7212", "#6a2e0b","#963200", "#dfd7ca", "#707272",
            "#bcc4c1", "#dbd3ae")

treducido <- c("#2C0D1D", "#7B1F36", "#551126", "#601A3C",
              "#DD7898",  "#FBA6B9",  "#F6BDDD")

delLibro <- c("#2e9fdf", "#ddafbb", "#e7b800", "#fc4ed7")
fviz_dend(tagore_hcl,k = 4,
             k_colors =  delLibro,
          color_labels_by_k = TRUE,
              repel = TRUE, 
          rect = TRUE
)

visualizo como scatterplot

fviz_cluster( list(data = tagore_wider_2, cluster = tagore_grp),
             palette = delLibro,
              repel = TRUE, 
             ellipse.type = "convex",
             show.clust.cent = FALSE,
             ggtheme = theme_minimal()
)

VisualizaciĂ³n de los tĂ³picos de los clusters y las palabras que los separan

Creo un marco de datos con los clusters

dd<- data.frame(poema = names( tagore_grp),
                cluster = tagore_grp)
rownames(dd) <- NULL 
akore_tokensC<-dd %>% 
      inner_join(takore_tokens,
                 by=c("poema" = "poem_number"))
akore_tokensC %>% 
      filter(cluster == "1") %>% 
      count(palabras, sort = TRUE) %>% 
       mutate(prob = n/sum(n)) %>% 
      filter(prob >= 0.03) 
##   palabras   n       prob
## 1       de 409 0.04587773
## 2        y 330 0.03701626
## 3       la 289 0.03241727
## 4       en 281 0.03151991
akore_tokensC %>% 
      filter(cluster == "2") %>% 
      count(palabras, sort = TRUE) %>% 
       mutate(prob = n/sum(n)) %>% 
      filter(prob >= 0.03) 
##   palabras  n       prob
## 1       la 71 0.04528061
## 2       de 63 0.04017857
## 3        y 57 0.03635204
akore_tokensC %>% 
      filter(cluster == "3") %>% 
      count(palabras, sort = TRUE) %>% 
       mutate(prob = n/sum(n)) %>% 
      filter(prob >= 0.03) 
##   palabras  n       prob
## 1        y 17 0.06415094
## 2       el 15 0.05660377
## 3       de 11 0.04150943
## 4       la 11 0.04150943
## 5      las 10 0.03773585
## 6      que 10 0.03773585
akore_tokensC %>% 
      filter(cluster == "4") %>% 
      count(palabras, sort = TRUE) %>% 
       mutate(prob = n/sum(n)) %>% 
      filter(prob >= 0.03) 
##   palabras n       prob
## 1       mi 6 0.05128205
## 2       no 6 0.05128205
## 3     como 5 0.04273504
## 4        y 5 0.04273504
## 5        a 4 0.03418803
## 6       me 4 0.03418803
## 7       te 4 0.03418803
load("D:/funcionesSentimientos.RData")
akore_tokensC %>% 
      filter(cluster == "1", 
             !palabras %in% lex$palabras) %>% 
      count(palabras, sort = TRUE)%>% 
  with(wordcloud(palabras, n, 
               random.order = FALSE,random.color = FALSE,
               color=brewer.pal(8, "Dark2")))

akore_tokensC %>% 
      filter(cluster == "2", 
             !palabras %in% lex$palabras) %>% 
      count(palabras, sort = TRUE)%>% 
  with(wordcloud(palabras, n, 
               random.order = FALSE,random.color = FALSE,
               color=brewer.pal(8, "Dark2")))

akore_tokensC %>% 
      filter(cluster == "3", 
             !palabras %in% lex$palabras) %>% 
      count(palabras, sort = TRUE)%>% 
  with(wordcloud(palabras, n, 
               random.order = FALSE,random.color = FALSE,
               color=brewer.pal(8, "Dark2")))

akore_tokensC %>% 
      filter(cluster == "4", 
             !palabras %in% lex$palabras) %>% 
      count(palabras, sort = TRUE)%>% 
  with(wordcloud(palabras, n, 
               random.order = FALSE,random.color = FALSE,
               color=brewer.pal(8, "Dark2")))

Comentarios

Entradas mĂ¡s populares de este blog

Venezuela. Entidades federales segĂºn nĂºmero de municipios

Cluster jerĂ¡rquico