Lectura distante y minería de corpus textuales con R

Romina De León

rdeleon@conicet.gov.ar

¿Qué es R?

R es un entorno de software libre (licencia GNU GLP), como lenguaje de programación interpretado, ejecuta las instrucciones directamente; además es gratuito y amigable de instalar y para trabajar, es muy utilizado para análisis estadístico y gráfica computacional.

Por su parte, R Studio es un entorno de desarrollo integrado para R, que cuenta con una consola, un editor de sintaxis para la ejecución de código, herramientas para el trazado, depuración y gestión del espacio de trabajo.

Ahora que ya sabemos de que se trata, comencemos con las instalaciones.

Instalaciones previas

¿Cómo instalar R y R Studio?

Instalación de R

Rlogo
Rlogo

En este primer paso comenzaremos con la instalación del lenguaje R, vale aclarar que en cualquier sistema operativo es igual, aunque se trate de Windows, macOS e incluso Linux. Como ya mencionamos es de descarga gratuita y fácil instalación. Lo que necesitaremos en una conexión a internet y unos pocos minutos.

La mejor manera de instalar R es descargándolo de los servidores de The Comprehensive R Archive Network (CRAN) que almacena y conserva todas las versiones, así como todas las librerías que se publican, de ellas hablaremos en breve.

Sistemas Operativos:

Windows

Debes ingresar a https://cran.r-project.org/bin/windows/base/ que te permitirá acceder al archivo Download R 4.1.0 for Windows (los números pueden variar según nuevas actualizaciones), una vez descargado, solo tienes que instalarlo como con cualquier otro programa de Windows.

Mac OS

Debes ingresar a https://cran.rproject.org/bin/macosx/, deberás dirigirte hasta la parte inferior izquierda donde aparecerá un enlace que diga R‐4.0.0.pkg (los dos últimos números pueden cambiar ligeramente, pues la actualización es constante). Hacé clic en el enlace y se inicirá la descarga del instalador en tu computadora. Al finalizar procede como lo harías con otro programa para Mac.

Linux

Debes ingresar a https://cran.r-project.org/bin/linux/ y seleccionar tu distribución, y dependiendo de ella podrás continuar los pasos que figuran para realizar la intalación.

Atención: Es importante que primero se realice la instalación de R y luego de RStudio

Instalación de R Studio

Ahora instalaremos R Studio, que puedes descargarlo desde este enlace para cualquier sistema operativo, deberás proceder como cualquier otro programa para tu computadora.

Vista del entorno de R Studio
Vista del entorno de R Studio

Interfaz de usuario

A continuación, puedes observar las partes en la que se encuentra dividida la interfaz de R Studio.

  1. Consola, puedes realizar diferentes cálculos y operaciones matemáticas, sería la ventana básica de R.

  2. Entorno de variables, muestra el historial, conjunto de datos y objetos (resultados, variables, gráficos, etc.) almacenados durante la ejecución de diferentes análisis.

  3. Editor de código, script, desde este panel puedes editar la sintaxis de un script para luego ejecutarla. Cuando realices cambios, no sucederá nada a menos que ejecutes los comandos, con la barra de herramientas que contiene el panel o al combinar las teclas ctrl+enter

  4. Utilidades, dentro de este panel se encuentran diversas subpestañas:

    1. files, verás el historial de archivos trabajados;

    2. plots, podrás visualizar los gráficos que se generen;

    3. packages, encuentras los paquetes, instalados, descargados y guardados en tu disco duro, puedes gestionar su instalación o actualización;

    4. help, puedes ingresar a la página oficial donde podrás acceder a diferentes recursos para el programa, como manuales, cursos, información general, descarga de paquetes, información de los paquetes instalados, etc.;

    5. viewer, muestra los resultados de reportes o análisis.

¿Cómo instalar librerías?

Las librerías o paquetes en R son una serie de funciones y conjunto de datos desarrollados por la comunidad; estos incrementan la capacidad de R mejorando sus funcionalidades básicas.

Ahora veremos como instalarlas, abre RStudio, allí tendrás dos opciones:

  • Seleccionar desde Packages, donde podrás buscar, seleccionar e instalar las librerías necesarias

  • En la parte Consola, si deseas instalar varias librerías al mismo tiempo, puedes escribir

    install.packages(c("tidyverse","tidytext","ggraph","RCurl","ggplot"))
  • Si deseas instalar una única librería debes escribir

    install.packages("tidyverse")

De esa manera podrás instalar las librerías que necesites. Cualquier duda puedes consultar en Librerías en R.

Conocimientos básicos en R Studio

Cómo ejecutar comandos u órdenes

Con R y Rstudio instalados comenzaremos por darles unos primeros comandos que serán útiles para llevar adelante un trabajo ordenado en las próximas entradas.

Aclaración: A partir de ahora todo lo que hagamos será en RStudio.

En RStudio las órdenes las podemos escribir y ejecutar de varias formas:

  • Directamente en la consola

  • Por medio de un script (.R)

  • Abriendo ficheros Rmarkdown (.Rmd)

Como ejecutar un comando desde la Consola

Para ello, escribiremos en la línea de comando la orden que queremos que R Studio realice. Veamos cómo hacerlo situándonos en un directorio.

Limpieza del entorno de trabajo

Siempre es recomendable iniciar un nuevo script o trabajo desde terminal, con el siguiente comando, para asegurarnos que el entorno se encuentra limpio y que hemos eliminado los objetos antes definidos:

rm(list=ls())
Directorio de trabajo

El directorio de trabajo será la carpeta que utilizaremos para almacenar los archivos con los que trabajamos en R. Puede obtener en que carpeta te encuentras trabajando con:

getwd()
Establecer la ruta del directorio
setwd("C:/Mi/Ruta")

#Forma equivalente, en ocasiones en Windows debes utilizar comillas simples

setwd("Mi/Ruta")

Otro comando útil es el que permitirá conocer el contenido del directorio

Lista los archivos del directorio
list.files()
Lista los directorios dentro del directorio de trabajo
list.dirs()

Nuevo script

Un script es un tipo de archivo que será guardado como texto donde escribes instrucciones o comandos que deseas que el software haga. Al tratarse de un lenguaje de programación, los script guardarán código que se puede ejecutar. Estos documentos tienen la extensión de archivo .R, serán útiles para volverlos a utilizar o para compartirlos con otra persona.

Para empezar un nuevo script busca en la esquina superior izquierda

Al crearlo podrás agregar tus funciones, variables y objetos.

Para cargar un nuevo script deberás hacerlo desde Open File, como en cualquier otro programa al abrir un archivo, o sino desde la Consola de RStudio

source("../micarpeta/mi_script_sellama.R")

Se abrirá en el panel de visor de código o editor de script, allí podrás ver su contenido. En la barra de herramientas del visor, desde Run (botón en la parte derecha de las opciones del panel de Script) podrás ejecutar todo el código que contiene o sólo partes de él.

Importante

Cuando se corre un Script o se ejecuta un comando por consola, deberás esperar que desaparezca un cartel de Stop en color rojo, en el panel consola, y podrás comenzar a trabajar nuevamente, cuando en la Consola, aparezca el símbolo >| (| es el prompt).

Ahora, comenzaremos con la ejercitación para ver si se comprendió todo!

Introducción al análisis textual

Durante esta ejercitación utilizaremos funciones básicas en R para manipulación de datos, dataframe, vectores, etc, formas de iteración, formas de visualizaciones, y también una aproximación al análisis textual.

EL corpus con el que trabajaremos lo he dejado en formato zip en la carpeta del campus. El mismo está compuesto por las plataformas electorales de candidatos y candidatas a la presidencia de Argentina, que fueron publicadas en la web oficial luego del cierre de listas el 24 de junio de 2023. Estas se encontraban en formato PDF pero fueron pasadas a texto plano para poder llevar adelante esta ejercitación1.

Cada archivo fue denominado como nombre de la plataforma con extensión .txt, es decir como texto plano.

Inicialmente, partiremos con la preparación de nuestro entorno de trabajo:

rm(list = ls()) #limpiamos el entorno

getwd() #obtenemos la dirección donde estoy ubicada, 
pathwd <- getwd() #asigno a la variable pathwd mi ubicación
setwd("direccion") #seteo mi lugar de trabajo

Ahora instalaremos las librerías necesarias:

install.packages("tm")
install.packages("gridExtra")
install.packages("dplyr")
install.packages("ggplot2")
install.packages("wordcloud")
install.packages("tidyverse")
install.packages("tidytext")

Primero paso: Se puede descargar y descomprimir como lo realizas habitualmente la carpeta directamente del campus, o sino mediante el comando download.file descargarás el archivo *.zip con la url entre comillas, luego indicarás el nombre del archivo y finalmente con el parámetro wget se indica el método utilizado para realizar la descarga, aclaración en Windows debes cambiarlo por wininet. Luego, descomprime el archivo con el comando unzip. A continuación ingresa a tu carpeta de trabajo.

download.file("https://github.com/hdlabconicet/Estilometria-con-R/raw/gh-pages/corpus_ej2.zip", destfile="corpus_ej2.zip", "wget") # Aclaración para Windows reemplazar 'wget' por "wininet"

unzip("corpus_ej2.zip")

setwd("/corpus_ej2/") # Ingresa a la carpeta que se ha creado, recuerda que puedes incluso crear otra carpeta para datos de entrada (input) y datos de salida (output) para cargar y guardar tus archivos

El paso a seguir es llamar a las librerías que se utilizarán:

  • tidyverse y tidytext Estas librerías serán fundamentales para la parte más interesante de este módulo, donde aprenderemos a limpiar y transformar datos en R. Este trabajo es indispensable para el text mining, que realizado en R, contará con varias ventajas: no requiere muestreo para extraer información, permite aplicar varias metodologías de forma rápida y genera procedimientos auditables y reproducibles. El principio básico de un dataframe 'tidy' es que cada columna representa una variable y cada línea, una observación.
  • La librería Tidytext permite realizar minería de texto con el uso de herramientas tidy, generando datos estructurados y tidy a partir de datos textuales.
       
    Nos serviremos de la librería tidytext para 'tokenizar', es decir, sustituir algunos datos por sustitutos sin alterar el tipo o la longitud de los datos.
  • ggplot2 es un paquete que permite la visualización de datos, implementa una representación organizada y en capas, de marcos, ejes, textos, títulos, etc., utilizando diferentes colores, símbolos, tamaños, etc. Fue desarrollada por L. Wilkinson et. al en 20002. No hace falta llamarlo pues se encuentra incluido dentro de tidyverse, sin embargo, es fundamental considerarlo porque es muy útil en R.
  • dplyr , este paquete posee funciones auxiliares necesarias para la manipulación y transformación de datos. En particular, el operador, pipe, %>% permite escribir funciones más legibles para seres humanos.
library(tidytext) #recuerda que si no está instalada la librería primero debes hacerlo mediante install.packages()
library(tidyverse)
library(dplyr)

Una vez instalados estos requerimientos, llamaremos a la función list.file para corroborar que los archivos necesarios se encuentran en la carpeta donde estás trabajando.

list.files(, pattern='txt') #no completo la dirección de la carpeta antes de la coma porque voy a trabajar en ella, solo aclaro que me devuelva la lista de los archivos txt
##  [1] "coalicion_paz_democracia_soberania.txt"     
##  [2] "frente_izquierda_trabajadores.txt"          
##  [3] "frente_liber_ar.txt"                        
##  [4] "hacemos_nuestro_pais.txt"                   
##  [5] "juntos_cambio_orden_nacional.txt"           
##  [6] "libertad_avanza.txt"                        
##  [7] "libres_sur.txt"                             
##  [8] "movimiento_accion_vecinal.txt"              
##  [9] "movimiento_izquierda_juventud_dignidad.txt" 
## [10] "movimiento_socialismo.txt"                  
## [11] "patria_unida.txt"                           
## [12] "politica_obrera.txt"                        
## [13] "principios_valores_tierra_techo_trabajo.txt"
## [14] "union_centro_democratico.txt"               
## [15] "union_patria.txt"

En un segundo paso, crearemos una nueva lista, a la que puedes llamar archivos, cuyos elementos serán los textos planos dentro de la carpeta corpus_ej2, para ello, utilizarás, nuevamente, la función list.files, y le indicarás que tipo de archivo debe contener, txt, con la declaración pattern. Recuerda estar trabajando en la carpeta donde se encuentran tus archivos, sino deberás incorporar un declaración que indique la ubicación, path =, por ejemplo: list.files(path = "discurso", pattern = "\\.txt$").

archivos <- list.files(pattern = "\\.txt$", full.names = TRUE)

archivos #corroboramos que la lista es correcta
##  [1] "./coalicion_paz_democracia_soberania.txt"     
##  [2] "./frente_izquierda_trabajadores.txt"          
##  [3] "./frente_liber_ar.txt"                        
##  [4] "./hacemos_nuestro_pais.txt"                   
##  [5] "./juntos_cambio_orden_nacional.txt"           
##  [6] "./libertad_avanza.txt"                        
##  [7] "./libres_sur.txt"                             
##  [8] "./movimiento_accion_vecinal.txt"              
##  [9] "./movimiento_izquierda_juventud_dignidad.txt" 
## [10] "./movimiento_socialismo.txt"                  
## [11] "./patria_unida.txt"                           
## [12] "./politica_obrera.txt"                        
## [13] "./principios_valores_tierra_techo_trabajo.txt"
## [14] "./union_centro_democratico.txt"               
## [15] "./union_patria.txt"
class(archivos) #la función 'class()' devuelve el tipo de objeto, en este caso podrás ver que se trata de una lista de caracteres
## [1] "character"
length(archivos) #la función 'length()' permite obtener el tamaño del objeto que se incluye dentro de los paréntesis
## [1] 15

Ahora, para facilitar la visualización de cada texto en los siguientes pasos, eliminaremos lo que no es necesario del nombre de cada archivo. Para ello, se utilizará la función gsub, de gran utilidad para limpieza de datos que está incluida por defecto en R. Los parámetros indicarán, según orden de escritura, caracteres que se eliminarán (\\. será para indicar que se busca un . y no otro carácter según las reglas de expresión regular3), los que se agregarán (las doble comillas indican que no se agregará nada), y finalmente, con perl, se determina que se utilicen las reglas de expresiones regulares4.

textos_archivo <- gsub("\\.txt", "", archivos, perl = TRUE)

#Ahora llama a la lista para corroborar que se ha realizado la limpieza

textos_archivo
##  [1] "./coalicion_paz_democracia_soberania"     
##  [2] "./frente_izquierda_trabajadores"          
##  [3] "./frente_liber_ar"                        
##  [4] "./hacemos_nuestro_pais"                   
##  [5] "./juntos_cambio_orden_nacional"           
##  [6] "./libertad_avanza"                        
##  [7] "./libres_sur"                             
##  [8] "./movimiento_accion_vecinal"              
##  [9] "./movimiento_izquierda_juventud_dignidad" 
## [10] "./movimiento_socialismo"                  
## [11] "./patria_unida"                           
## [12] "./politica_obrera"                        
## [13] "./principios_valores_tierra_techo_trabajo"
## [14] "./union_centro_democratico"               
## [15] "./union_patria"
textos_archivo <- gsub("./", "", textos_archivo, perl = TRUE) #esta línea la he agregado porque en mi lista me queda ./ y de esta manera lo elimino, si no es tu caso no hace falta

textos_archivo
##  [1] "coalicion_paz_democracia_soberania"     
##  [2] "frente_izquierda_trabajadores"          
##  [3] "frente_liber_ar"                        
##  [4] "hacemos_nuestro_pais"                   
##  [5] "juntos_cambio_orden_nacional"           
##  [6] "libertad_avanza"                        
##  [7] "libres_sur"                             
##  [8] "movimiento_accion_vecinal"              
##  [9] "movimiento_izquierda_juventud_dignidad" 
## [10] "movimiento_socialismo"                  
## [11] "patria_unida"                           
## [12] "politica_obrera"                        
## [13] "principios_valores_tierra_techo_trabajo"
## [14] "union_centro_democratico"               
## [15] "union_patria"

A continuación, armaremos un vector denominado partidos, que será utilizado para armar una matriz, plataformas, que será a modo de recordatorio de los nombres de cada agrupación y útil para recortar estos dentro del dataframe en el que trabajaremos más adelante.

partidos <- c("part_01", "part_02", "part_03", "part_04", "part_05", "part_06", "part_07", "part_08", "part_09", "part_10", "part_11", "part_12", "part_13", "part_14", "part_15")

plataformas <- cbind(partidos, textos_archivo)

plataformas
##       partidos  textos_archivo                           
##  [1,] "part_01" "coalicion_paz_democracia_soberania"     
##  [2,] "part_02" "frente_izquierda_trabajadores"          
##  [3,] "part_03" "frente_liber_ar"                        
##  [4,] "part_04" "hacemos_nuestro_pais"                   
##  [5,] "part_05" "juntos_cambio_orden_nacional"           
##  [6,] "part_06" "libertad_avanza"                        
##  [7,] "part_07" "libres_sur"                             
##  [8,] "part_08" "movimiento_accion_vecinal"              
##  [9,] "part_09" "movimiento_izquierda_juventud_dignidad" 
## [10,] "part_10" "movimiento_socialismo"                  
## [11,] "part_11" "patria_unida"                           
## [12,] "part_12" "politica_obrera"                        
## [13,] "part_13" "principios_valores_tierra_techo_trabajo"
## [14,] "part_14" "union_centro_democratico"               
## [15,] "part_15" "union_patria"

Posteriormente, realizaremos el cambio de nombre dentro del objeto, por medio de la función sprintf, que toma una cadena y un conjunto de argumentos, para devolver una cadena de caracteres con el texto formateado, además le estoy aclarando que quiero que se llame part_ y un número según nuestra lista textos_archivo, si le digo que utilice dos digitos, por medio de %02d, utilizando expresiones regulares.

textos_archivo #solo corroboro mi lista con archivos
##  [1] "coalicion_paz_democracia_soberania"     
##  [2] "frente_izquierda_trabajadores"          
##  [3] "frente_liber_ar"                        
##  [4] "hacemos_nuestro_pais"                   
##  [5] "juntos_cambio_orden_nacional"           
##  [6] "libertad_avanza"                        
##  [7] "libres_sur"                             
##  [8] "movimiento_accion_vecinal"              
##  [9] "movimiento_izquierda_juventud_dignidad" 
## [10] "movimiento_socialismo"                  
## [11] "patria_unida"                           
## [12] "politica_obrera"                        
## [13] "principios_valores_tierra_techo_trabajo"
## [14] "union_centro_democratico"               
## [15] "union_patria"
new_names <- sprintf("part_%02d", 1:length(textos_archivo)) #utilizo este código para nuevo nombre, diciendole que son dos digitos pero que comience con 01 para evitar luego el desorden pasando la decena

textos_archivo <- new_names #asigno los nuevos nombres

textos_archivo #corroboro que se realizó correctamente
##  [1] "part_01" "part_02" "part_03" "part_04" "part_05" "part_06" "part_07"
##  [8] "part_08" "part_09" "part_10" "part_11" "part_12" "part_13" "part_14"
## [15] "part_15"

Cuarto paso, con la lista de textos acorde para continuar el ejercicio, procedemos a armar un tibble, este objeto es muy similar a los data.frame presentados en la unidad anterior, pues es rectangular, organizado en filas y columnas, y pertenece al paquete tidyverse.

Existen tres diferencias entre los data.frame y los tibble, la primera es como se muestran en consola; segunda, los tibble eliminan por defecto rownames, e incluso no se recomienda su uso, para evitar problemas de compatibilidad principalmente con bases de datos SQL; por último, no convierte a las string (cadenas de caracteres) en factores. Igualmente, ambos objetos son intercambiables5.

Armaremos el tibble con tres columnas, la primera y última tendrán caracteres dentro de sus variables, y parrafo será numérica, como se muestra a continuación:

mensajes <- tibble(textos_archivo = character(),
                   parrafo = numeric(),
                   texto = character()) 

#Si llamas a "mensajes" comprobarás que figura como vacío, esto es porque aún no se ha completado con datos, ello lo realizarás en el próximo paso.

mensajes

Para poder completar el tibble mensajes que creamos, lo hacemos mediante una iteración con el bucle for, que permite repetir instrucciones, evaluando el mismo código para cada elemento de un vector o lista.

En este ejercicio, se le indica que comience la iteración en 1 hasta el tamaño (length) de archivos. Luego, armará en el objeto discurso lo que leerá con la función read_lines, allí se indicará que con la función paste junte los textos dentro de tu carpeta de trabajo, importante añadir esa dirección, con el contenido de archivos[i] , cuyo valor cambiará en cada repetición del bucle. El parámetro sep = será para indicar que los pegue con “/“ .

Paso siguiente, convertiremos lo que acaba de leer en una nueva tabla, otra tibble llamada temporal, tal como hiciste con la anterior de mensajes, indicando que complete con cada texto. La primer columna, parrafo indicará el número de párrafos de cada texto, se lo adjudicará con la función seq_along que contará hasta el número máximo en el objeto discurso y por último, en texto se agregará cada párrafo. Para finalizar la repetición, indicarás que en mensajes se sume la tabla temporal, mediante la función bind_rows.

#Iteración 

for (i in 1:length(archivos)){
  discurso <- read_lines(paste(pathwd, #recuerden que uso pathwd porque es donde me situé y están mis archivos
                               archivos[i],
                               sep = "/"))
  temporal <- tibble(textos_archivo = textos_archivo[i],
                     parrafo = seq_along(discurso),
                     texto = discurso)
  mensajes <- bind_rows(mensajes, temporal)
} 

mensajes #corrobora que se creó correctamente la tabla
plataformas
##       partidos  textos_archivo                           
##  [1,] "part_01" "coalicion_paz_democracia_soberania"     
##  [2,] "part_02" "frente_izquierda_trabajadores"          
##  [3,] "part_03" "frente_liber_ar"                        
##  [4,] "part_04" "hacemos_nuestro_pais"                   
##  [5,] "part_05" "juntos_cambio_orden_nacional"           
##  [6,] "part_06" "libertad_avanza"                        
##  [7,] "part_07" "libres_sur"                             
##  [8,] "part_08" "movimiento_accion_vecinal"              
##  [9,] "part_09" "movimiento_izquierda_juventud_dignidad" 
## [10,] "part_10" "movimiento_socialismo"                  
## [11,] "part_11" "patria_unida"                           
## [12,] "part_12" "politica_obrera"                        
## [13,] "part_13" "principios_valores_tierra_techo_trabajo"
## [14,] "part_14" "union_centro_democratico"               
## [15,] "part_15" "union_patria"
#solo para recordar que partidos corresponden a la numeracion de part_numero

Este sexto paso, será para proceder con la tokenización del corpus, es decir extraer sus unidades de análisis. Para ello, se utilizará la función unnest_tokens que se encuentra dentro del paquete tidytext; se indicará que a cada fila de parrafo, lo separe a nivel de palabra según la columna texto.

mensajes_palabras estará formado por tres columnas, una que indicará el texto, la otra el número de párrafo y finalmente, las palabras de cada uno, pero separadas. Recuerda que el operador pipe (%>%) fue presentado en la primera unidad.

mensajes_palabras <- mensajes %>% 
  unnest_tokens(palabra, texto)


mensajes_palabras

Como siguiente paso, se eliminarán las palabras vacías, que no serán útil en este ejercicio, pero si pueden servir para otros análisis; asimismo, lo realizarás para continuar con la parte de ejercitación que solicitaré como extra. Para ello, se armará una una tabla con las palabras que se obtienen de la función get_stopwords que forma parte del paquete tidytext, y se aclarará que se utilice en español.

stopwords1 <- get_stopwords("es")

stopwords1

Paso siguiente, se le indicará que cambie la columna word por palabra, mediante la función rename, que forma parte del paquete dplyr, que a su vez pertenece a tidyverse, es útil para cambiar el nombre de variables u objetos. Cuestión que debe considerarse al momento de renombrar, es que primero debe escribirse el nuevo término, y a continuación el que se va a cambiar. Este paso es importante para poder eliminar las palabras vacías de mensajes_palabras.

stopwords1 <- stopwords1 %>%
rename(palabra = word)

Ahora, para poder obtener una nueva lista con palabras vacías excluidas, se usará la función anti_join que compara las columnas con el mismo nombre, en este caso palabra y elimina los elementos que coinciden. Cuando finalice la ejecución, aparece un mensaje que significa que las dos listas tienen iguales elementos en esas columnas, en caso contraria, devolverá mensaje de error.

mensajes_sin_vacias <- mensajes_palabras %>%
anti_join(stopwords1)
## Joining with `by = join_by(palabra)`

Como paso siguiente, se procederá a la limpieza de la lista mensajes_palabras y mensajes_sin_vacias. Para ello, se eliminarán dígitos, palabras con menos de tres caracteres, celdas sin caracteres y las que contengan puntos, todo ello se realizará en la columna palabra. Por lo cual, se utilizarán las siguientes funciones:

  • mutate, que crea, modifica y elimina columnas según ciertos parámetros que se le adjudican, se encuentra dentro del paquete tidyverse. En este caso se le sumará str_remove_all (función que se utiliza para eliminar coincidencias en una cadena de caracteres) para que elimine en la columna palabra los números que aparezcan.

  • filter, será para filtrar las palabras con menos de tres caracteres, con la ayuda de nchar que cuenta el número de caracteres; también se utilizará para eliminar los espacios con valores de caracteres vacíos y cuando encuentre un . o (símbolo de número que figura en los textos).

Repetirás las limpieza en las dos listas, recuerda guardar las que no fueron limpias, adjudicando nuevos nombres a las que si se hayan limpiado.

mensajes_pal_limpio <- mensajes_palabras %>%
mutate(palabra = str_remove_all(palabra, "\\d+")) %>%
filter(nchar(palabra) >= 3) %>% #en este item puedo dejar que sea estrictamente mayor a 3, pero lo he dejado como igual o mayor porque había algunas palabras que podrían ser de utilidad
filter(palabra != "") %>%   
filter(palabra != ".") %>%   
filter(palabra != "n°")

mensajes_pal_limpio

Indica nuevo nombre a esta tabla que se ha limpiado. Esta nueva tabla será útil para realizar la parte de ejercitación extra.

mensajes_limpio <- mensajes_sin_vacias %>%
mutate(palabra = str_remove_all(palabra, "\\d+")) %>%
filter(nchar(palabra) >= 3) %>% 
filter(palabra != "") %>%   
filter(palabra != ".") %>%   
filter(palabra != "n°")


mensajes_limpio

En el paso que sigue, se dará inicio a los análisis de frecuencia y gráficos de los textos del corpus. Para lo cual, primero se contará las palabras que se encuentran dentro de la columna palabra en mensajes_pal_limpio, por medio de la función count, que también pertenece al paquete tidyverse, y presentará la frecuencia absoluta de cada una, o sea la cantidad de veces que se repite.

mensajes_pal_limpio %>% 
  count(palabra, sort = TRUE)

Como la frecuencia absoluta no representa ningún dato novedoso, se calculará el promedio de palabras por texto, que no han sido procesadas con la limpieza de datos, pudiéndose calcular entre el resultado del número de columnas obtenidos con la función nrow y el tamaño de la lista archivos, calculado en los primeros pasos.

nrow(mensajes_palabras) / length(archivos)
## [1] 2293

Ese dato solo indicará un promedio, por lo cual, a continuación se calculará la frecuencia relativa por palabras y será adjudica como una nueva columna, dentro del tibble limpio: mensajes_pal_limpio, que se denominará relativa. Por lo cual tendremos tres columnas, la del término, su frecuencia absoluta y la relativa. Por ello armaremos un nuevo tibble denominado, mensajes_frecuencias:

mensajes_frec_limpio <- mensajes_pal_limpio %>%
  count (palabra, sort = TRUE) %>%
  mutate (relativa = n / sum(n))

mensajes_frec_limpio #veremos como quedó conformado el nuevo dataframe

También, podrías pedir que devuelva la frecuencia por cada texto, para ello, se deberá agrupar por cada uno mediante la función group_by, del paquete tidyverse, únicamente indicando que debe considerar la lista de textos, antes preparada; luego del cálculo de la frecuencia absoluta, debe crearse una nueva columna para la frecuencia relativa, y finalmente que desagrupe los datos, con ungroup(). Todo ello, será guardado en otra tabla frecuencia_text_arch:

frecuencia_text_arch <- mensajes_pal_limpio %>%
           group_by(textos_archivo) %>%
           count(palabra, sort = T) %>%
           mutate(relative = n / sum(n)) %>%
           ungroup()

frecuencia_text_arch

Ahora, para visualizar estos datos calculados realizarás un gráfico, donde se presentará la frecuencia por cada texto, con la función ggplot, que fue convocada al principio de la práctica con el paquete tidyverse, se le indicará que se graficará en barras, mediante el parámetro geom_bar, luego se indicará con aes, el contenido de los eje X e Y, en ese orden; y por último, con stat, que tipo de transformación estadísticas tendrán los datos. Recuerda que hemos trabajado con mensajes_pal_limpio y mediante group_by los reunimos según los elementos de la columna textos_archivo:

mensajes_pal_limpio %>%
  group_by(textos_archivo) %>%
  count(palabra, sort = T) %>%
  ggplot() +
  geom_bar(aes(x = textos_archivo, y = n),
           stat = 'identity', , width = 0.7, color = 'purple') +
  labs(    y = "Cantidad de palabras",
    x = "Plataforma",
    title = "Cantidad de palabras por plataforma"
  )

# con este comando puedes guardar tu gráfico: ggsave("mensajes_pal_limpio.png")

Otro gráfico que se puede realizar es observando las palabras más frecuentes de los textos, para ello primero, se llamará a mensajes_pal_limpio, se pedirá que cuente las ocurrencias, ordenadas de mayor a menor; en la tercera línea se indicará que filtre las ocurrencias mayores a 10, pues se han eliminado las palabras vacías. Como se explicó antes, al crear una nueva tabla interna se debe indicar con mutate, la nueva columna, que almacenará los nuevos datos. Luego se indicarán los parámetros del gráfico. Aclaración, ggplot une sus parámetros con +; el argumento fill hará que cada palabra tenga un color determinado, stat indicará que las barras tendrán la altura según n. Las líneas siguientes presentarán parámetros para título, ubicación de leyenda y etiquetas en los ejes; y con coord_flip() se asegura que el eje Y se imprima de forma horizontal.

mensajes_pal_limpio %>%
count(palabra, sort = T) %>%
filter(n > 35) %>%
mutate(palabra = reorder(palabra, n)) %>%
ggplot(aes(x = palabra, y = n, fill = palabra)) +
geom_bar(stat="identity") +
theme_minimal() +
theme(legend.position = "none") +
ylab("Número de veces que aparecen") +
xlab(NULL) +
ggtitle("Palabras más frecuentes por plataforma") +
coord_flip()

# puedes guardar el gráfico con el siguiente comando: ggsave("mensajes_palabras.png")

Un gráfico interesante podría realizarse teniendo en cuenta los mensajes limpios, es decir con las stopwords eliminadas, pero observando que sucede en cada plataforma, observa que solo le he indicado que fill sea diferenciado por partido.

mensajes_limpio %>%
   count(palabra, textos_archivo, sort = T) %>%
  filter(n > 12) %>%
  mutate(palabra = reorder(palabra, n)) %>%
  ggplot(aes(x = palabra, y = n, fill = textos_archivo)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  ylab("Número de veces que aparecen") +
  xlab(NULL) +
  ggtitle("Palabras más frecuentes por plataforma") +
  coord_flip()

Otra utilidad que podemos apreciar, y la hemos visto en la parte teórica, es la Ley de Zipf, por lo cual, vamos a reorganizar los parámetros de ggplot para poder apreciar la relación entre cada palabra y su frecuencia.

Para ello, primero se armará una tabla con mensajes_palabras, con columnas con frecuencia absoluta = n y frecuencia relativa, sumada una última columna, que indicará el orden de palabras en forma descendente, o el número de filas, llamada Clasificacion.

mensajes_frecuencias <- mensajes_palabras %>%
  count (palabra, sort = TRUE) %>%
  mutate (relativa = n / sum(n)) %>% 
   mutate(Clasificacion = row_number())

mensajes_frecuencias

Para realizar el gráfico con dichos datos, se utilizará la tabla anterior, y se indicará en la tercera línea, mediante geom_line la forma en que va a realizar la línea del gráfico; y en las últimas dos, se indicará que en ambos ejes se usará la escala logarítimica.

mensajes_frecuencias %>%  
  ggplot(aes(Clasificacion, relativa, color = n)) + 
  geom_line(size = 1.5, alpha = 1.8, show.legend = FALSE) + 
  scale_x_log10() +
  scale_y_log10()

Una cuestión final, que es a modo de comparación con la clase anterior con la Dra. del Rio, así como con las herramientas que trabajaron, veremos como se puede realizar gráficos de nube de palabras. Para lo cual, deberás utilizar los datos de mensajes_limpio y cargaras la librería wordcloud. Primero, indicaremos que seleccione los datos para realizar la nube, luego mediante count se contarán las observaciones, indicando que las clasifique, con el argumento with podremos realizar la evaluación de la función wordcloud, primero le diremos que tome las palabras de determinada frecuencia, max.words, que nos indicará que elija los términos más con determinada frecuencia, y por último indicaremos la gama de colores que deseamos (pueden acceder al siguiente enlace para una paleta de colores completa).

library("wordcloud")
mensajes_limpio %>% 
  count(palabra, sort = T) %>%
  with(wordcloud(palabra,
                 n,
                 max.words = 85,
                 color = brewer.pal(8, "Paired")))

library(wordcloud2) #esta librería permite nubes de palabras interactivas, que presentan la frecuencia

mensajes_limpio %>%
  count(palabra, sort = TRUE) %>%
  wordcloud2(data = ., size = 0.5)

Bien, hasta aquí trabajamos en conjunto, ahora mi propuesta es que realicen análisis y gráficos, con mensajes donde se han realizado la limpieza de palabras vacías y que comparen los datos.
Por otro lado, como ejercitación extra podrían intentar agrupar, según algunas palabras, los archivos del corpus.
Pueden compartir sus script, recuerden guardarlo como *.R y los gráficos pegados, en el foro de consultas o enviarlos directamente a mi correo electrónico.


  1. Plataformas extraídas desde https://www.electoral.gob.ar/nuevo/paginas/datos/plataformas_paso2023.php, en distrito nacional. Por otro lado, se puede realizar el pasaje de PDF a txt mediante R, para ello pueden consultar: https://cran.r-project.org/web/packages/pdftools/pdftools.pdf y https://github.com/ropensci/pdftools#readme↩︎

  2. Para más información sobre ggplot2, véase Wilkinson, L., D. Wills, D. Rope, A. Norton, and R. Dubbs (2005. The Grammar of Graphics. Statistics and Computing. New York: Springer.↩︎

  3. Para más información sobre expresiones regulares en R: https://cran.r-project.org/web/packages/stringr/vignettes/regular-expressions.html↩︎

  4. También puedes econtrar información general sobre RegEx en: https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular.↩︎

  5. Puedes acceder a más información sobre tibble en https://cran.r-project.org/web/packages/tibble/vignettes/tibble.html.↩︎