Clase 31 - Introducción a la Minería de Texto

logo

1 Lectura de datos

Para la realización de esta actividad usaremos las siguientes bibliotecas:

  library("rwhatsapp")
  library("dplyr")
  library("ggplot2")
  library("lubridate")
  library("tidyr")
  library("ggimage")
  library("tidytext")
  library("stopwords")
  library("plotly")

La lectura de los datos se hará con el siguiente comando. Mensajes sin usuarios serán removidos:

## Cargar los datos
chat = rwa_read("WAppDiinf.txt")                       # Lectura
chat = filter(chat, !is.na(author))                    # Remover mensajes sin autor

print(levels(chat$author))
##  [1] "+1 (403) 990-5727" "+56 9 5895 4518"   "+56 9 6845 6981"  
##  [4] "+56 9 7686 7402"   "+56 9 8234 9110"   "+56 9 8286 1145"  
##  [7] "+56 9 8736 1782"   "+56 9 9231 6070"   "+56 9 9333 9553"  
## [10] "+56 9 9365 6879"   "+56 9 9879 4998"   "+56 9 9918 1562"  
## [13] "Cristobal Acosta"  "Diego Caro"        "Felipe Bello"     
## [16] "José Luis Jara"    "Leo Medina"        "Manuel Villalobos"
## [19] "Mario Inostroza"   "Maurício Marin"    "Max Chacón"       
## [22] "Pablo Roman"       "Roberto González"
chat=filter(chat, (author=="Roberto González") | (author=="Mario Inostroza") | (author=="Leo Medina") | 
              (author=="Maurício Marin") | (author=="Max Chacón") | (author=="Diego Caro") | (author=="José Luis Jara") |
              (author=="Felipe Bello") | (author=="Cristobal Acosta") | (author=="Pablo Roman") | 
                 (author=="Manuel Villalobos"))

## Ver los datos
knitr::kable(head(chat,n = 5))
time author text source id emoji emoji_name
2019-10-20 16:53:37 Cristobal Acosta Todo bien por acá WAppDiinf.txt 6 NULL NULL
2019-10-20 17:46:37 Leo Medina Grande Gonzalo! WAppDiinf.txt 35 NULL NULL
2019-10-20 18:31:37 Roberto González Array suspendido WAppDiinf.txt 38 NULL NULL
2019-10-20 18:31:37 Roberto González Proximamente se viene comunicado :( WAppDiinf.txt 39 NULL NULL
2019-10-20 18:32:37 Pablo Roman Por mi lado estamos bien. WAppDiinf.txt 40 NULL NULL

2 Registro de actividades

El siguiente gráfico muestra la actividad del grupo en el tiempo:

theme_set(theme_minimal())
chat =  mutate(chat,day = date(time)) 
chat = mutate(chat,date = format(as.Date(chat$time),"%Y/%m"))
freq = count(chat,date)
grafico = ggplot(freq,aes(x = date, y = n)) +
  geom_bar(stat = "identity") +
  ylab("") + xlab("") + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
  ggtitle("Registro de Actividades") 
ggplotly(grafico)

3 Actividad por usuario

La actividad por usuario es la siguiente:

chat =  mutate(chat,day = date(time)) 
frec = count(chat,author)
grafico = ggplot(frec,aes(x = reorder(author, n), y = n)) +
  geom_bar(stat = "identity") +
  ylab("") + xlab("") +
  coord_flip() +
  ggtitle("Cantidad de Mensajes")
ggplotly(grafico)

4 Uso de emojis

¿Usarán emojis los académicos de este grupo del Diinf? Estos son los 5 emojis más usados por los académicos:

  frec=unnest(chat,emoji)
  frec=count(frec,author, emoji, sort = TRUE)
  frec=dplyr::group_by(frec,author)
  frec=top_n(frec,n = 5, n)
  grafico=ggplot(frec,aes(x = reorder(emoji, n), y = n, fill = author)) +
    geom_col(show.legend = FALSE) +
    ylab("") +
    xlab("") +
    coord_flip() +
    facet_wrap(~author, ncol = 4, scales = "free_y")  +
    ggtitle("Emojis más utilizados")
ggplotly(grafico)

5 Palabras más utilizadas

Sin aplicar ningún filtro en el texto, las palabras más utilizadas por los académicos son:

frec=unnest_tokens(chat,input = text,
              output = word)
frec=count(frec,author, word, sort = TRUE)
frec=group_by(frec,author)
frec= top_n(frec,n = 5, n) 
grafico=ggplot(frec,aes(x = reorder_within(word, n, author), y = n, fill = author)) +
  geom_col(show.legend = FALSE) +
  ylab("") +
  xlab("") +
  coord_flip() +
  facet_wrap(~author, ncol = 4, scales = "free_y") +
  scale_x_reordered() +
  ggtitle("Palabras más utilizadas")
ggplotly(grafico)

Como ven, hay palabras que se repiten que no tienen relevancia. Estas serán eliminadas:

## Palabras para remover
no_relevantes = c(tm::stopwords("es"),"omitido","https","multimedia","twitter.com","status","youtube","video",
                   "tambien","www.ncbi.nlm.nih.gov")

Ahora repetiremos la actividad:

frec=unnest_tokens(chat,input = text,
              output = word)
frec=filter(frec,!word %in% no_relevantes)        #Aplicación de filtro
frec=frec[which(nchar(frec$word)>3),]             #Palabras con más de 3 letras
frec=count(frec,author, word, sort = TRUE)
frec=group_by(frec,author)
frec= top_n(frec,n = 5, n) 
grafico=ggplot(frec,aes(x = reorder_within(word, n, author), y = n, fill = author)) +
  geom_col(show.legend = FALSE) +
  ylab("") +
  xlab("") +
  coord_flip() +
  facet_wrap(~author, ncol = 4, scales = "free_y") +
  scale_x_reordered() +
  ggtitle("Palabras más utilizadas")
ggplotly(grafico)

¿Cómo se reirá la gente del Diinf?

frec=unnest_tokens(chat,input = text,
              output = word)
frec=filter(frec,!word %in% no_relevantes)        #Aplicación de filtro
idx=which(grepl("jaja", frec$word, fixed = TRUE)=="TRUE")
idx=c(idx,which(grepl("haha", frec$word, fixed = TRUE)=="TRUE"))
idx=c(idx,which(grepl("ajj", frec$word, fixed = TRUE)=="TRUE"))
idx=c(idx,which(grepl("ahah", frec$word, fixed = TRUE)=="TRUE"))
frec=frec[idx,]
frec=count(frec,author, word, sort = TRUE)
frec=group_by(frec,author)
frec= top_n(frec,n = 5, n) 
grafico=ggplot(frec,aes(x = reorder_within(word, n, author), y = n, fill = author)) +
  geom_col(show.legend = FALSE) +
  ylab("") +
  xlab("") +
  coord_flip() +
  facet_wrap(~author, ncol = 4, scales = "free_y") +
  scale_x_reordered() +
  ggtitle("Palabras más utilizadas")
ggplotly(grafico)

6 Diversidad léxica

La diversidad léxica de los académicos es la siguiente.

frec=unnest_tokens(chat,input = text,
              output = word)
frec=filter(frec,!word %in% no_relevantes)        #Aplicación de filtro
frec=group_by(frec,author)
frec=summarise(frec,lex_diversity = n_distinct(word))
frec=arrange(frec,desc(lex_diversity))
grafico=ggplot(frec,aes(x = reorder(author, lex_diversity),
             y = lex_diversity,
             fill = author)) +
    geom_col(show.legend = FALSE) +
    scale_y_continuous(expand = (mult = c(0, 0, 0, 10000))) +
    geom_text(aes(label = scales::comma(lex_diversity)), hjust = -0.3) +
    ylab("Palabras únicas") +
    xlab("") +
    ggtitle("Diversidad Léxica") +
    coord_flip()
ggplotly(grafico)

7 Wordcloud

Para generar la nube de palabras consideraremos las siguientes bibiotecas:

  library("tm")
  library("SnowballC")
  library("wordcloud")
  library("RColorBrewer")
  library("stringr")
  library("caret")
  library("dplyr")

El procesamiento del texto es el siguiente:

frec=unnest_tokens(chat,input = text,
               output = word)
frec=filter(frec,!word %in% no_relevantes)        #Aplicación de filtro
frec=frec[which(nchar(frec$word)>3),]             #Palabras con más de 3 letras

corpus = Corpus(VectorSource(frec$word)) # formato de texto

## Transformación del Texto

  # lleva a minúsculas
texto = tm_map(corpus, tolower)

  # quita espacios en blanco
texto = tm_map(corpus, stripWhitespace)

# quita la puntuación
texto = tm_map(texto, removePunctuation)

# quita los números
texto = tm_map(texto, removeNumbers)

# remueve palabras vacías genericas

texto = tm_map(texto, removeWords, no_relevantes)

# crea matriz de términos
tdm = TermDocumentMatrix(texto)

Creación de nube de palabras

# lo vuelve una matriz
matriz = as.matrix(tdm)

# lo ordena y suma
v = sort(rowSums(matriz),decreasing=TRUE)

# lo nombra y le da formato de data.frame
df = data.frame(word = names(v),freq=v)

### Trazar frecuencia de palabras
barplot(df[1:10,]$freq,
        las = 2,
        names.arg = df[1:10,]$word,
        col ="lightblue",
        main ="Palabras más frecuentes",
        ylab = "Frecuencia de palabras")

## Nube de Palabras
wordcloud(words = df$word,
          freq = df$freq,
          min.freq = 6,
          max.words=100,
          random.order=FALSE,
          rot.per=0.35,
          colors=brewer.pal(8, "Dark2"))

8 Análisis de Sentimientos (básico)

Primero definiremos un tema para los gráficos.

library("purrr")

tema_graf =
  theme_minimal() +
  theme(text = element_text(family = "serif"),
        panel.grid.minor = element_blank(),
        strip.background = element_rect(fill = "#EBEBEB", colour = NA),
        legend.position = "none",
        legend.box.background = element_rect(fill = "#EBEBEB", colour = NA))

Luego, ordenaremos los datos y emplearemos un diccionario de puntuación de sentimientos.

frec=unnest_tokens(chat,input = text,
               output = word)
frec=filter(frec,!word %in% no_relevantes)        #Aplicación de filtro
frec=frec[which(nchar(frec$word)>3),]             #Palabras con más de 3 letras

afinn = read.csv("lexico_sentimientos.csv",sep=";",header=T,
                 encoding ="UTF-8",check.names = F)
afinn = data.frame(afinn)
colnames(afinn)=c("word","score","ingles")

frec=merge(frec,afinn,by = "word")
frec$emoji=NULL
frec$emoji_name=NULL

frec= mutate(frec,Tipo = ifelse(score > 0, "Positiva", "Negativa"))
frec=mutate(frec,score = ifelse(is.na(score), 0, score)) #Ocultamos palabras que no tienen puntaje

#Positivo
sentimiento = "Positiva"
  frec2 = filter(frec,Tipo ==  sentimiento)
  frec2=group_by(frec2,author) 
  frec2=count(frec2,word, sort = T) 
  frec2=top_n(frec2,n = 10, wt = n) 
  grafico=ggplot(frec2) +
    aes(word, n, fill = author) +
    geom_col() +
    facet_wrap("author", ncol = 2, scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = sentimiento) + tema_graf
  ggplotly(grafico)
#Negativa
sentimiento = "Negativa"
  frec2 = filter(frec,Tipo ==  sentimiento)
  frec2=group_by(frec2,author) 
  frec2=count(frec2,word, sort = T) 
  frec2=top_n(frec2,n = 10, wt = n) 
  grafico=ggplot(frec2) +
    aes(word, n, fill = author) +
    geom_col() +
    facet_wrap("author", ncol = 2, scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = sentimiento) + tema_graf
  ggplotly(grafico)

Más detalles pueden ser encontrados en este link.