Los datos analizados provienen del archivo
tabla_archivos_juve.xlsx, ubicado en la ruta
C:\Users\Usuario\Downloads\.
El dataset contiene información textual en español, estructurada en las siguientes columnas principales:
Los datos se obvtuvieron con técnicas de web scraping, guardados en un archivo Excel para su análisis posterior.
# Librerías necesarias para el análisis
library(tm) # Minería de texto
library(topicmodels) # Modelado de tópicos
library(tidytext) # Análisis de texto tidy
library(tidyverse) # Manipulación de datos
library(readxl) # Lectura de archivos Excel
library(rebus) # Expresiones regulares
library(udpipe) # Procesamiento de lenguaje natural
library(ggwordcloud) # Nubes de palabras
library(igraph) # Análisis de redes
library(ggraph) # Visualización de grafos
library(widyr) # Correlaciones entre palabras
# Lectura del archivo Excel
ruta_archivo <- "C:/Users/Usuario/Downloads/tabla_archivos_juve.xlsx"
articulos_juve <- read_excel(ruta_archivo) %>%
select(titulos, textos) %>%
mutate(id = 1:nrow(.)) %>%
relocate(id, .before = titulos)
# Visualización de las primeras filas
head(articulos_juve, 3)
# Estadísticas básicas
cat("Total de documentos:", nrow(articulos_juve), "\n")
## Total de documentos: 110
cat("Longitud promedio de textos:",
mean(nchar(articulos_juve$textos), na.rm = TRUE), "caracteres\n")
## Longitud promedio de textos: 7291.764 caracteres
Todas las palabras fueron convertidas a minúsculas para estandarizar el análisis y evitar que palabras iguales pero con diferentes capitalizaciones se consideren distintas.
Removí os signos de puntuación (puntos, comas, comillas, paréntesis, etc.) para que el codigo logre enfocarse solo en las palabras.
Removí palabras comunes en español que no aportan significado semántico relevante y se utilizan mas como nexos , tales como: - Preposiciones: de, en, a, por, para, con - Artículos: el, la, los, las, un, una - Conjunciones: y, o, pero, ni - Pronombres: él, ella, nosotros, ustedes
aqui agrupamos términos frecuentes en tokens únicos para preservar su significado conjunto: - redes sociales → redes_sociales - medio comunicación → medio_comunicacion - inteligencia artificial → inteligencia_artificial - nativo digital → nativo_digital
Basado en el análisis exploratorio eliminé palabras de alta frecuencia pero bajo contenido informativo: - Verbos auxiliares: hacer, poder - Adverbios genéricos: bien, solo, cada - Referencias temporales: año, primero - Adjetivos genéricos: mayor
# Carga de stop words en español
stop_words <- stopwords(kind = "spanish")
stopwords_2 <- str_c("\\b", stop_words, "\\b")
# Limpieza y transformación del texto
articulos_juve2 <- articulos_juve %>%
mutate(textos = str_to_lower(textos)) %>%
mutate(textos = str_remove_all(textos, pattern = "[:punct:]")) %>%
mutate(textos = str_remove_all(textos, c(or1(stopwords_2)))) %>%
mutate(textos = str_replace_all(textos, c(
"redes sociales" = "redes_sociales",
"medio comunicación" = "medio_comunicacion",
"medios comunicación" = "medio_comunicacion",
"nativo digital" = "nativo_digital",
"nativos digitales" = "nativo_digital",
"inteligencia artificial" = "inteligencia_artificial",
"ia" = "inteligencia_artificial",
"nuevo león" = "nuevo_león",
"ciudad méxico" = "ciudad_de_méxico",
"jornada laboral" = "jornada_laboral",
"manolo jiménez" = "manolo_jiménez",
"población económicamente activa" = "población_económicamente_activa",
"red social" = "redes_sociales"
))) %>%
mutate(textos = str_squish(textos))
# Muestra del texto procesado
cat("Ejemplo de texto procesado:\n")
## Ejemplo de texto procesado:
cat(substr(articulos_juve2$textos[1], 1, 300), "...\n")
## idea máquina proporcione terapinteligencia_artificial psicológica nueva primeros intentos programas computadora fin datan 1966 programa eliza mit pasando cognisoft noventa beating the blues 2000 diversos intentos machinelearning procesamiento lenguaje natural últimos 10 años llegar época actual gran ...
# Descarga y carga del modelo de español
# Verificar si el modelo ya existe, si no, descargarlo
modelo_path <- "spanish-gsd-ud-2.5-191206.udpipe"
if (!file.exists(modelo_path)) {
cat("Descargando modelo de español...\n")
modelo <- udpipe_download_model(language = "spanish")
modelo_path <- modelo$file_model
cat("Modelo descargado en:", modelo_path, "\n")
}
# Cargar el modelo
udmodel <- udpipe_load_model(file = modelo_path)
# Lematización y etiquetado morfológico
lemas_juve <- udpipe_annotate(udmodel, x = articulos_juve2$textos) %>%
as_tibble() %>%
mutate(id = str_extract(doc_id, pattern = "\\d+")) %>%
select(id, token, lemma, upos) %>%
filter(upos != "PUNCT") %>%
mutate(is.number = str_detect(lemma, pattern = "\\d")) %>%
filter(!is.number) %>%
filter(!(lemma %in% c("él", "hacer", "coahuila",
"méxico", "poder", "primero", "mayor", "año",
"bien", "cada", "solo", "dar", "deber", "ver",
"decir", "ir", "haber", "ser", "estar")))
# Visualización de la estructura de datos lematizados
head(lemas_juve, 10)
# Cálculo de frecuencias
terminos_frecuentes <- lemas_juve %>%
count(lemma, sort = TRUE) %>%
top_n(20, n)
# Tabla de los 20 términos más frecuentes
knitr::kable(
terminos_frecuentes,
col.names = c("Término", "Frecuencia"),
caption = "Los 20 términos más frecuentes en el corpus"
)
| Término | Frecuencia |
|---|---|
| país | 444 |
| nacional | 388 |
| coahuilo | 340 |
| nivel | 303 |
| población | 269 |
| persona | 244 |
| entidad | 235 |
| dato | 233 |
| gobierno | 220 |
| información | 218 |
| acceso | 206 |
| nuevo | 201 |
| si | 198 |
| tasa | 198 |
| manera | 196 |
| mil | 188 |
| caso | 187 |
| mexicano | 187 |
| local | 184 |
| ciudad | 179 |
| mujer | 179 |
terminos_frecuentes %>%
mutate(lemma = reorder(lemma, n)) %>%
ggplot(aes(x = lemma, y = n, fill = n)) +
geom_col(show.legend = FALSE) +
scale_fill_gradient(low = "#3498db", high = "#e74c3c") +
coord_flip() +
labs(
title = "Los 20 Términos Más Frecuentes",
subtitle = "Análisis de frecuencia en el corpus de textos",
x = "Término (Lema)",
y = "Frecuencia"
) +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(size = 10, color = "gray40"),
axis.text.y = element_text(size = 9)
)
Frecuencia de los 20 términos más utilizados
Interpretación: Aquí se muestra con más precisión cuántas veces aparece cada término. Por ejemplo, “país” tiene la frecuencia más alta, seguido de “nacional” y “coahuilo”. Esta gráfica me permitió entender mejor la importancia relativa de cada palabra y ver que el enfoque del corpus está muy relacionado con temas territoriales, población y gobierno.
set.seed(123)
lemas_juve %>%
count(lemma) %>%
top_n(50, n) %>%
ggplot(aes(label = lemma, size = n, color = n)) +
geom_text_wordcloud_area(
rm_outside = TRUE,
eccentricity = 1
) +
scale_size_area(max_size = 15) +
scale_color_gradient(low = "#3498db", high = "#e74c3c") +
theme_minimal() +
labs(title = "Nube de Palabras - Top 50 Términos")
Nube de palabras de los términos más frecuentes
Interpretación: Esta nube de palabras me ayudó a ver de forma rápida cuáles son los términos que más se repiten en el corpus. Las palabras más grandes como “país”, “nivel” y “nacional” destacan porque aparecen muchas veces en los textos. Es una forma visual muy útil para identificar los temas principales sin tener que leer todo el contenido
# Cálculo de correlaciones de palabras que aparecen juntas
palabra_correlaciones <- lemas_juve %>%
group_by(lemma) %>%
filter(n() >= 10) %>%
pairwise_cor(lemma, id, sort = TRUE)
# Top 30 correlaciones
top_correlaciones <- palabra_correlaciones %>%
head(30)
knitr::kable(
top_correlaciones,
col.names = c("Término 1", "Término 2", "Correlación"),
caption = "Top 30 pares de términos con mayor correlación",
digits = 3
)
| Término 1 | Término 2 | Correlación |
|---|---|---|
| nivel | programa | Inf |
| nacional | programa | Inf |
| nivel | digital | Inf |
| nacional | digital | Inf |
| nivel | servir | Inf |
| nacional | servir | Inf |
| nivel | recordar | Inf |
| nacional | recordar | Inf |
| nivel | estudio | Inf |
| nacional | estudio | Inf |
| nivel | forma | Inf |
| nacional | forma | Inf |
| nivel | usar | Inf |
| nacional | usar | Inf |
| nivel | actualmente | Inf |
| nacional | actualmente | Inf |
| nivel | respuesta | Inf |
| nacional | respuesta | Inf |
| nivel | tecnología | Inf |
| nacional | tecnología | Inf |
| nivel | medir | Inf |
| nacional | medir | Inf |
| nivel | significativamente | Inf |
| nacional | significativamente | Inf |
| nivel | depresión | Inf |
| nacional | depresión | Inf |
| nivel | aplicación | Inf |
| nacional | aplicación | Inf |
| nivel | significativo | Inf |
| nacional | significativo | Inf |
# Seleccionar los 20 términos más frecuentes
top_20_terminos <- terminos_frecuentes$lemma
# Calcular correlaciones para los top 20
correlaciones_top20 <- lemas_juve %>%
filter(lemma %in% top_20_terminos) %>%
pairwise_cor(lemma, id, sort = TRUE) %>%
filter(correlation > 0.15)
# Tabla de correlaciones significativas
knitr::kable(
head(correlaciones_top20, 20),
col.names = c("Término 1", "Término 2", "Correlación"),
caption = "Correlaciones significativas entre los 20 términos más frecuentes",
digits = 3
)
| Término 1 | Término 2 | Correlación |
|---|---|---|
| población | nivel | Inf |
| población | nacional | Inf |
| nivel | población | Inf |
| nacional | población | Inf |
| información | acceso | 1.000 |
| acceso | información | 1.000 |
| local | manera | 1.000 |
| manera | local | 1.000 |
| manera | acceso | 0.572 |
| local | acceso | 0.572 |
| manera | coahuilo | 0.572 |
| local | coahuilo | 0.572 |
| manera | información | 0.572 |
| local | información | 0.572 |
| acceso | manera | 0.572 |
| coahuilo | manera | 0.572 |
| información | manera | 0.572 |
| acceso | local | 0.572 |
| coahuilo | local | 0.572 |
| información | local | 0.572 |
set.seed(123)
# Crear red de relaciones con validación estricta
red_datos <- lemas_juve %>%
filter(lemma %in% top_20_terminos) %>%
pairwise_count(lemma, id, sort = TRUE) %>%
filter(n >= 5) %>%
filter(!is.na(item1) & !is.na(item2)) %>%
filter(is.finite(n)) %>%
mutate(weight = n)
# Crear y visualizar red
if (nrow(red_datos) > 0) {
red_palabras <- graph_from_data_frame(red_datos, directed = FALSE)
ggraph(red_palabras, layout = "fr") +
geom_edge_link(
alpha = 0.6,
width = 1,
edge_colour = "steelblue"
) +
geom_node_point(size = 8, color = "#e74c3c") +
geom_node_text(
aes(label = name),
repel = TRUE,
size = 3.5,
fontface = "bold"
) +
theme_void() +
labs(
title = "Red de Co-ocurrencia de Términos",
subtitle = "Términos que aparecen frecuentemente juntos en los mismos documentos"
) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, color = "#00008B", hjust = 0.5)
)
} else {
cat("No hay suficientes co-ocurrencias para generar la red")
}
Red de relaciones entre los términos más frecuentes
Interpretación: Esta red muestra cómo ciertos nombres aparecen juntos frecuentemente. Me parece que podría estar relacionada con personas mencionadas en los textos, como si fueran parte de un grupo o comunidad. Ver los vínculos entre ellas me ayudó a imaginar cómo se conectan los temas o actores dentro del corpus
set.seed(456)
# Crear red de correlaciones con validación
red_cor_datos <- correlaciones_top20 %>%
filter(correlation > 0.2) %>%
filter(!is.na(item1) & !is.na(item2)) %>%
filter(is.finite(correlation)) %>%
mutate(cor_norm = scales::rescale(correlation, to = c(0.5, 3)))
# Crear y visualizar red
if (nrow(red_cor_datos) > 0) {
red_correlacion <- graph_from_data_frame(red_cor_datos, directed = FALSE)
ggraph(red_correlacion, layout = "stress") +
geom_edge_link(
aes(alpha = cor_norm, width = cor_norm),
edge_colour = "#27ae60",
show.legend = FALSE
) +
geom_node_point(size = 10, color = "#7FFFD4") +
geom_node_text(
aes(label = name),
repel = TRUE,
size = 3.5,
color = "#00008B",
fontface = "bold"
) +
theme_void() +
labs(
title = "Red de Correlaciones entre Términos",
subtitle = "Términos con correlación > 0.2"
) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, color = "gray40", hjust = 0.5)
)
} else {
cat("No hay suficientes correlaciones para generar la red")
}
Red de correlaciones entre términos
Interpretación: Esta gráfica me pareció interesante porque separa dos grupos de países: uno de Sudamérica y otro de Centroamérica. Las conexiones entre ellos podrían representar relaciones políticas, sociales o económicas. Me ayudó a ver cómo se agrupan los países en función de sus vínculos, lo cual podría ser útil para entender dinámicas regionales.
# Seleccionar algunos términos clave para análisis
terminos_clave <- top_20_terminos[1:5]
# Encontrar términos correlacionados con cada término clave
contexto_detallado <- palabra_correlaciones %>%
filter(item1 %in% terminos_clave) %>%
group_by(item1) %>%
top_n(10, correlation) %>%
ungroup()
# Visualización
ggplot(contexto_detallado, aes(x = reorder(item2, correlation),
y = correlation,
fill = item1)) +
geom_col(show.legend = TRUE) +
facet_wrap(~item1, scales = "free_y", ncol = 1) +
coord_flip() +
scale_fill_brewer(palette = "Set2") +
labs(
title = "Términos Más Correlacionados con Palabras Clave",
x = "Término Relacionado",
y = "Correlación",
fill = "Término Clave"
) +
theme_minimal() +
theme(
strip.text = element_text(face = "bold", size = 11),
legend.position = "none"
)
Términos más correlacionados con palabras clave específicas
Interpretación: Este panel múltiple muestra, para cada uno de los términos más frecuentes, cuáles son las palabras con las que más frecuentemente co-ocurrente. lo que me permitio entender el contexto específico de cada término clave y sus asociaciones más fuertes.
El análisis msotro que “país” es el concepto más discutido, seguido de “nacional” y “coahuilo”.Lo que sugiere que el corpus se centra principalmente en temas relacionados con la estructura territorial y administrativa de México, así como aspectos demográficos y gubernamentales.
La red de co-ocurrencias identifica varios clusters temáticos:
El análisis de correlaciones mostro asociaciones significativas entre términos que no necesariamente aparecen juntos frecuentemente, pero que comparten contextos semánticos similares. Por ejemplo: “información” y “acceso” muestran una correlación perfecta de 1, sugiriendo una fuerte relación entre disponibilidad de datos y acceso ciudadano. local” y “manera” tienen una correlación de 0.9999, lo que indica que los textos vinculan fuertemente el enfoque local con formas específicas de implementación o análisis. “población” y “nivel” presentan una correlación infinita, lo que sugiere que estos términos aparecen sistemáticamente juntos, posiblemente en contextos estadísticos o comparativos.
La agrupación de términos multipalabra (como “redes_sociales” e “inteligencia_artificial”) fue crucial para preservar significados complejos que se perderían en un análisis palabra por palabra.
Los resultados de este análisis tienen varias implicaciones:
Temáticas Principales: El corpus muestra un enfoque claro en la estructura nacional y territorial, con un énfasis particular en la población y el acceso a servicios.
Evolución Conceptual: Las relaciones entre términos sugieren una tendencia hacia la integración de datos demográficos con políticas de acceso e información pública.
Áreas de Interés: Los clusters identificados indican áreas de interés distintas que podrían ser objeto de análisis más profundos, como gobernanza territorial y equidad en el acceso a servicios.
Este análisis me ayudó a entender cómo los datos pueden revelar patrones y relaciones entre conceptos; ademas usar gráficas como la nube de palabras y las redes de co-ocurrencia me permitió identificar temas clave y conexiones relevantes. Entonces si combinamos técnicas como el análisis de frecuencias, la lematización y el análisis de redes, logramos una comprensión mucho más rica de todo el contenido lo que nos ayuda a identificar los temas principales y, a la vez, a descubrir esas conexiones ocultas o más sutiles entre las ideas.
sessionInfo()
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26100)
##
## Matrix products: default
## LAPACK version 3.12.1
##
## locale:
## [1] LC_COLLATE=Spanish_Mexico.utf8 LC_CTYPE=Spanish_Mexico.utf8
## [3] LC_MONETARY=Spanish_Mexico.utf8 LC_NUMERIC=C
## [5] LC_TIME=Spanish_Mexico.utf8
##
## time zone: America/Mexico_City
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] widyr_0.1.5 ggraph_2.2.2 igraph_2.2.0 ggwordcloud_0.6.2
## [5] udpipe_0.8.12 rebus_0.1-3 readxl_1.4.5 lubridate_1.9.4
## [9] forcats_1.0.1 stringr_1.5.2 dplyr_1.1.4 purrr_1.1.0
## [13] readr_2.1.5 tidyr_1.3.1 tibble_3.3.0 ggplot2_4.0.0
## [17] tidyverse_2.0.0 tidytext_0.4.3 topicmodels_0.2-17 tm_0.7-16
## [21] NLP_0.3-2
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.2.1 viridisLite_0.4.2 farver_2.1.2
## [4] viridis_0.6.5 S7_0.2.0 fastmap_1.2.0
## [7] tweenr_2.0.3 janeaustenr_1.0.0 digest_0.6.37
## [10] timechange_0.3.0 lifecycle_1.0.4 tokenizers_0.3.0
## [13] magrittr_2.0.4 compiler_4.5.1 rlang_1.1.6
## [16] sass_0.4.10 tools_4.5.1 yaml_2.3.10
## [19] data.table_1.17.8 knitr_1.50 labeling_0.4.3
## [22] graphlayouts_1.2.2 plyr_1.8.9 xml2_1.4.0
## [25] RColorBrewer_1.1-3 withr_3.0.2 grid_4.5.1
## [28] polyclip_1.10-7 stats4_4.5.1 colorspace_2.1-2
## [31] rebus.base_0.0-3 scales_1.4.0 MASS_7.3-65
## [34] cli_3.6.5 rmarkdown_2.30 generics_0.1.4
## [37] rstudioapi_0.17.1 reshape2_1.4.4 tzdb_0.5.0
## [40] commonmark_2.0.0 cachem_1.1.0 ggforce_0.5.0
## [43] modeltools_0.2-24 rebus.datetimes_0.0-2 parallel_4.5.1
## [46] cellranger_1.1.0 vctrs_0.6.5 Matrix_1.7-3
## [49] jsonlite_2.0.0 slam_0.1-55 litedown_0.7
## [52] hms_1.1.3 ggrepel_0.9.6 rebus.unicode_0.0-2.1
## [55] jquerylib_0.1.4 glue_1.8.0 stringi_1.8.7
## [58] gtable_0.3.6 pillar_1.11.1 htmltools_0.5.8.1
## [61] rebus.numbers_0.0-1.1 R6_2.6.1 tidygraph_1.3.1
## [64] evaluate_1.0.5 lattice_0.22-7 markdown_2.0
## [67] png_0.1-8 backports_1.5.0 SnowballC_0.7.1
## [70] gridtext_0.1.5 memoise_2.0.1 broom_1.0.10
## [73] bslib_0.9.0 Rcpp_1.1.0 gridExtra_2.3
## [76] xfun_0.53 pkgconfig_2.0.3