Tarea 2: Comparación de modelos – Respuestas

IA para Científicos Sociales - UCU

Autor/a

Danilo Freire

Fecha de publicación

12 de abril de 2026

1 Instrucciones

Esta es la clave de respuestas de la Tarea 2. Cada pregunta incluye el código R completo y una respuesta escrita.

1.1 Configuración

library(tidymodels)
library(tidyverse)

satisfaccion <- read_csv("datos/satisfaccion_democracia.csv")
# Lean el archivo directo desde la web:
# satisfaccion <- read_csv("https://raw.githubusercontent.com/danilofreire/introduccion-ia-ucu/main/clases/dia-01/datos/satisfaccion_democracia.csv")

satisfaccion <- satisfaccion |>
  mutate(
    satisfecho = factor(satisfecho, levels = c("no", "si")),
    zona = factor(zona),
    genero = factor(genero),
    pais = factor(pais)
  )

2 Exploración

2.1 Pregunta 1: Resumen del dataset

Calculen la proporción de satisfechos ("si") por país. ¿Cuál país tiene la proporción más alta? ¿Cuál tiene la más baja?

prop_pais <- satisfaccion |>
  count(pais, satisfecho) |>
  group_by(pais) |>
  mutate(prop = round(n / sum(n), 3)) |>
  filter(satisfecho == "si") |>
  arrange(desc(prop))

prop_pais
# A tibble: 18 × 4
# Groups:   pais [18]
   pais                 satisfecho     n  prop
   <fct>                <fct>      <int> <dbl>
 1 México               si            17 0.895
 2 El Salvador          si            23 0.852
 3 Honduras             si            23 0.852
 4 Costa Rica           si            26 0.812
 5 Brasil               si            17 0.81 
 6 Ecuador              si            12 0.8  
 7 Uruguay              si            24 0.774
 8 Paraguay             si            16 0.696
 9 Nicaragua            si            22 0.688
10 Venezuela            si            26 0.684
11 Argentina            si            17 0.68 
12 República Dominicana si            20 0.667
13 Colombia             si            17 0.654
14 Perú                 si            17 0.654
15 Panamá               si            24 0.632
16 Chile                si            19 0.594
17 Bolivia              si            16 0.571
18 Guatemala            si            17 0.567

Respuesta: México tiene la proporción más alta de satisfechos (~0.90) y Guatemala la más baja (~0.57). La proporción varía bastante entre países, lo cual refleja las diferencias en los factores subyacentes (confianza en el gobierno, educación, etc.) en cada país. Las diferencias entre países son en parte producto de la simulación aleatoria, pero se observa variabilidad que podría existir en datos reales de Latinobarómetro.

2.2 Pregunta 2: Confianza y satisfacción

Creen un boxplot que muestre la distribución de confianza_gobierno separada por satisfecho.

ggplot(satisfaccion, aes(x = satisfecho, y = confianza_gobierno, fill = satisfecho)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_manual(values = c("#e74c3c", "#27ae60")) +
  labs(
    title = "Confianza en el gobierno por nivel de satisfacción",
    x = "Satisfecho con la democracia",
    y = "Confianza en el gobierno (1-10)"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

Respuesta: Los encuestados satisfechos con la democracia tienden a tener mayor confianza en el gobierno. La mediana de confianza es visiblemente más alta en el grupo satisfecho. Esto tiene sentido: quien confía más en el gobierno probablemente evalúa mejor el funcionamiento de la democracia.

2.3 Pregunta 3: Correlaciones

Calculen la matriz de correlaciones entre las 4 variables numéricas principales.

mat_cor <- satisfaccion |>
  select(edad, educacion_anos, ingreso_hogar, confianza_gobierno) |>
  cor() |>
  round(3)

mat_cor
                     edad educacion_anos ingreso_hogar confianza_gobierno
edad                1.000          0.012         0.030             -0.009
educacion_anos      0.012          1.000        -0.035             -0.077
ingreso_hogar       0.030         -0.035         1.000             -0.082
confianza_gobierno -0.009         -0.077        -0.082              1.000

Respuesta: Las correlaciones entre estas variables son muy débiles (todos los valores absolutos por debajo de 0.1). Esto indica que cada variable aporta información casi independiente, lo cual es bueno para un modelo de regresión: prácticamente no hay multicolinealidad. En una encuesta de opinión como esta, no sorprende que edad, educación, ingreso y confianza apenas se correlacionen entre sí.

3 Feature engineering

3.1 Pregunta 4: Crear variables nuevas

satisfaccion <- satisfaccion |>
  mutate(
    confianza_baja = if_else(confianza_gobierno <= 4, "si", "no"),
    joven = if_else(edad < 30, "si", "no"),
    ingreso_x_educacion = ingreso_hogar * educacion_anos
  )

satisfaccion |>
  select(satisfecho, confianza_baja, joven, ingreso_x_educacion) |>
  head(10)
# A tibble: 10 × 4
   satisfecho confianza_baja joven ingreso_x_educacion
   <fct>      <chr>          <chr>               <dbl>
 1 si         no             no                   6960
 2 si         no             no                  19872
 3 no         no             no                  12270
 4 si         si             no                   2842
 5 si         no             no                   4648
 6 no         si             no                   3430
 7 si         no             no                   4466
 8 si         si             si                  13095
 9 si         no             no                   2660
10 no         no             no                   4515

3.2 Pregunta 5: Explorar las nuevas variables

# Proporción de satisfechos por confianza baja/alta
satisfaccion |>
  count(confianza_baja, satisfecho) |>
  group_by(confianza_baja) |>
  mutate(prop = round(n / sum(n), 3)) |>
  filter(satisfecho == "si")
# A tibble: 2 × 4
# Groups:   confianza_baja [2]
  confianza_baja satisfecho     n  prop
  <chr>          <fct>      <int> <dbl>
1 no             si           194 0.808
2 si             si           159 0.612
# Proporción de satisfechos entre jóvenes vs. no jóvenes
satisfaccion |>
  count(joven, satisfecho) |>
  group_by(joven) |>
  mutate(prop = round(n / sum(n), 3)) |>
  filter(satisfecho == "si")
# A tibble: 2 × 4
# Groups:   joven [2]
  joven satisfecho     n  prop
  <chr> <fct>      <int> <dbl>
1 no    si           283 0.711
2 si    si            70 0.686

Respuesta: La variable confianza_baja muestra una diferencia mucho mayor en la proporción de satisfechos que joven. Las personas con confianza baja en el gobierno tienen una proporción de satisfacción mucho menor que las de confianza alta. La edad, en cambio, muestra diferencias más modestas. Esto sugiere que confianza_baja será un predictor más útil para el modelo.

4 Modelos

4.1 Pregunta 6: División de datos

set.seed(42)
datos_split <- initial_split(satisfaccion, prop = 0.75, strata = satisfecho)
datos_train <- training(datos_split)
datos_test <- testing(datos_split)

cat("Entrenamiento:", nrow(datos_train), "observaciones\n")
Entrenamiento: 374 observaciones
cat("Prueba:", nrow(datos_test), "observaciones\n")
Prueba: 126 observaciones
# Verificar proporciones
cat("\nProporciones en entrenamiento:\n")

Proporciones en entrenamiento:
datos_train |>
  count(satisfecho) |>
  mutate(prop = round(n / sum(n), 3))
# A tibble: 2 × 3
  satisfecho     n  prop
  <fct>      <int> <dbl>
1 no           110 0.294
2 si           264 0.706
cat("\nProporciones en prueba:\n")

Proporciones en prueba:
datos_test |>
  count(satisfecho) |>
  mutate(prop = round(n / sum(n), 3))
# A tibble: 2 × 3
  satisfecho     n  prop
  <fct>      <int> <dbl>
1 no            37 0.294
2 si            89 0.706

4.2 Pregunta 7: Dos modelos con fórmula básica

# Definir modelos
modelo_logistico <- logistic_reg() |>
  set_engine("glm") |>
  set_mode("classification")

modelo_arbol <- decision_tree() |>
  set_engine("rpart") |>
  set_mode("classification")

# Folds
set.seed(42)
folds <- vfold_cv(datos_train, v = 5, strata = satisfecho)

# Fórmula básica
formula_basica <- satisfecho ~ edad + educacion_anos + ingreso_hogar +
                               confianza_gobierno + consumo_noticias +
                               participacion_politica + zona

# Evaluar cada modelo con validación cruzada (inline, sin función auxiliar)
eval_log <- fit_resamples(
  modelo_logistico, formula_basica, resamples = folds,
  metrics = metric_set(accuracy),
  control = control_resamples(event_level = "second")
) |>
  collect_metrics() |> mutate(modelo = "Logístico")

eval_arb <- fit_resamples(
  modelo_arbol, formula_basica, resamples = folds,
  metrics = metric_set(accuracy),
  control = control_resamples(event_level = "second")
) |>
  collect_metrics() |> mutate(modelo = "Árbol")

bind_rows(eval_log, eval_arb) |>
  select(modelo, .metric, mean, std_err) |>
  arrange(desc(mean))
# A tibble: 2 × 4
  modelo    .metric   mean std_err
  <chr>     <chr>    <dbl>   <dbl>
1 Logístico accuracy 0.706 0.0114 
2 Árbol     accuracy 0.628 0.00898

Respuesta: La regresión logística supera al árbol de decisión en este dataset (≈0.71 vs. ≈0.63 de accuracy). Con predictores cuya relación con el outcome es aproximadamente lineal, la regresión logística tiene ventaja; el árbol, que parte el espacio en cortes y umbrales, capta peor esa estructura suave. Nota: la accuracy del logístico (≈0.71) coincide casi con la proporción de la clase mayoritaria, así que conviene mirar también precision, recall y AUC, no solo la accuracy.

4.3 Pregunta 8: Mejor modelo con fórmula extendida

# Fórmula extendida
formula_ext <- satisfecho ~ edad + educacion_anos + ingreso_hogar +
                            confianza_gobierno + consumo_noticias +
                            participacion_politica + zona +
                            confianza_baja + ingreso_x_educacion

# Evaluar el modelo logístico con la fórmula extendida (inline, sin función auxiliar)
eval_log_ext <- fit_resamples(
  modelo_logistico, formula_ext, resamples = folds,
  metrics = metric_set(accuracy),
  control = control_resamples(event_level = "second")
) |>
  collect_metrics() |> mutate(modelo = "Logístico (ext)")

# Comparar
cat("Accuracy fórmula básica:\n")
Accuracy fórmula básica:
eval_log |> select(modelo, mean, std_err)
# A tibble: 1 × 3
  modelo     mean std_err
  <chr>     <dbl>   <dbl>
1 Logístico 0.706  0.0114
cat("\nAccuracy fórmula extendida:\n")

Accuracy fórmula extendida:
eval_log_ext |> select(modelo, mean, std_err)
# A tibble: 1 × 3
  modelo           mean std_err
  <chr>           <dbl>   <dbl>
1 Logístico (ext) 0.722 0.00821
cat("\nDiferencia:", round(eval_log_ext$mean - eval_log$mean, 4), "\n")

Diferencia: 0.016 

Respuesta: La diferencia en accuracy entre la fórmula básica y la extendida es generalmente pequeña. Esto sugiere que las variables originales ya capturan la mayor parte de la información relevante. La variable confianza_baja es una versión discretizada de confianza_gobierno (que ya está en el modelo), por lo que no agrega información nueva. El producto ingreso_x_educacion podría capturar una interacción, pero su efecto es marginal.

5 Evaluación

5.1 Pregunta 9: Matriz de confusión

# Ajustar modelo logístico
ajuste <- modelo_logistico |>
  fit(formula_basica, data = datos_train)

# Predicciones
pred_test <- ajuste |>
  predict(datos_test) |>
  bind_cols(datos_test)

# Matriz de confusión
mc <- conf_mat(pred_test, truth = satisfecho, estimate = .pred_class)
mc
          Truth
Prediction no si
        no  5  5
        si 32 84
# Total de errores
tabla <- mc$table
errores <- tabla["si", "no"] + tabla["no", "si"]
cat("Total de errores:", errores, "de", nrow(datos_test), "observaciones\n")
Total de errores: 37 de 126 observaciones
cat("Tasa de error:", round(errores / nrow(datos_test), 3), "\n")
Tasa de error: 0.294 

Respuesta: El modelo comete 37 errores en las 126 observaciones del conjunto de prueba (tasa de error ≈ 0.29), repartidos entre falsos positivos y falsos negativos. Clasifica correctamente la mayoría de las observaciones, aunque no es perfecto. Los errores son esperables dado que la satisfacción democrática depende de muchos factores que no están en el modelo.

5.2 Pregunta 10: Precisión, recall y AUC

# augment() junta predicciones (clases + probabilidades) con los datos
# originales en una sola línea
pred_probs <- ajuste |> augment(datos_test)

# Precision
prec <- pred_probs |>
  precision(truth = satisfecho, estimate = .pred_class,
            event_level = "second")

# Recall
rec <- pred_probs |>
  recall(truth = satisfecho, estimate = .pred_class,
         event_level = "second")

# AUC
auc <- pred_probs |>
  roc_auc(truth = satisfecho, .pred_si, event_level = "second")

cat("Precision:", round(prec$.estimate, 3), "\n")
Precision: 0.724 
cat("Recall:", round(rec$.estimate, 3), "\n")
Recall: 0.944 
cat("AUC:", round(auc$.estimate, 3), "\n")
AUC: 0.701 

Respuesta: La precisión es ≈0.72, el recall ≈0.94 y el AUC ≈0.70. Un AUC entre 0.70 y 0.80 se considera aceptable, entre 0.80 y 0.90 bueno, y superior a 0.90 excelente: el nuestro queda justo en el límite de lo aceptable. Para un modelo con variables sociodemográficas como las nuestras es un resultado razonable, dado que la satisfacción democrática es un fenómeno complejo que depende de muchos factores no observados. La Pregunta 14 vuelve sobre qué tan bueno es realmente este modelo.

5.3 Pregunta 11: Curva ROC

roc_data <- pred_probs |>
  roc_curve(truth = satisfecho, .pred_si, event_level = "second")

autoplot(roc_data) +
  labs(title = "Curva ROC - Modelo logístico para satisfacción democrática")

5.4 Pregunta 12: Coeficientes del modelo

coefs <- tidy(ajuste) |>
  mutate(odds_ratio = round(exp(estimate), 3)) |>
  arrange(p.value)

coefs |>
  select(term, estimate, std.error, p.value, odds_ratio)
# A tibble: 8 × 5
  term                    estimate std.error   p.value odds_ratio
  <chr>                      <dbl>     <dbl>     <dbl>      <dbl>
1 confianza_gobierno      0.256     0.0611   0.0000281      1.29 
2 participacion_politica  0.0178    0.00543  0.00103        1.02 
3 (Intercept)            -1.58      0.658    0.0164         0.206
4 zonaurbano              0.545     0.257    0.0341         1.72 
5 edad                    0.0144    0.00847  0.0895         1.01 
6 consumo_noticias        0.0354    0.0226   0.118          1.04 
7 ingreso_hogar          -0.000199  0.000159 0.212          1    
8 educacion_anos         -0.0329    0.0305   0.281          0.968

Respuesta: La variable con el efecto más fuerte es confianza_gobierno (p < 0.001, odds ratio ≈ 1.29): cada punto adicional de confianza multiplica las chances de satisfacción por ~1.29. Las más débiles son educacion_anos e ingreso_hogar (p > 0.2, odds ratios ≈ 1), que no muestran relación clara con la satisfacción una vez controladas las demás variables. El orden de importancia de los predictores tiene sentido teórico: la confianza en el gobierno es el predictor más directo de la satisfacción con la democracia.

6 Reflexión

6.1 Pregunta 13: Árbol vs. logística

Respuesta: La regresión logística y los árboles de decisión tienen fortalezas complementarias:

Regresión logística:

  • Mejor cuando la relación entre predictores y outcome es aproximadamente lineal (en la escala logit)
  • Produce coeficientes interpretables: cada variable tiene un odds ratio que se puede comunicar a audiencias no técnicas
  • Tiende a generalizar mejor cuando hay pocos datos, porque tiene menos parámetros
  • Preferible cuando el objetivo es entender qué factores influyen y en qué dirección

Árbol de decisión:

  • Captura relaciones no lineales e interacciones de forma automática, sin necesidad de especificarlas
  • Muy fácil de interpretar visualmente: se puede mostrar el árbol completo
  • Funciona bien con variables categóricas sin necesidad de crear dummies
  • Preferible cuando la estructura de los datos es jerárquica (por ejemplo, la edad importa solo para personas con baja educación)

En esta tarea, la regresión logística funciona igual o mejor que el árbol porque la relación entre los predictores y la satisfacción es aproximadamente lineal. El árbol tiende a sobreajustar (cortes arbitrarios) con datasets de este tamaño. Para un organismo que necesita recomendaciones claras de política, la regresión logística es preferible porque los coeficientes indican directamente qué factores modificar.

6.2 Pregunta 14: Una accuracy que engaña

Miren de nuevo la accuracy del modelo logístico (Pregunta 7) y la proporción de personas satisfechas en los datos (el count(satisfecho)). Van a notar que son casi iguales. Sin escribir código nuevo, expliquen: ¿qué significa que la accuracy del modelo sea casi idéntica a la proporción de la clase mayoritaria? ¿El modelo realmente “aprendió” algo? ¿Qué métricas mirarían para responder eso mejor que la accuracy?

Respuesta: Alrededor del 71% de las personas están satisfechas, así que un “modelo” que prediga siempre “satisfecho” ya acertaría el 71% de las veces sin mirar ningún predictor. Que la accuracy del modelo logístico (≈0.71) coincida casi exactamente con esa proporción es una señal de alarma: medido por accuracy, el modelo apenas mejora sobre adivinar la clase mayoritaria.

Eso no significa que el modelo sea inútil, sino que la accuracy es la métrica equivocada para juzgarlo acá. El AUC (≈0.70) muestra que sí hay algo de capacidad para ordenar a las personas por su probabilidad de estar satisfechas, y el recall alto indica que recupera a la mayoría de los satisfechos (a costa de muchos falsos positivos, como se ve en la matriz de confusión). La lección es la de “La paradoja de la precisión”: con clases desbalanceadas, la accuracy hay que leerla siempre contra la línea base, y conviene apoyarse en precisión, recall y AUC para saber si el modelo realmente aprendió.

Volver arriba