library(tidyverse)
library(gutenbergr)
library(tidytext)
library(patchwork)
library(wordcloud)He convertido dos obras cumbres de la novela en castellano en sendos data frames de R, y he hecho alguna estadística sencilla con ellas. Los conjuntos de datos resultantes se pueden usar en la docencia como ejemplos de visualización de datos o de ajuste de una recta por mínimos cuadrados.

La primera novela empieza así:
En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor. Una olla de algo más vaca que carnero, salpicón las más noches, duelos y quebrantos los sábados, lantejas los viernes, algún palomino de añadidura los domingos, consumían las tres partes de su hacienda. El resto della concluían sayo de velarte, calzas de velludo para las fiestas, con sus pantuflos de lo mesmo, y los días de entresemana se honraba con su vellorí de lo más fino. Tenía en su casa una ama que pasaba de los cuarenta, y una sobrina que no llegaba a los veinte, y un mozo de campo y plaza, que así ensillaba el rocín como tomaba la podadera.
El comienzo de la segunda es:
La heroica ciudad dormía la siesta. El viento Sur, caliente y perezoso, empujaba las nubes blanquecinas que se rasgaban al correr hacia el Norte. En las calles no había más ruido que el rumor estridente de los remolinos de polvo, trapos, pajas y papeles que iban de arroyo en arroyo, de acera en acera, de esquina en esquina revolando y persiguiéndose, como mariposas que se buscan y huyen y que el aire envuelve en sus pliegues invisibles.
Se trata, claro, del Quijote y La Regenta.
Cómo convertir una novela en un data frame
Antes de empezar hay que cargar todos los paquetes que van a ser necesarios:
El siguiente código usa el paquete gutenbergr para descargar el Quijote y la Regenta desde la página del Proyecto Gutenberg. Se usa el paquete gutenbergr y el comando gutenberg_download aplicado a la clave del libro, que hay que buscar en la página mencionada. Posteriormente se usa unnest_tokens de tidytext para convertir el libro en un data frame manejable:
# Quijote --------------------------------------
quijote <- gutenberg_download(2000)
quijote <- quijote %>%
# Crea una variable que contiene las palabras sueltas:
unnest_tokens(word, text)
# Regenta -------------------------------------
regenta <- gutenberg_download(17073)
# Para resolver un problema técnico con la codificación
regenta$text <- iconv(regenta$text, "latin1", "UTF-8")
regenta <- regenta %>%
# Crea una variable que contiene las palabras sueltas:
unnest_tokens(word, text)El resultado es un fichero con dos variables, la primera contiene el código del libro y la segunda, una por una, todas las palabras.
¿Cuáles son las palabras significativas más frecuentes?
Si vamos a mirar cuáles son las palabras más repetidas tenemos que quitar primero las que no son significativas (preposiciones, artículos, etc.). Para ello, he usado un fichero de palabras no significativas del castellano que he encontrado aquí y luego he retocado ligeramente. Además, es necesario quitar algunas otras palabras por la naturaleza del texto que estamos analizando:
# Convierte fichero de palabras no significativas (stop-words) en data frame
stop_words <- scan('datos/spanish.txt', what = "character", encoding = "UTF-8")
stop_words_spanish <- tibble(word = stop_words)
# Se eliminan palabras no significativas y otras rarezas
quijote_ordenado <- quijote %>%
# filter(!word %in% c("don", "Don", "á", "ó", "the")) %>% # quita rarezas
anti_join(stop_words_spanish) # quita lista de palabras no significativas
regenta_ordenado <- regenta %>%
anti_join(stop_words_spanish) # quita lista de palabras no significativasPara visualizar la lista de palabras más frecuentes he usado gráficos de barras estándar generados con el código siguiente:
rmax <- 20 # Considera las 20 palabras más frecuentes
df <- quijote_ordenado %>%
count(word, sort = TRUE) %>% # cuenta las frecuencias
mutate(word = reorder(word, n)) %>% # para ordenar según frecuencia en lugar de alfabéticamente
filter(row_number() <= rmax)
plot1 <- ggplot(df, aes(word, n)) +
geom_col(fill='lightblue') +
coord_flip() +
labs(title = "El Quijote",
x = NULL, y = NULL)
df <- regenta_ordenado %>%
count(word, sort = TRUE) %>% # cuenta las frecuencias
mutate(word = reorder(word, n)) %>% # para ordenar según frecuencia en lugar de alfabéticamente
filter(row_number() <= rmax)
plot2 <- ggplot(df, aes(word, n)) +
geom_col(fill='lightblue') +
coord_flip() +
labs(title = "La Regenta",
x = NULL, y = NULL)
plot1 + plot2
Tal vez debería haber quitado también los nombres de los personajes, lo que sería fácil modificando el código anterior, pero ya no he tenido ganas. El Quijote se publicó en 1605 (primera parte) y 1615 (segunda parte) mientras que La Regenta se publicó en dos tomos en 1884 y 1885. Me ha llamado la atención que, aunque hay más de 250 años de diferencia entre la publicación de ambas novelas y aunque hablan de personajes y entornos sociales muy distintos, hay algunas palabras comunes entre las más repetidas: señor, Dios, mundo, vida, casa, ojos.
Los mismos datos se pueden visualizar de formas diferentes en función de lo que se pretenda comunicar. Por ejemplo, según el contexto puede ser conveniente representar las palabras más frecuentes en forma de nube:
pal <- brewer.pal(9, "Set1")
quijote_ordenado %>%
count(word) %>%
with(wordcloud(
word, n, max.words = 50,
colors = pal))
pal <- brewer.pal(9, "Set1")
regenta_ordenado %>%
count(word) %>%
with(wordcloud(
word, n, max.words = 50,
colors = pal))
La ley de Zipf
El lingüista George Kingsley Zipf, al estudiar el vocabulario en la obra de James Joyce alrededor de 1935, describió una regularidad estadística: cuando hablamos o escribimos hay un conjunto pequeño de palabras que se repiten con una frecuencia muy alta mientras que hay un conjunto numeroso de palabras que usamos muy poco. Supongamos que ordenamos todas las palabras de un texto de más frecuente a menos (como hemos hecho antes pero sin quitar las palabras no significativas), entonces el rango de una palabra es el lugar que ocupa en la lista y lo que dice la ley de Zipf es que la frecuencia es (de forma aproximada) inversamente proporcional al rango:
\[\text{frecuencia} \approx \frac{a}{(\text{rango})^b},\ \ \ \text{con}\ \ \ b\approx 1.\] Esto significa que si tomamos logaritmos
\[\log(\text{frecuencia}) \approx \log(a) - b\log(\text{rango}),\] es decir, si representamos frecuencias y rangos de cada palabra en escala logarítmica deberíamos observar puntos aproximadamente alineados.
Veamos qué ocurre con los dos textos que estamos analizando en esta entrada. Para el Quijote tenemos:
df <- quijote %>%
count(word, sort = TRUE) %>%
mutate(rango = row_number(desc(n))) %>%
rename(frecuencia = n, palabra = word)
ggplot(df, aes(x = rango, y = frecuencia)) +
geom_point() +
scale_x_log10() + scale_y_log10() +
labs(x = "Rango", y = "Frecuencia",
title = "Frecuencia vs rango en El Quijote")
Los valores estimados de las constantes \(a\) y \(b\) son:
lm(log(frecuencia) ~ log(rango), data = df)
#>
#> Call:
#> lm(formula = log(frecuencia) ~ log(rango), data = df)
#>
#> Coefficients:
#> (Intercept) log(rango)
#> 11.885 -1.215Para La Regenta:
df <- regenta %>%
count(word, sort = TRUE) %>%
mutate(rango = row_number(desc(n))) %>%
rename(frecuencia = n, palabra = word)
ggplot(df, aes(x = rango, y = frecuencia)) +
geom_point() +
scale_x_log10() + scale_y_log10() +
labs(x = "Rango", y = "Frecuencia",
title = "Frecuencia vs rango en La Regenta")
Y la recta estimada es:
lm(log(frecuencia) ~ log(rango), data = df)
#>
#> Call:
#> lm(formula = log(frecuencia) ~ log(rango), data = df)
#>
#> Coefficients:
#> (Intercept) log(rango)
#> 11.290 -1.147Sí parece que las dos cimas de la literatura en castellano cumplen la ley de Zipf aproximadamente con valores de \(b\) similares y cercanos a uno.