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"Tarea 9: Modelos locales y auditoría de equidad
IA para Científicos Sociales - UCU
1 Instrucciones
Esta tarea aplica los conceptos del Laboratorio 9 a un caso nuevo: 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 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:
- Descarguen este archivo
.qmdyconsultas_salud_mental.csv(enclases/dia-05/datos/) de la página del curso, o clonen el repositorio congit clone https://github.com/danilofreire/introduccion-ia-ucu.git. Mantengan el CSV en una subcarpetadatos/junto al.qmd - Necesitan Quarto y RStudio (>= 2022.07)
- Necesitan Ollama corriendo y el modelo del laboratorio:
ollama pull granite4.1:3b(~2,1 GB). No hace falta ninguna API key: todo corre en su computadora - Instalar
quallmerdesde GitHub si aún no lo hicieron:install.packages("pak"); pak::pak("quallmer/quallmer"). Para la Parte B:install.packages(c("fairmodels", "DALEX")) - Abrir este archivo en RStudio y ejecutar los bloques con Ctrl+Enter
1.1 Configuración
2 Codificación con un modelo local
2.1 Pregunta 1: Diseñar un codebook nominal
Diseñen desde cero un codebook para clasificar el motivo principal 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 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".
# Escriban su código aquíRespuesta:
2.2 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 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.
# Escriban su código aquíRespuesta:
2.3 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.
# Escriban su código aquíRespuesta:
2.4 Pregunta 4: La tabla de confusión
Una lista de desacuerdos dice dónde falló el modelo; una tabla de confusión 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 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.
# Escriban su código aquíRespuesta:
2.5 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.
# Escriban su código aquíRespuesta:
3 Auditoría de equidad
3.1 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. Entrenen una regresión logística sobre German Credit (sin usar 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.
# Escriban su código aquíRespuesta:
3.2 Pregunta 7: Auditoría interseccional
El sesgo puede esconderse en las intersecciones: 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.
# Escriban su código aquíRespuesta:
4 Reflexión
4.1 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:
4.2 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 (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: