Códigos en R utilizados para análisis literario a distancia en español (Giménez, 2024). Este documento actualiza y amplía una versión anterior desarrollada por Diego Giménez y Andressa Gomide en 2022, que se centraba en el análisis del “Libro del desasosiego”. En esta nueva versión, se analizan obras de Miguel de Cervantes, incluyendo “Don Quijote”, “Los trabajos de Persiles y Sigismunda”, “Novelas ejemplares”, “El Cerco de Numancia” y “Galatea”.
Quanteda (Quantitative Analysis of Textual Data) es un paquete de R para la manipulación y análisis de datos textuales.
La instalación de R varía según el sistema operativo (ej.: Windows, Mac, Linux), así como sus diferentes versiones. Hay varias fuentes donde se pueden obtener instrucciones actualizadas sobre cómo instalar R (ej.: https://didatica.tech/como-instalar-a-linguagem-r-e-o-rstudio/). El Comprehensive R Archive Network (CRAN), la red oficial de distribución de R, ofrece instrucciones fiables para ello, aunque quizás no tan detalladas como en otras fuentes.
Otra sugerencia es instalar una interfaz gráfica de usuario, del inglés Graphical User Interface (GUI). Las GUIs facilitan considerablemente la interacción del usuario con el ordenador. (RStudio) es la GUI más utilizada para R y, al igual que R, es gratuita y de código abierto.
Al reutilizar códigos, es una buena práctica estar atento a la versión instalada tanto de R como de las bibliotecas utilizadas. No es necesario que las versiones sean las mismas que las utilizadas durante la creación de los códigos; sin embargo, en algunos casos, puede no haber compatibilidad entre versiones diferentes y algunas funciones o paquetes pueden haber sido descontinuados. Este artículo fue escrito utilizando la versión 4.3.3 de R.
# Verificar la versión de R
R.version.string
## [1] "R version 4.3.3 (2024-02-29 ucrt)"
Para nuestro análisis, utilizaremos algunos paquetes ya existentes. Estos paquetes no son más que extensiones para R que normalmente contienen datos o códigos. Para utilizarlos, necesitamos instalarlos en el ordenador, si aún no se ha hecho, y cargarlos en R. Una ventaja de cargar solo los paquetes necesarios (en lugar de todos los paquetes instalados) es evitar procesamiento computacional innecesario. El código a continuación crea una lista de los paquetes utilizados en el presente análisis y los carga, instalando los que aún no estaban presentes.
# Listamos los paquetes que necesitamos
packages = c("quanteda", # aAnálisis cuantitativo de datos textuales.
"quanteda.textmodels", # Complementa a Quanteda, proporcionando funcionalidades específicas para la modelización de texto.
"quanteda.textstats", # Este paquete contiene funciones para calcular estadísticas descriptivas y medidas de complejidad de texto, como la diversidad léxica y la densidad léxica.
"quanteda.textplots", # Este paquete ofrece herramientas para la visualización de datos textuales, incluyendo gráficos de dispersión de palabras, nubes de palabras y mapas de calor.
"newsmap", # Para clasificar documentos, basado en “seed words”, es decir, palabras clave predefinidas que indican tópicos o categorías.
"readtext", # Para leer diferentes formatos de texto.
"spacyr", # Para anotación de clases gramaticales, reconocimiento de entidades y anotación sintáctica (Python debe estar instalado).
"ggplot2", # Para gráficos simples de las frecuencias.
"seededlda", # Para modelización de tópicos.
"stringr", # Para las expresiones regulares.
"dplyr", # Este paquete es parte del tidyverse y ofrece un conjunto de funciones para la manipulación de datos tabulares en R, permitiendo realizar operaciones como filtrado, selección, agregación y unión de datos de forma sencilla y eficiente.
"tidytext", # Este paquete complementa al tidyverse, proporcionando herramientas para el análisis de texto en conjunto con los principios de organización de datos del tidyverse, permitiendo integrar fácilmente análisis de texto en pipelines de análisis de datos.
"knitr", # Este paquete se utiliza para la producción de documentos dinámicos en R, permitiendo integrar código R y resultados de análisis en documentos Markdown, HTML, PDF y otros formatos.
"stringr", # Este paquete proporciona funciones para la manipulación de cadenas de texto en R, facilitando tareas como la coincidencia de patrones, la extracción de subcadenas y la manipulación de texto.
"igraph", # Este paquete se utiliza para el análisis y visualización de redes en R, ofreciendo funciones para crear, manipular y representar grafos y redes complejas.
"topicmodels" # Este paquete se utiliza para la modelización de tópicos en textos, ofreciendo implementaciones de algoritmos como LDA (Latent Dirichlet Allocation) y LSA (Latent Semantic Analysis) para la inferencia de tópicos en colecciones de documentos.
)
# Instalamos (si es necesario) y cargamos los paquetes
package.check <- lapply(
packages,
FUN = function(x) {
if (!require(x, character.only = TRUE)) {
install.packages(x, dependencies = TRUE)
require(x, character.only = TRUE)
}
}
)
Los códigos a continuación se implementaron en la versión 4.0.2 de
Quanteda. Utilizar una versión diferente puede resultar en errores o
resultados indeseados. Para verificar la versión de los paquetes,
empleamos la función packageVersion
. Para verificar la
versión de R, utilizamos R.version.string
.
# Verificar la versión de Quanteda
packageVersion("quanteda")
## [1] '4.0.2'
Por último, necesitamos establecer cuál será nuestro directorio de trabajo. Este será el lugar donde se guardarán los resultados. Para identificar cuál es el directorio de trabajo actual, utilizamos la función getwd(), que devuelve la ruta absoluta, es decir, la dirección completa del directorio. Para definir un nuevo lugar de trabajo, utilizamos la función setwd(). Archivos guardados en ese directorio pueden ser leídos solo con la indicación del nombre del archivo, pues podemos utilizar la ruta relativa, es decir, la dirección del archivo a partir del directorio en el que estamos trabajando.
Una vez instalados los paquetes necesarios, se puede proceder al análisis del corpus. Para ello, necesitamos cargar el corpus en R. Si estamos trabajando con datos almacenados localmente, es decir, disponibles en el ordenador donde se realizarán los análisis, basta con utilizar la función readtext(), indicando la ubicación (relativa o absoluta) del archivo deseado.
El libro “Don Quijote” puede ser leído como un archivo único,
# Para leer un archivo único con todo el contenido del libro
Don_Quijote <- readtext("~/corpora/Don Quijote.txt", encoding = "utf-8")
# Devuelve la estructura del objeto creado
str(Don_Quijote)
## Classes 'readtext' and 'data.frame': 1 obs. of 2 variables:
## $ doc_id: chr "Don Quijote.txt"
## $ text : chr "El ingenioso hidalgo don Quijote de la Mancha\n\n\n\npor Miguel de Cervantes Saavedra\n\n\n\n\n\nEl ingenioso h"| __truncated__
O considerando el libro como una unidad dentro de un corpus formado por varios documentos:
# Leer todos los archivos en la carpeta ldod del directorio corpora
cervantes_files <- readtext("~/corpora/cervantes", encoding = "utf-8")
# Devolver la estructura del objeto creado
str(cervantes_files)
## Classes 'readtext' and 'data.frame': 5 obs. of 2 variables:
## $ doc_id: chr "Don Quijote.txt" "El Cerco de Numancia.txt" "Galatea.txt" "Los trabajos de Persiles y Sigismunda.txt" ...
## $ text : chr "El ingenioso hidalgo don Quijote de la Mancha\n\n\n\npor Miguel de Cervantes Saavedra\n\n\n\n\n\nEl ingenioso h"| __truncated__ "EL CERCO DE NUMANCIA\n\nFIGURAS SIGUIENTES:\n\nCIPIÓN, romano.\nIUGURTA, romano.\n_Gayo_ MARIO, romano.\nQUINTO"| __truncated__ "Yo, Miguel de Ondarza Zavala, escribano de cámara de Su Majestad, de los que residen en el su Consejo, doy fe q"| __truncated__ "HISTORIA DE LOS TRABAJOS DE PERSILES Y SIGISMUNDA\n\n\nLIBRO I\n\nCAPITULO XXII\n\n_Donde el capitán da cuenta "| __truncated__ ...
Los textos anteriores derivan de la obra de Cervantes, disponible en el Proyecto Gutenberg Projeto Gutenberg.
Los archivos se guardaron con la codificación utf-8 y se eliminaron la información para-textual y editorial (como notas de los editores) que pudieran interferir en la investigación automática del software.
Los análisis a continuación se demostrarán utilizando los dos corpus, en diferentes momentos.
La limpieza a continuación se aplicó solo a los textos guardados por separado (cervantes_files). El archivo con el libro en un único texto (Don_Quijote) ya había sido limpiado anteriormente.
# Creamos una copia para recuperar el original en caso de que haya errores en la regex
cervantes_clean <- cervantes_files
## Eliminación de los elementos indeseados
# Eliminar números al inicio de líneas (índices)
cervantes_clean$text <- str_replace_all(cervantes_clean$text, "\\n\\d", "\n")
# Eliminar fechas
cervantes_clean$text <- str_replace_all(cervantes_clean$text, "\\d{1,2}-(\\d{1,2}|[IVX]{1,4})-19\\d{2}", "")
Después de que los archivos se cargan en el sistema, necesitamos
crear un objeto “corpus”, es decir, el formato necesario para que
Quanteda pueda procesar y generar información sobre el(los) texto(s).
Para ello, basta con aplicar la función corpus
.
Automáticamente, el texto se segmenta en tokens y frases. Los tokens
corresponden a todas las ocurrencias (incluyendo repeticiones) de
palabras, así como otros elementos como puntuación, números y símbolos.
Al investigar el corpus con la función summary
, obtenemos
el recuento de frases, tokens y types (el número de tokens distintos en
un corpus).
# Crear el corpus de varios archivos
corpus_clean <- corpus(cervantes_clean)
# ver un resumen del corpus
summary(corpus_clean)
# Crear corpus del archivo único
corpus_unico <- corpus(Don_Quijote)
# Presentar un resumen del corpus
summary(corpus_unico)
Si es necesario, podemos alterar la estructura de nuestro corpus. En
el corpus_unico
, tenemos un corpus hecho con solo un texto.
Con corpus_reshape
podemos crear un nuevo corpus en el que
cada frase se considere un texto, es decir, una unidad.
# Revelar el número de textos en el corpus
ndoc(corpus_unico)
## [1] 1
# Reestructurar el corpus, convirtiendo cada frase en una unidad
corpus_sents <- corpus_reshape(corpus_unico, to = "sentences")
# Presentar un resumen del corpus
summary(corpus_sents)
# Número total de unidades en la nueva estructura del corpus
ndoc(corpus_sents)
## [1] 7250
Los ejemplos anteriores nos muestran que un corpus es un conjunto de textos con información sobre cada texto (metadatos), de los cuales podemos extraer fácilmente el recuento de tokens, types y frases para cada texto. Sin embargo, para realizar análisis cuantitativos en el corpus, necesitamos dividir los textos en tokens (tokenización). También es posible filtrarlos, eliminando elementos como puntuación, símbolos, números, URLs y separadores.
# Tokenizar nuestros tres corpus
toks_unico <- tokens(corpus_unico)
toks_sents <- tokens(corpus_sents)
toks_files <- tokens(corpus_clean)
## A continuación, filtramos los tres corpus de diversas formas, para demostración
# Eliminar puntuación (corpus limpio con regex)
toks_nopunct_files <- tokens(corpus_clean, remove_punct = TRUE)
toks_nopunct_unico <- tokens(corpus_unico, remove_punct = TRUE)
# Eliminar números (corpus con solo un archivo)
toks_nonumbr <- tokens(corpus_unico, remove_numbers = TRUE)
# Eliminar separadores (categorías Unicode "Separator" [Z] y "Control" [C]) (corpus hecho por frases)
toks_nosept <- tokens(corpus_sents, remove_separators = TRUE)
# Eliminar varios elementos al mismo tiempo (corpus con solo un archivo)
toks_simples <- tokens(corpus_unico, remove_numbers = TRUE, remove_symbols = TRUE, remove_punct = TRUE)
También es posible eliminar tokens no deseados. Quanteda ofrece una lista de ‘stopwords’ para diferentes lenguas. Las stopwords, o palabras vacías en español, son palabras que se deben eliminar durante el procesamiento de textos para análisis computacionales. No existe una lista estándar, pero generalmente las stopwords son las palabras más frecuentemente utilizadas en una lengua, como preposiciones y artículos. El bloque a continuación elimina las palabras incluidas en la lista de stopwords para el español y también incluye otras palabras que se repiten en el corpus en cuestión.
# Eliminar stopwords del corpus hecho con un solo archivo
toks_nostop <- tokens_select(toks_unico, pattern = stopwords("es"), selection = "remove")
# Eliminar tokens específicos del corpus hecho con varios archivos y limpio con regex, después de eliminar las puntuaciones
toks_selected_files <- tokens_select(toks_nopunct_files, pattern = c("dijo", "tan", "así", "respondió", "sino", "pues", "dos", "aunque", "aquel", "alguna", "aquella", "cómo", "algún", "aun", "oh", "á", "si","mas", stopwords("es")), selection = "remove")
# Eliminar tokens específicos del corpus hecho con un archivo, después de eliminar las puntuaciones
toks_selected_unico <- tokens_select(toks_nopunct_unico, pattern = c("dijo", "tan", "así", "respondió", "sino", "pues", "dos", "aunque", "aquel", "alguna", "aquella", "cómo", "algún", "aun", "oh", "á", "si", "mas", stopwords("es")), selection = "remove")
Después de la tokenización, el siguiente paso es crear una tabla con la frecuencia de cada token por cada texto, o, en los términos de Quanteda, una document-feature-matrix (DFM). La DFM es un requisito previo para varias otras funciones en Quanteda, como es el caso de la topfeatures, que devuelve los tokens más frecuentes en un corpus.
# aAquí podemos ver las 20 palabras más frecuentes cuando eliminamos
# Números, símbolos y puntuación
dfm_simples <- dfm(toks_simples)
print("Con eliminación de números, símbolos y puntuación")
## [1] "Con eliminación de números, símbolos y puntuación"
topfeatures(dfm_simples, 20)
## que de y la a en el no los se con por lo
## 20769 18410 18272 10492 9875 8285 8265 6346 4769 4752 4275 3945 3492
## las le su don del me como
## 3486 3420 3388 2714 2536 2345 2270
dfm_nostop <- dfm(toks_nostop)
print("remoção de stopwords")
## [1] "remoção de stopwords"
topfeatures(dfm_nostop, 20)
## , . — ; don quijote sancho :
## 40277 8208 6923 4802 2714 2241 2174 2047
## si dijo tan señor así respondió ser bien
## 1968 1808 1245 1065 1065 1063 1059 1051
## ? ¿ merced pues
## 960 959 900 865
dfm_selected_unico <- dfm(toks_selected_unico)
print("Eliminación de tokens seleccionados en el corpus previamente limpiado con regex y sin stopwords")
## [1] "Eliminación de tokens seleccionados en el corpus previamente limpiado con regex y sin stopwords"
topfeatures(dfm_selected_unico, 20)
## don quijote sancho señor ser bien merced caballero
## 2714 2241 2174 1065 1059 1051 900 677
## decir hacer dios señora aquí mal cosa buen
## 578 535 531 518 516 463 447 446
## verdad tal allí ver
## 436 428 421 410
dfm_selected_files <- dfm(toks_selected_files)
print("Eliminación de tokens seleccionados en el corpus de archivo único y sin stopwords")
## [1] "Eliminación de tokens seleccionados en el corpus de archivo único y sin stopwords"
topfeatures(dfm_selected_files, 20)
## don quijote sancho ser bien señor merced decir
## 2754 2242 2185 1971 1935 1510 1063 972
## hacer vida caballero mal luego aquí allí cosa
## 955 890 864 848 842 838 837 822
## señora tal ver habia
## 819 813 787 768
Después de generar la lista de tokens, podemos explorar el corpus. Una de las técnicas más simples y utilizadas para la investigación de corpus es a través de las líneas de concordancia, también conocidas como concordance lines o keywords in context (kwic). Las líneas de concordancia muestran fragmentos del corpus donde ocurren los términos buscados. El número de palabras en el contexto puede ser estipulado por el usuario, siendo 5 tokens a la izquierda y 5 a la derecha el estándar. La primera columna indica el nombre del archivo donde la palabra buscada ocurre. Existen varias opciones para búsquedas. Pueden hacerse por palabras o por fragmentos, secuencias o combinaciones de las mismas.
# Ocurrencias de palabras que empiezan con “feli”
kwic(toks_unico, pattern = "feli*")
# Podemos también buscar más de una palabra al mismo tiempo
kwic(toks_unico, pattern = c("feli*", "alegr*"))
# Por secuencia de más de un token
kwic(toks_unico, pattern = phrase("me fal*"))
Las listas de frecuencia de palabras pueden ser útiles para identificar elementos comunes en un texto. Sin embargo, en muchos casos, es igualmente importante saber en qué contexto se encuentran esas palabras. Identificar qué palabras coocurren frecuentemente en un corpus puede proporcionarnos aún más información sobre el texto. Por ejemplo, saber que la secuencia ‘estoy triste’ ocurre frecuentemente en el corpus nos proporciona información más rica que solo la frecuencia de la palabra ‘triste’ aislada. La secuencia ‘estoy triste’ es un ejemplo de lo que llamamos n-grams, o, en este caso específico, bigramas. Los n-grams son secuencias de dos o más palabras que ocurren en un texto. Para generar listas de n-grams, partimos de una lista de tokens y especificamos el número mínimo y máximo de tokens en cada n-grama.
# Crear una lista de bigramas, trigramas y tetragramas
toks_ngram <- tokens_ngrams(toks_simples, n = 2:4)
# Visualizar solo los 30 más frecuentes
head(toks_ngram[[1]], 30)
## [1] "El_ingenioso" "ingenioso_hidalgo" "hidalgo_don"
## [4] "don_Quijote" "Quijote_de" "de_la"
## [7] "la_Mancha" "Mancha_por" "por_Miguel"
## [10] "Miguel_de" "de_Cervantes" "Cervantes_Saavedra"
## [13] "Saavedra_El" "El_ingenioso" "ingenioso_hidalgo"
## [16] "hidalgo_don" "don_Quijote" "Quijote_de"
## [19] "de_la" "la_Mancha" "Mancha_Tasa"
## [22] "Tasa_Testimonio" "Testimonio_de" "de_las"
## [25] "las_erratas" "erratas_El" "El_Rey"
## [28] "Rey_Al" "Al_Duque" "Duque_de"
Otra forma de extraer información de un texto es a través de la
creación de “diccionarios”. La función dictionary
en
Quanteda permite agrupar tokens por categorías. Esta categorización
puede entonces ser utilizada para búsquedas en el corpus. Por ejemplo,
podemos crear las categorías “alegría” y “tristeza” conteniendo palabras
relacionadas con esos sentimientos, respectivamente. Con el diccionario
creado, podemos identificar la distribución de esos términos en un
corpus.
# Creación de diccionario a partir del corpus formado por un único documento
dict <- dictionary(list(alegria = c("alegr*", "allegr*", "feli*", "content*"),
tristeza = c("trist*", "infeli*")))
dict_toks <- tokens_lookup(toks_unico, dictionary = dict)
print(dict_toks)
## Tokens consisting of 1 document.
## Don Quijote.txt :
## [1] "alegria" "alegria" "alegria" "alegria" "alegria" "tristeza"
## [7] "alegria" "alegria" "alegria" "alegria" "alegria" "tristeza"
## [ ... and 540 more ]
dfm(dict_toks)
## Document-feature matrix of: 1 document, 2 features (0.00% sparse) and 0 docvars.
## features
## docs alegria tristeza
## Don Quijote.txt 403 149
# Creación de diccionario a partir del corpus formado por varios documentos
dict <- dictionary(list(alegria = c("alegr*", "allegr*", "feli*", "content*"),
tristeza = c("trist*", "infeli*")))
dict_toks <- tokens_lookup(toks_files, dictionary = dict)
print(dict_toks)
## Tokens consisting of 5 documents.
## Don Quijote.txt :
## [1] "alegria" "alegria" "alegria" "alegria" "alegria" "tristeza"
## [7] "alegria" "alegria" "alegria" "alegria" "alegria" "tristeza"
## [ ... and 540 more ]
##
## El Cerco de Numancia.txt :
## [1] "tristeza" "tristeza" "tristeza" "tristeza" "alegria" "tristeza"
## [7] "tristeza" "tristeza" "tristeza" "tristeza" "tristeza" "tristeza"
## [ ... and 10 more ]
##
## Galatea.txt :
## [1] "alegria" "alegria" "tristeza" "alegria" "tristeza" "alegria"
## [7] "alegria" "alegria" "alegria" "alegria" "tristeza" "alegria"
## [ ... and 431 more ]
##
## Los trabajos de Persiles y Sigismunda.txt :
## [1] "alegria" "alegria" "alegria" "alegria" "alegria" "alegria"
## [7] "tristeza" "alegria" "alegria" "alegria" "tristeza" "alegria"
## [ ... and 13 more ]
##
## Novelas Ejemplares.txt :
## [1] "alegria" "alegria" "alegria" "alegria" "alegria" "alegria" "alegria"
## [8] "alegria" "alegria" "alegria" "alegria" "alegria"
## [ ... and 302 more ]
dfm(dict_toks)
## Document-feature matrix of: 5 documents, 2 features (0.00% sparse) and 0 docvars.
## features
## docs alegria tristeza
## Don Quijote.txt 403 149
## El Cerco de Numancia.txt 4 18
## Galatea.txt 324 119
## Los trabajos de Persiles y Sigismunda.txt 23 2
## Novelas Ejemplares.txt 272 42
En 1.4, creamos una DFM con la frecuencia de los tokens. Para absorber estas frecuencias de forma más rápida, podemos generar visualizaciones. Una opción es la nube de palabras, un gráfico que permite la rápida visualización de los términos más frecuentes.
# Demostración de cómo cambian las frecuencias de palabras según la preparación del corpus corpus
set.seed(100) #para reprodução dos resultados
textplot_wordcloud(dfm_selected_unico, min_count = 6, random_order = FALSE, rotation = .25, color = RColorBrewer::brewer.pal(8, "Dark2"))
set.seed(100)
textplot_wordcloud(dfm_selected_files, min_count = 6, random_order = FALSE, rotation = .25, color = RColorBrewer::brewer.pal(8, "Dark2"))
set.seed(100)
textplot_wordcloud(dfm_nostop, min_count = 6, random_order = FALSE, rotation = .25, color = RColorBrewer::brewer.pal(8, "Dark2"))
Otra solución es utilizar la biblioteca ggplot y representar en un gráfico el número de ocurrencias de las palabras más frecuentes.
# A partir del corpus formado por un único documento
dfm_selected_unico %>%
textstat_frequency(n = 20) %>%
ggplot(aes(x = reorder(feature, frequency), y = frequency)) +
geom_point() +
coord_flip() +
labs(x = NULL, y = "Frequência") +
theme_minimal()
# A partir de un corpus formado por varios documentos
dfm_selected_files %>%
textstat_frequency(n = 20) %>%
ggplot(aes(x = reorder(feature, frequency), y = frequency)) +
geom_point() +
coord_flip() +
labs(x = NULL, y = "Frequência") +
theme_minimal()
Otra función frecuentemente utilizada en el Procesamiento de Lenguaje Natural (PLN) es el modelado de tópicos, también conocido como topic modeling (TM). El modelado de tópicos aplica un modelo estadístico que busca comprender la estructura del corpus e identificar y agrupar palabras que se relacionan de alguna forma entre sí. El TM utiliza una técnica semi o no supervisada para la identificación de esos tópicos. En otras palabras, el programa aprende a reconocer patrones en los datos sin la necesidad de anotaciones previas. El código a continuación demuestra la aplicación del modelo Latent Dirichlet Allocation (LDA).
# Modelización de tópicos a partir del corpus formado por un único documento
lda <- LDA(dfm_selected_unico, k = 10)
terms(lda, 10)
## Topic 1 Topic 2 Topic 3 Topic 4 Topic 5 Topic 6 Topic 7
## [1,] "sancho" "quijote" "merced" "sancho" "don" "don" "don"
## [2,] "don" "señor" "señor" "don" "quijote" "ser" "quijote"
## [3,] "ser" "sancho" "bien" "bien" "bien" "quijote" "sancho"
## [4,] "señora" "decir" "ser" "caballero" "merced" "merced" "señor"
## [5,] "merced" "mal" "don" "quijote" "aquí" "señor" "ser"
## [6,] "dicho" "caballero" "hacer" "merced" "ser" "mundo" "cosa"
## [7,] "buen" "dios" "aquí" "ser" "decir" "cosa" "caballero"
## [8,] "señor" "hacer" "sancho" "señora" "señor" "ahora" "buen"
## [9,] "sé" "don" "dios" "decir" "sancho" "lugar" "bien"
## [10,] "lugar" "dio" "menos" "dios" "mal" "bien" "vida"
## Topic 8 Topic 9 Topic 10
## [1,] "don" "quijote" "quijote"
## [2,] "quijote" "sancho" "don"
## [3,] "señor" "don" "bien"
## [4,] "decir" "caballero" "sancho"
## [5,] "merced" "bien" "ser"
## [6,] "verdad" "ser" "señor"
## [7,] "hacer" "dios" "señora"
## [8,] "ser" "dicho" "dicho"
## [9,] "bien" "hacer" "mundo"
## [10,] "mal" "todas" "merced"
# Modelización de tópicos a partir de un corpus formado por varios documentos
lda <- LDA(dfm_selected_files, k = 10)
terms(lda, 10)
## Topic 1 Topic 2 Topic 3 Topic 4 Topic 5 Topic 6 Topic 7
## [1,] "numancia" "amor" "habia" "don" "don" "ser" "sancho"
## [2,] "s" "bien" "hacer" "quijote" "quijote" "navío" "quijote"
## [3,] "°" "ser" "d" "ser" "señor" "tierra" "don"
## [4,] "1" "pastores" "ojos" "bien" "merced" "mar" "bien"
## [5,] "vida" "elicio" "ser" "merced" "caballero" "todas" "merced"
## [6,] "2" "galatea" "habian" "manera" "dios" "lugar" "aquí"
## [7,] "romanos" "vida" "ó" "ver" "sancho" "rey" "decir"
## [8,] "muerte" "mal" "tal" "mal" "bien" "fué" "vida"
## [9,] "aquí" "cielo" "bien" "aquí" "panza" "luego" "señora"
## [10,] "cip" "ojos" "cosa" "señora" "decir" "cosa" "toda"
## Topic 8 Topic 9 Topic 10
## [1,] "habia" "fué" "sancho"
## [2,] "bien" "casa" "ser"
## [3,] "ser" "ó" "don"
## [4,] "ó" "todas" "señor"
## [5,] "d" "ser" "hacer"
## [6,] "luego" "habia" "bien"
## [7,] "señora" "ahora" "cosa"
## [8,] "señor" "merced" "verdad"
## [9,] "decir" "señor" "caballero"
## [10,] "vida" "cosa" "dicho"
El Feature co-occurrence matrix (FCM) es similar al DFM, pero considera las coocurrencias, presentando un gráfico con las redes semánticas.
# Red a partir del corpus formado por un único documento
# Crear FCM a partir de DFM
fcm_nostop <- fcm(dfm_selected_unico)
# Listar las top features
feat <- names(topfeatures(dfm_selected_unico, 50))
# Seleccionar
fcm_select <- fcm_select(fcm_nostop, pattern = feat, selection = "keep")
size <- log(colSums(dfm_select(dfm_selected_unico, feat, selection = "keep")))
textplot_network(fcm_select, min_freq = 0.8, vertex_size = size / max(size) * 3)
# Red a partir de un corpus formado por varios documentos
# Crear FCM a partir de DFM
fcm_nostop <- fcm(dfm_selected_files)
# Listar las top features
feat <- names(topfeatures(dfm_selected_files, 50))
# Seleccionar
fcm_select <- fcm_select(fcm_nostop, pattern = feat, selection = "keep")
size <- log(colSums(dfm_select(dfm_selected_files, feat, selection = "keep")))
textplot_network(fcm_select, min_freq = 0.8, vertex_size = size / max(size) * 3)
Los datos y códigos están disponibles vía github https://github.com/DiegoEGimenez/R_literatura_Quanteda
El código puede ser visualizado en https://rpubs.com/DiegoEGimenez/r_literatura_quanteda_es
Este documento (2024) contiene una revisión y ampliación de códigos originalmente preparados por Diego Giménez y Andressa Gomide en 2022 para el análisis del “Libro del desasosiego”. Algunos de los códigos descritos en el documento de 2022 utilizaron los códigos gentilmente cedidos por Mark Alfano, usados en su trabajo “Nietzsche corpus analysis”.