--- title: "Tarea 9: Modelos locales y auditoría de equidad" subtitle: "IA para Científicos Sociales - UCU" author: "Danilo Freire" date: "2026-04-16" format: html: toc: true toc-depth: 2 number-sections: true code-fold: false lang: es engine: knitr --- ## Instrucciones Esta tarea aplica los conceptos del Laboratorio 9 a un caso [nuevo]{.alert}: respuestas abiertas de una encuesta sobre salud mental. Una encuesta preguntó a personas que dejaron de ir (o nunca fueron) a una consulta psicológica por qué no lo hicieron. Los relatos hablan de salud, así que son [datos sensibles]{.alert} según la Ley 18.331: no pueden salir de su máquina, y por eso toda la Parte A usa el modelo local. En la Parte B auditan la equidad de un modelo de crédito, como en el laboratorio, pero con otro modelo y otra pregunta. **Para trabajar en esta tarea:** 1. Descarguen este archivo `.qmd` y `consultas_salud_mental.csv` (en `clases/dia-05/datos/`) de la [página del curso](https://danilofreire.github.io/introduccion-ia-ucu/laboratorios.html), o clonen el repositorio con `git clone https://github.com/danilofreire/introduccion-ia-ucu.git`. Mantengan el CSV en una subcarpeta `datos/` junto al `.qmd` 2. Necesitan Quarto y RStudio (>= 2022.07) 3. Necesitan [Ollama](https://ollama.com/) corriendo y el modelo del laboratorio: `ollama pull granite4.1:3b` (~2,1 GB). [No hace falta ninguna API key]{.alert}: todo corre en su computadora 4. Instalar `quallmer` desde GitHub si aún no lo hicieron: `install.packages("pak"); pak::pak("quallmer/quallmer")`. Para la Parte B: `install.packages(c("fairmodels", "DALEX"))` 5. Abrir este archivo en RStudio y ejecutar los bloques con Ctrl+Enter ### Configuración ```{r setup, message=FALSE, warning=FALSE} library(ellmer) library(quallmer) library(tidyverse) set.seed(2026) # Ollama tiene que estar corriendo (abran la aplicación o `ollama serve`) consultas <- read_csv("datos/consultas_salud_mental.csv", show_col_types = FALSE) MODELO_LOCAL <- "ollama/granite4.1:3b" ``` ## Codificación con un modelo local ### Pregunta 1: Diseñar un codebook nominal Diseñen desde cero un codebook para clasificar el [motivo principal]{.alert} por el que cada persona no consultó, con las cinco categorías del CSV: `costo`, `estigma`, `desconfianza`, `falta_tiempo` y `autosuficiencia`. Definan cada categoría en las `instructions` e incluyan al menos [dos reglas de decisión]{.alert} para casos límite (por ejemplo: ¿qué hacer cuando un relato menciona la plata y la falta de tiempo a la vez?). Nombren el campo del schema `motivo`. *Pista:* el codebook del laboratorio es el molde, pero las definiciones y las reglas son de ustedes. Para categorías cerradas, `type_enum()`; el nivel es `"nominal"`. ```{r p1} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 2: Humano contra humano Antes de mirar al LLM: codifiquen ustedes. Elijan seis respuestas del corpus, léanlas y asígnenles una categoría [sin mirar la columna]{.alert} `motivo_humano`. Recién después comparen sus códigos con los del equipo: ¿en cuántas coinciden? ¿Dónde no, y por qué? El desacuerdo entre codificadores humanos también existe, y conviene conocerlo antes de exigirle perfección a un modelo. *Pista:* guarden sus códigos en un vector y comparen con `consultas$motivo_humano` en esas filas; `mean(sus_codigos == ...)` da la proporción de acuerdo. ```{r p2} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 3: Codificar con el modelo local y validar Codifiquen las 18 respuestas con el modelo local y validen contra el gold del equipo (`motivo_humano`) a nivel nominal. Reporten la accuracy y el kappa. Con la referencia del curso (kappa ≥ 0,7), ¿confiarían en este codificador? *Pista:* `max_active = 1` y `params(temperature = 0)`, como en el laboratorio. El gold se construye con `qlm_humancoded()` y necesita una columna `.id` y una columna con el mismo nombre que el campo del schema. ```{r p3} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 4: La tabla de confusión Una lista de desacuerdos dice dónde falló el modelo; una [tabla de confusión]{.alert} dice si los errores tienen un patrón. Crucen la categoría del modelo con la del gold y cuenten: ¿qué par de categorías se confunde más? Agreguen [una regla de decisión nueva]{.alert} al codebook para ese par, re-codifiquen y re-validen. ¿Mejoró? *Pista:* armen un tibble con las dos columnas y usen `count()`. Ojo con la interpretación: con 18 textos cada caso vale unos 5,6 puntos de accuracy, así que una mejora chica puede ser ruido. ```{r p4} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 5: ¿El modelo local es determinista? La sesión 5.1 promete reproducibilidad. Pónganla a prueba: vuelvan a codificar las 18 respuestas con el mismo modelo y comparen las dos corridas a nivel nominal. ¿El acuerdo es perfecto? Expliquen por qué `temperature = 0` ayuda pero no es una garantía absoluta. *Pista:* `qlm_replicate()` repite una codificación existente (la Tarea 8 hizo lo mismo en la nube); `qlm_compare()` mide el acuerdo entre las dos corridas. ```{r p5} # Escriban su código aquí ``` **Respuesta:** ## Auditoría de equidad ### Pregunta 6: Regresión logística y fairness_check() En el laboratorio auditaron un clasificador de crédito con `fairmodels`; acá repiten esa auditoría y, en la pregunta 7, la llevan un paso más allá con un análisis [interseccional]{.alert}. Entrenen una [regresión logística]{.alert} sobre German Credit ([sin usar]{.alert} `Sex` como predictor), creen el explicador de DALEX y corran `fairness_check()` con `Sex` como atributo protegido. Para simplificar, entrenen y auditen sobre el dataset completo (en una auditoría real usarían datos de test, como en el laboratorio). ¿El modelo pasa la regla del 80%? ¿En qué métricas falla? *Pista:* quiten `Risk` y `Sex` del data frame antes de ajustar y usen `glm(Risk_binary ~ ., ..., family = binomial)`; así la fórmula no menciona esas columnas y `DALEX::explain()` puede predecir sobre los mismos datos sin ellas. `explain()` necesita el modelo, los datos (sin `Risk_binary`) y la `y` binaria. ```{r p6} # Escriban su código aquí ``` **Respuesta:** ### Pregunta 7: Auditoría interseccional El sesgo puede esconderse en las [intersecciones]{.alert}: un modelo puede tratar bien a "las mujeres" y a "los jóvenes" en promedio, y aun así tratar mal a las mujeres jóvenes. Creen una variable que combine sexo y edad en cuatro grupos (`hombre_joven`, `hombre_mayor`, `mujer_joven`, `mujer_mayor`, con corte en 35 años), corran `fairness_check()` con esos cuatro grupos e identifiquen el más perjudicado. ¿Ese resultado se veía en la auditoría por sexo de la pregunta 6? *Pista:* `paste()` combina las dos variables; `privileged` puede ser `"hombre_mayor"`. El gráfico de `plot()` ayuda a ver qué grupo queda fuera de la zona verde. ```{r p7} # Escriban su código aquí ``` **Respuesta:** ## Reflexión ### Pregunta 8: El párrafo para el comité de ética El equipo de la Parte A quiere procesar las respuestas en su propia máquina en lugar de enviarlas a una API en la nube. Escriban el párrafo (máximo doscientas palabras) que presentarían al comité de ética para justificar esa decisión. Incluir: por qué los relatos sobre salud mental son datos sensibles según la Ley 18.331, qué riesgo concreto evita el procesamiento local y qué control adicional implementarían de todos modos. **Respuesta:** ### Pregunta 9: Recomendación al regulador Imaginen que asesoran a un regulador financiero que va a exigir una métrica de equidad para los modelos de scoring crediticio. Recomendar [una]{.alert} (paridad demográfica, igualdad de oportunidades o calibración), justificar por qué y explicar qué se pierde al elegirla, citando el teorema de imposibilidad. Máximo doscientas palabras. **Respuesta:**