--- title: "Tarea 6: Análisis de texto" subtitle: "IA para Científicos Sociales - UCU" author: "Danilo Freire" date: "2026-04-24" format: html: toc: true toc-depth: 2 number-sections: true code-fold: false lang: es engine: knitr --- ## Instrucciones Esta tarea usa el mismo corpus del Laboratorio 6 (`textos_politicos.csv`): 60 textos políticos simulados sobre 5 temas, 18 países y 7 años. Respondan cada pregunta escribiendo código R en los bloques indicados. Cuando se pida una respuesta escrita, usen texto normal debajo del bloque de código. **Para trabajar en esta tarea:** 1. Descarguen este archivo `.qmd` y el dataset `textos_politicos.csv` de la [página del curso](https://danilofreire.github.io/introduccion-ia-ucu/laboratorios.html), o clonen el repositorio completo con `git clone https://github.com/danilofreire/introduccion-ia-ucu.git` 2. Necesitan [Quarto](https://quarto.org/docs/get-started/) instalado junto con RStudio 3. Abran este archivo `.qmd` en RStudio y ejecuten los bloques de código con Ctrl+Enter (o Cmd+Enter en Mac) 4. Cuando terminen, pueden renderizar el documento completo con el botón "Render" en RStudio ### Configuración ```{r setup, message=FALSE, warning=FALSE} library(tidyverse) library(tidytext) library(tm) set.seed(2026) textos <- read_csv("datos/textos_politicos.csv", show_col_types = FALSE) # Tokenización y limpieza (reutilizadas en varias preguntas) stopwords_es <- tibble(palabra = tm::stopwords("spanish")) tokens <- textos |> unnest_tokens(palabra, texto) tokens_limpios <- tokens |> anti_join(stopwords_es, by = "palabra") |> filter(!str_detect(palabra, "^[0-9]+$"), nchar(palabra) > 2) ``` ## Exploración ### Pregunta 1: Distribución por año Cuenten cuántos textos hay por año y visualicen el resultado en un gráfico de barras. ¿Algún año tiene muchos más textos que otros? ```{r p1} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 2: Longitud de los textos Calculen el número de palabras (tokens, sin limpiar stopwords) de cada texto. ¿Cuál es el texto más corto y el más largo? Muestren su contenido. *Pista:* después de `unnest_tokens()`, agrupen por `id` y cuenten filas. ```{r p2} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 3: Bigramas más frecuentes Tokenicen el corpus original en **bigramas** (pares consecutivos de palabras) usando `unnest_tokens(..., token = "ngrams", n = 2)`. Identifiquen los 10 bigramas más frecuentes después de filtrar aquellos donde alguna de las dos palabras sea stopword. *Pista:* después de generar bigramas, sepárenlos en dos columnas con `separate(palabra_par, c("palabra1", "palabra2"), sep = " ")`, filtren stopwords en ambas columnas, y vuelvan a unirlas. ```{r p3} # Escriban su código aquí ``` **Respuesta:** ## TF-IDF ### Pregunta 4: Frecuencia bruta vs. TF-IDF Calculen las 10 palabras más frecuentes de todo el corpus (conteo bruto sobre `tokens_limpios`) y, por separado, las 3 palabras más distintivas de cada tema según TF-IDF. ¿Qué palabras dominan la lista por frecuencia bruta pero no aparecen como distintivas en TF-IDF? ¿Por qué? ```{r p4} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 5: ¿Cuándo informa el TF-IDF por grupo? Calculen TF-IDF agrupando por `anio` y miren las 3 palabras más distintivas de cada año. ¿Cuentan una historia temporal coherente (por ejemplo, un "año de la pandemia" con vocabulario sanitario), o son palabras sueltas sin patrón? Comparen con el TF-IDF por tema. ¿Qué condición debe cumplir una variable de agrupamiento para que el TF-IDF revele una señal interpretable? *Pista:* es el mismo patrón que el TF-IDF por tema, cambiando `tema` por `anio` en `count()` y `bind_tf_idf()`. ```{r p5} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 6: TF-IDF de bigramas Combinen las técnicas de las Preguntas 3 y 4: calculen el TF-IDF de los [bigramas]{.alert} (ya filtrados de stopwords) agrupando por tema, y muestren los 3 bigramas más distintivos de cada tema. Comparen con las palabras sueltas de la Pregunta 4: ¿los bigramas son más fáciles de interpretar? ¿Qué limitación aparece al usar bigramas en un corpus tan chico? *Pista:* es el mismo `bind_tf_idf()` de siempre, pero la unidad ahora es el bigrama, no la palabra. `slice_max(..., with_ties = FALSE)` evita que los empates llenen la tabla. ```{r p6} # Escriban su código aquí ``` **Respuesta:** ## Sentimiento ### Pregunta 7: Ampliar diccionarios Construyan diccionarios de palabras positivas y negativas con al menos **30 palabras cada uno**. Pueden basarse en los diccionarios del laboratorio y agregar palabras relevantes para texto político en español (busquen patrones en los datos: ¿qué palabras parecen claramente positivas/negativas?). *Pista:* exploren las palabras más frecuentes en `tokens_limpios` y vean cuáles tienen carga emocional clara. ```{r p7} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 8: Sentimiento por país Calculen el score promedio de sentimiento por país. ¿Qué países tienen el tono más negativo en promedio? ¿Coincide con países que pasan por crisis (Venezuela, Argentina con inflación, etc.)? *Pista:* `case_when()` para asignar valencia + `group_by(pais) |> summarise(score_promedio = mean(score))`. ```{r p8} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 9: El documento más positivo Identifiquen el documento con el score de sentimiento más positivo. Léanlo. ¿El método capta bien su tono? ¿Hay palabras positivas que el método NO está contando? ```{r p9} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 10: Heatmap de sentimiento por tema y año Construyan una tabla cruzada de score promedio de sentimiento por tema y año. Visualicen como heatmap (`geom_tile`). ¿Hay temas que se vuelven más negativos con el tiempo, o más positivos? ```{r p10} # Escriban su código aquí ``` **Respuesta:** ## Síntesis ### Pregunta 11: Clasificador por palabras clave Construyan un clasificador simple por diccionario de palabras clave: para cada tema, definan 5-10 palabras "ancla" y asignen a cada texto el tema con más palabras-ancla presentes. Comparen con el tema real (matriz de confusión). ¿Qué accuracy obtienen? *Pista:* la [clase 10](10-analisis-texto.html#sec:apendice-caso) tiene un ejemplo cercano ("Caso integrado"). ```{r p11} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 12: TF-IDF + sentimiento Conecten el TF-IDF por tema (pregunta 6 y laboratorio) con el sentimiento por tema: ¿los temas cuyo vocabulario distintivo es más negativo (por ejemplo, seguridad) son también los de score de sentimiento más bajo? ¿Se sostiene la misma relación a nivel de país (pregunta 8)? Comenten en 3-5 oraciones. **Respuesta:** ### Pregunta 13: Reflexión Basándose en los resultados, respondan: 1. ¿Cuándo conviene usar TF-IDF y cuándo análisis de sentimiento? Den un ejemplo concreto de pregunta de investigación para cada uno 2. ¿Cuáles son las dos limitaciones más serias del análisis de sentimiento por diccionario? ¿Cómo las mitigarían con más recursos? 3. ¿Cuándo NO usarían estos métodos clásicos (TF-IDF, diccionarios) y preferirían un LLM (que veremos en el día 4)? **Respuesta:**