Para llevar a cabo el caso de uso es necesario cargar los siguientes paquetes:
A continuación, encontrarán el código de R para el cargue de los paquetes, es una buena práctica comentar al lado de los paquetes para recordar fácilmente porque los estamos cargando.
#Cargue de paquetes
library(tidytext) #Análisis de datos textuales
library(ggplot2) #Graficas
library(wordcloud2) #Graficas datos textuales
library(tidyr) #Procemsamiento
library(igraph)#grafico de redes
library(ggraph)#grafico de redes
library("udpipe") #toquenización y diccionarios en español
library(stringr) #Manejo de cadenas de texto expresiones regulares
library(dplyr) #Procemsamiento
library(readxl) #Cargar archivos excel
library(readr) #Cargar archios csvAunque es posible hacer realizar la conexión de R a twitter directamente, para agilizar el desarrollo del curso obviaremos esta parte y cargaremos los datos de un archivo .csv, esta conexión será realizada más adelante a través de qlik, software en el cual el procedimiento se simplifica.
Si usted desea conocer el procedimiento para la conexión desde R puede consultar el siguiente tutorial: https://rpubs.com/Joaquin_AR/334526
El código que encuentra a continuación corresponde a la importación de una base de datos en formato .csv que contiene información de tweets, entre ella el texto correspondiente, el cual guardaremos en la variable texto
tweets <- read_delim("C:/Users/User/Downloads/TManar.csv",
"|", escape_double = FALSE, trim_ws = TRUE)
texto=tweets$UserTimeline_textLa limpieza del texto es un proceso fundamental en la minería de texto, consiste en estandarizar el texto y eliminar de él todo lo que no aporte información útil para la temática que queremos tratar. Este proceso no es único y depende de las necesidades del investigador, a continuación, encontrará algunos de los procesos de limpieza más comunes:
# El orden de la limpieza no es arbitrario
# Se convierte todo el texto a minúsculas
nuevo_texto <- tolower(texto) # Eliminación de páginas web (palabras que empiezan por "http." seguidas
# de cualquier cosa que no sea un espacio "\\S*")
nuevo_texto <- str_replace_all(nuevo_texto,"http\\S*", "") # Elimiinacion de emoticones
nuevo_texto <- iconv(nuevo_texto,"UTF-8", sub="") # Eliminación de signos de puntuación
nuevo_texto <- str_replace_all(nuevo_texto,"[[:punct:]]", " ")
# Eliminación de números
nuevo_texto <- str_replace_all(nuevo_texto,"[[:digit:]]", " ") # Eliminación de espacios en blanco múltiples
nuevo_texto <- str_replace_all(nuevo_texto,"[\\s]+", " ") # Eliminación de saltos de línea
nuevo_texto <- str_replace_all(nuevo_texto,"\n", " ") # Eliminación espacios al inicio de las cadenas
nuevo_texto <- trimws(x = nuevo_texto)A continuación, crearemos un diccionario con lo que en el análisis textual llamamos Stop words o palabras vacías, este diccionario contiene artículos, preposiciones, pronombres, etc., en general, palabras que no aportan información relevante sobre el texto.
Hay diferentes diccionarios de palabras, en este caso usaremos el diccionario para el idioma español del paquete tm.
Guardaremos este diccionario en la variable custom_stop_words, lo usaremos más adelante para excluir esta palabras del análisis.
custom_stop_words <- data_frame(word = c(tm::stopwords("spanish")),
lexicon = "spanish")# A tibble: 6 x 2
word lexicon
<chr> <chr>
1 de spanish
2 la spanish
3 que spanish
4 el spanish
5 en spanish
6 y spanish
La tokenización es un proceso que consiste en dividir el texto en las unidades que deseamos analizar, para esta primera parte analizaremos las palabras individuales, la tokenización la haremos con la función unnest_tokens
text_df <- data.frame(line = 1:length(nuevo_texto), text = nuevo_texto)
text_df_pre <- text_df %>%
unnest_tokens(word, text, token = "words") line word
1 1 acompáñenos
2 1 a
3 1 partir
4 1 de
5 1 hoy
6 1 a
En las siguientes líneas de código se eliminan las palabras vacías haciendo uso del diccionario que guardamos.
text_df_pre <- text_df_pre %>%
anti_join(custom_stop_words) line word
1 1 acompáñenos
2 1 partir
3 1 hoy
4 1 conocer
5 1 tendencias
6 1 manera
A la hora de entender las características del texto es interesenta estudiar la frecuencia con la que se emplean las palabras,
text_df_pre <- text_df_pre %>%
count(word, sort = TRUE) word n
1 qlik 911
2 datos 507
3 qlikview 285
4 cómo 276
5 descubre 205
6 bi 160
text_df_pre %>%
filter(n > 100) %>%
mutate(word = reorder(word, n)) %>%
ggplot(aes(word, n)) +
geom_col() +
xlab(NULL) +
coord_flip()wordcloud2(text_df_pre %>% filter(n>50))Hasta este momento hemos considerado las palabras como unidades individuales. Sin embargo, es interesante ver la relación entre las palabras, estudiando que palabras siguen a otras.
En el ejercicio anterior usamos la función unnest_tokens para tokenizar por palabras, lo cual es útil para los análisis de frecuencias de palabras individuales. Pero también podemos usar la función para tokenizar en secuencias consecutivas de palabras, llamadas n-grams. Al ver la frecuencia con la que la palabra X va seguida de la palabra Y, podemos construir un modelo de las relaciones entre ellas.
pares=tibble(txt = nuevo_texto)
austen_bigrams <- pares %>%
unnest_tokens(bigram,txt, token = "ngrams",n=2)
austen_bigrams# A tibble: 34,021 x 1
bigram
<chr>
1 acompáñenos a
2 a partir
3 partir de
4 de hoy
5 hoy a
6 a conocer
7 conocer las
8 las tendencias
9 tendencias en
10 en la
# ... with 34,011 more rows
Examinando el resultado por medio de un conteo vemos que, como era de esperar, muchos de los pares de palabras más comunes son poco interesantes y podrían considerarse “palabras vacías”.
austen_bigrams %>%
count(bigram, sort = TRUE)# A tibble: 16,321 x 2
bigram n
<chr> <int>
1 de datos 197
2 de la 192
3 de qlik 185
4 en el 159
5 de los 148
6 los datos 148
7 qlik sense 135
8 en la 133
9 con qlik 88
10 de las 86
# ... with 16,311 more rows
Separaremos los pares de palabras para que cada uno quede en una columna: “Word1” y “Word2”, una vez realizada esta división podremos eliminar los casos en los que encontremos stopwords.
#Separamos los pares de palabras
bigrams_separated <- austen_bigrams %>%
separate(bigram, c("word1", "word2"), sep = " ") #función de tidyr
#quitamos los stop words
bigrams_filtered <- bigrams_separated %>%
filter(!word1 %in% custom_stop_words$word) %>%
filter(!word2 %in% custom_stop_words$word)
#Contamos
bigram_counts <- bigrams_filtered %>%
count(word1, word2, sort = TRUE)
bigram_counts# A tibble: 5,463 x 3
word1 word2 n
<chr> <chr> <int>
1 qlik sense 135
2 big data 72
3 descubre cómo 63
4 <NA> <NA> 53
5 qlik ayuda 44
6 cómo qlik 43
7 tiempo real 37
8 manar technologies 28
9 sense cloud 25
10 descubra cómo 21
# ... with 5,453 more rows
#Unimos los pares de palabras
bigrams_united <- bigrams_filtered %>%
unite(bigram, word1, word2, sep = " ")
#Realizamos un conteo de los pares de palabras unidas
conteo=bigrams_united %>%
count(bigram, sort = TRUE)
#Graficamos
conteo %>%
filter(n >= 15) %>%
mutate(bigram = reorder(bigram, n)) %>%
ggplot(aes(bigram, n)) +
geom_col() +
xlab(NULL) +
coord_flip()Podemos organizar las palabras en una red o “gráfico”. Aquí nos referiremos a un “gráfico” no en el sentido de una visualización, sino como una combinación de nodos conectados. Se puede construir un gráfico a partir de un objeto ordenado ya que tiene tres variables:
El paquete igraph tiene muchas funciones poderosas para manipular y analizar redes. Una forma de crear un objeto igraph a partir de datos ordenados es la función graph_from_data_frame(), que toma un marco de datos con columnas para los atributos “desde”, “hasta” y “pesos” (en este caso n):
#creamos el objeto redefilico
bigram_graph <- bigram_counts %>%
filter(n >=15) %>%
graph_from_data_frame()
bigram_graphIGRAPH e989596 DN-- 29 20 --
+ attr: name (v/c), n (e/n)
+ edges from e989596 (vertex names):
[1] qlik ->sense big ->data
[3] descubre ->cómo NA ->NA
[5] qlik ->ayuda cómo ->qlik
[7] tiempo ->real manar ->technologies
[9] sense ->cloud descubra ->cómo
[11] mike ->tarallo mejores ->decisiones
[13] tomar ->decisiones business ->intelligence
[15] utiliza ->qlik leadwithdata->bi
+ ... omitted several edges
#Realizamos el grafico de redes
set.seed(2017)
ggraph(bigram_graph, layout = "fr") +
geom_edge_link() +
geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1)