Analisis de texto en R

Concepto:

El análisis de texto en R se refiere al procesamiento y análisis de datos de texto el cual consiste en aplicar técnicas y algoritmos para extraer información, patrones y conocimientos útiles de documentos de texto, ya sea en forma de texto plano, comentarios de usuarios, artículos de noticias, entre otros.

1. Crear el data grame

## Warning: package 'tidyverse' was built under R version 4.3.1
## Warning: package 'ggplot2' was built under R version 4.3.1
## Warning: package 'tibble' was built under R version 4.3.1
## Warning: package 'tidyr' was built under R version 4.3.1
## Warning: package 'readr' was built under R version 4.3.1
## Warning: package 'purrr' was built under R version 4.3.1
## Warning: package 'dplyr' was built under R version 4.3.1
## Warning: package 'stringr' was built under R version 4.3.1
## Warning: package 'forcats' was built under R version 4.3.1
## Warning: package 'lubridate' was built under R version 4.3.1
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.2     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.2     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.1     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
## Warning: package 'tidytext' was built under R version 4.3.1
## Warning: package 'tm' was built under R version 4.3.1
## Loading required package: NLP
## 
## Attaching package: 'NLP'
## 
## The following object is masked from 'package:ggplot2':
## 
##     annotate
## Warning: package 'wordcloud' was built under R version 4.3.1
## Loading required package: RColorBrewer

Crear un dataframe con textos, ya sean de revistas, periocicos, noticias, en nuestro caso fueron las letras de la cancion No hay pesos de los cantantes y Me tengo que ir de los adolecentes, para poder analisar estos textos.

#Creamos el data frame
library(readxl)
## Warning: package 'readxl' was built under R version 4.3.1
letra <- read_excel("Letra.xlsx")
View(letra)

2. Divido los textos en palabras

Para poder analizar las letras de estas canciones necesitamos dividirlas entre palabras, esto lo hacemos mediante la funcion unnest_tokes()

#Ponemos la libreria
library(dplyr)

#Creamos un data nuevo con las palabras divididas

letra.dividida <- letra %>%
  unnest_tokens(palabras, Letra)  # Divide las letras en palabras individuales

#Visualizamos 
View(letra.dividida)

3.Conteo de palabras (word counts)

Despues de hacer esto hacemos un conteo de las palabras ma frecuentes, pero vemos que las mas freceuntes son aquellas como, y que, en, lo, que en analisis son llamadas palabras vacias, que no nos ayudan en la parte de analizar nuestros textos, entonces para poder tener un buen analicis, vamos a eliminar estas palabras vacias, mediante la funcion anti.join () y el diccionario stop_words.

#Conteo de palabras (word counts)

count_palabras <- letra.dividida %>%
  count(palabras, sort = TRUE)

View(count_palabras)

4. Eliminar palabras vacías (stop words)

Como estamos trabajando con palabras en español, y nuestro diccionario de stop_words esta en ingles, lo que podemos hacer es crear una lista de palabras vacias en español, el cual este data frame haga el mismo trabajo que nuestro diccionario stop_words y nos elimine estas palabras.

#Eliminar palabras vacías (stop words)

#Creamos un data frame con palabras vacias para poder borrar estas
library(readxl)
Palabras_Vacias <- read_excel("Palabras Vacias.xlsx")
View(Palabras_Vacias)

Despues de hacer esto ahora si, podemos eliminar estas palabras y visualizar nuestro data con palabras mas significativas.

# Realizar la eliminación de palabras vacías
letra.dividida <- letra.dividida %>%
  anti_join(Palabras_Vacias, by = c("palabras" = "palabras"))
letra.dividida %>%
  count(palabras, sort = TRUE)
## # A tibble: 77 × 2
##    palabras     n
##    <chr>    <int>
##  1 amor        12
##  2 corazón      9
##  3 alma         7
##  4 contar       5
##  5 pesos        5
##  6 puro         5
##  7 quiero       5
##  8 verdad       5
##  9 bolsillo     4
## 10 bueno        4
## # ℹ 67 more rows
# Ver el resultado
View(letra.dividida)

5. Visualización de palabras más frecuentes

Luego hacemos una visualizacion de las palabras mas frecuentes de nuestro data frame y lo ponemos en un ggplot

# Obtener las palabras más frecuentes
palabras_frecuentes <- letra.dividida %>%
  count(palabras, sort = TRUE) %>%
  filter(n > 2)

# Crear el gráfico de barras
grafico <- ggplot(palabras_frecuentes, aes(x = reorder(palabras, n), y = n)) +
  geom_col(fill = "#98FF98") +
  labs(x = "Palabra", y = "Frecuencia") +
  ggtitle("Palabras más frecuentes") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5))

# Mostrar el gráfico en una ventana gráfica
plot(grafico)

6. Análisis de sentimientos

¿Cómo podemos profundizar en el análisis del contenido de las canciones con R? Una técnica interesante para aplicar aquí es el análisis de sentimientos. Esto se puede hacer sistemáticamente con el paquete gracias a la función, que proporciona 4 léxicos de sentimiento diferentes que se pueden aplicar a nuestros datos con un simple tidytext, get_sentiments() y inner_join

Como nuestras lecciones estan en ingles, y nuestras palabras en espeñol, lo que se hizo fue crear un data frame en el cual estuvieran las traducciones de nuestras palabras, y añadirlas a nuestra base de datos para poder facilitar el proceso y trabajar mejor nuestas lecciones o diccionarios de sentimientos.

#Creamos un data frame con las palabras en ingles 
library(readxl)
word <- read_excel("word.xlsx")
View(word)

#Y se hañade en nuestro data frame de letra.dividida para poder trabajar con ellas
letra.dividida <- letra.dividida %>%
  mutate(word = word$word)
View(letra.dividida)

Hacemos el analisis de sentimiento

#install.packages("textdata")
library(textdata)
## Warning: package 'textdata' was built under R version 4.3.1
#Análisis de sentimientos 
letra.dividida <- letra.dividida %>%
  inner_join(get_sentiments("bing"))
## Joining with `by = join_by(word)`
View(letra.dividida)

Ahora que tenemos los datos como queremos, podemos ir y hacer un buen gráfico de bares de sentimientos. Pero para esto necesitamos un conteo de los sentimeintos.

#Contamos los sentimientos positivos y negativos de cada cancion 

Conteo_canciones <- letra.dividida %>%
  inner_join(get_sentiments("bing")) %>%
  count(Cancion, Autor, sentiment, name = "conteo")
## Joining with `by = join_by(word, sentiment)`
View(Conteo_canciones)

7. Para ver que canciones son negativas y negativas hacemos un plot

#primero hicimos una separacion por cada sentimiento y por cada cancion 
canciones<- letra.dividida %>%
  inner_join(get_sentiments("bing")) %>%
  count(Cancion, Autor, sentiment) %>%
  spread(sentiment, n, fill = 0) %>%
  mutate(sentiment = positive + negative ) %>%
  arrange(desc(sentiment))
## Joining with `by = join_by(word, sentiment)`
View(canciones)

Realizamos el plot:

library(ggplot2)

# Crear la gráfica de barras
grafica_barras <- ggplot(data = canciones, aes(x = Cancion, y = sentiment, fill = sentiment)) +
  geom_bar(stat = "identity") +
  labs(x = "Canción", y = "Sentiment") +
  ggtitle("Gráfica de Barras de Sentiment por Canción") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Mostrar la gráfica
print(grafica_barras)

library(ggplot2)

Y podemos ver que en una cancion hay mas sentimientos que en las otras, podemos notar que hay mas palabras vacias en Me tengo que ir que en No hay pesos, por esto disminuyen las palabras significativas y encontramos menos sentimientos en la cancion.

8. Dibujar un mapa de red de las canciones

¿y si quisiéramos hacer una última cosa, digamos… ¿Un mapa de red de cómo se relacionan las canciones entre sí? Hacemos este mapa con el fin de ver que tan relacionada entan las palabras entre las cancion.

library(igraph)
## Warning: package 'igraph' was built under R version 4.3.1
## 
## Attaching package: 'igraph'
## The following objects are masked from 'package:lubridate':
## 
##     %--%, union
## The following objects are masked from 'package:dplyr':
## 
##     as_data_frame, groups, union
## The following objects are masked from 'package:purrr':
## 
##     compose, simplify
## The following object is masked from 'package:tidyr':
## 
##     crossing
## The following object is masked from 'package:tibble':
## 
##     as_data_frame
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union
library(tidyverse)

# Calcular la matriz de co-ocurrencia de palabras
co_ocurrencia <- letra.dividida %>%
  group_by(Cancion, palabras) %>%
  count() %>%
  filter(n > 1)

# Crear la red de co-ocurrencia
red <- graph_from_data_frame(co_ocurrencia, directed = FALSE)

# Ajustar los tamaños de los nodos según su grado (número de conexiones)
tamano_nodos <- degree(red) * 5  # Puedes ajustar el factor multiplicativo según tus preferencias

# Ajustar los colores de los nodos según la canción
colores <- as.factor(letra.dividida$Cancion)

# Visualizar el mapa de red
plot(red, vertex.size = tamano_nodos, vertex.color = colores)

Con este mapa nos podemos dar una idea de que la letra de las canciones no tiene una relacion entre si, podemos analizar que aunque nosotros escuchemos su ritmo, su melodio y nos parescan igual, en terminos de palabras y letra son totalmente distintas.

9. correlacion entre canciones

Para finalizar hacemos un correlacion para poder ver con exactitud como estan relacionadas o no, esto lo hacemos mediante la funcion de widyr::pairwise_cor

#install.packages("widyr")
library(widyr)
## Warning: package 'widyr' was built under R version 4.3.1
library(readxl)

limpia_cors <- letra.dividida %>%
  widyr::pairwise_cor(Cancion,word,sort=TRUE)
limpia_cors
## # A tibble: 2 × 3
##   item1           item2           correlation
##   <chr>           <chr>                 <dbl>
## 1 Me tengo que ir No hay pesos         -0.892
## 2 No hay pesos    Me tengo que ir      -0.892