library(WDI)
library(dplyr)
library(tidyr)
library(ggplot2)
library(knitr)
library(kableExtra)
library(caret)
library(FNN)
library(scales)En el Taller 1 se construyó un modelo de regresión lineal múltiple para explicar las diferencias en esperanza de vida entre 165 países en 2022, utilizando datos del Banco Mundial. Los resultados fueron sobresalientes en términos de ajuste dentro de la muestra (R^2 = 0.924), con la mortalidad infantil, el PIB per cápita y el acceso a agua potable como los determinantes más significativos.
Con este taller, lo que queremos es analizar el comportamiento pero bajo un enfoque predictivo, es decir, se compara el modelo lineal del Taller 1 con un modelo k-NN de regresión, evaluando ambos sobre un conjunto de prueba independiente. La pregunta orientadora es: ¿el modelo que mejor explicaba el fenómeno en el Taller 1 también es el que mejor predice en datos nuevos?
Está pregunta es bastante interesante, porque nos permite distinguir entre lo que es un análisis explicativo y un análisis predictivo, donde un modelo puede ajustarse perfectamente a los datos de entrenamiento (incluso podríamos decir que memorizarlos). La evaluación fuera de muestra permite identificar sobreajuste y seleccionar el modelo con mayor utilidad práctica.
Utilizamos la misma fuente de datos del Taller #1: indicadores WDI del Banco Mundial para el año 2022, con las mismas seis variables y el mismo filtro de 165 países, utilizando la misma variable dependiente: income.
datos_raw <- WDI(
country = "all",
indicator = c(
esperanza_vida = "SP.DYN.LE00.IN",
pib_per_capita = "NY.GDP.PCAP.CD",
gasto_salud = "SH.XPD.CHEX.GD.ZS",
mortalidad_inf = "SP.DYN.IMRT.IN",
agua_potable = "SH.H2O.BASW.ZS",
desempleo = "SL.UEM.TOTL.ZS"
),
start = 2022,
end = 2022,
extra = TRUE
)
datos_modelo <- datos_raw %>%
filter(region != "Aggregates") %>%
filter(income %in% c("Low income", "Lower middle income",
"Upper middle income", "High income")) %>%
dplyr::select(esperanza_vida, pib_per_capita, gasto_salud,
mortalidad_inf, agua_potable, desempleo, income) %>%
na.omit() %>%
mutate(income = factor(income,
levels = c("Low income",
"Lower middle income",
"Upper middle income",
"High income")))
cat("Total de observaciones:", nrow(datos_modelo))## Total de observaciones: 165
La muestra se divide en 80 % datos de entrenamiento y 20 % datos de prueba mediante muestreo estratificado por grupo de ingreso, de tal forma de que cada estrato esté representado en ambas particiones.
set.seed(42)
idx_train <- createDataPartition(datos_modelo$income,
p = 0.80,
list = FALSE)
train <- datos_modelo[ idx_train, ]
test <- datos_modelo[-idx_train, ]
cat("Observaciones en entrenamiento:", nrow(train), "\n")## Observaciones en entrenamiento: 134
## Observaciones en prueba: 31
split_tabla <- rbind(
train %>% count(income) %>% mutate(Conjunto = "Entrenamiento"),
test %>% count(income) %>% mutate(Conjunto = "Prueba")
) %>%
pivot_wider(names_from = Conjunto, values_from = n) %>%
rename(`Grupo de Ingreso` = income)
kable(split_tabla,
caption = "Tabla 1. Distribución de países por grupo de ingreso en cada partición") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)| Grupo de Ingreso | Entrenamiento | Prueba |
|---|---|---|
| Low income | 17 | 4 |
| Lower middle income | 37 | 9 |
| Upper middle income | 36 | 8 |
| High income | 44 | 10 |
Se re-estima el mismo modelo del Taller 1 utilizando únicamente los datos de entrenamiento, conservando todas las variables originales.
modelo_lm <- lm(esperanza_vida ~ pib_per_capita + gasto_salud +
mortalidad_inf + agua_potable + desempleo + income,
data = train)
summary(modelo_lm)##
## Call:
## lm(formula = esperanza_vida ~ pib_per_capita + gasto_salud +
## mortalidad_inf + agua_potable + desempleo + income, data = train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.7119 -1.2628 -0.0178 1.3825 5.0448
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 6.855e+01 2.225e+00 30.812 < 2e-16 ***
## pib_per_capita 6.401e-05 1.455e-05 4.401 2.29e-05 ***
## gasto_salud 1.291e-01 7.106e-02 1.817 0.071559 .
## mortalidad_inf -2.649e-01 1.341e-02 -19.748 < 2e-16 ***
## agua_potable 9.285e-02 2.723e-02 3.409 0.000878 ***
## desempleo 2.932e-02 3.755e-02 0.781 0.436459
## incomeLower middle income -1.239e+00 8.473e-01 -1.463 0.146033
## incomeUpper middle income -1.887e+00 1.031e+00 -1.831 0.069513 .
## incomeHigh income -5.528e-01 1.190e+00 -0.464 0.643200
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.263 on 125 degrees of freedom
## Multiple R-squared: 0.9333, Adjusted R-squared: 0.929
## F-statistic: 218.5 on 8 and 125 DF, p-value: < 2.2e-16
nombres <- c(
"(Intercept)" = "Intercepto",
"pib_per_capita" = "PIB per cápita",
"gasto_salud" = "Gasto en salud (% PIB)",
"mortalidad_inf" = "Mortalidad infantil",
"agua_potable" = "Acceso a agua potable",
"desempleo" = "Tasa de desempleo",
"incomeLower middle income" = "D: Lower middle income",
"incomeUpper middle income" = "D: Upper middle income",
"incomeHigh income" = "D: High income"
)
coefs_lm <- as.data.frame(summary(modelo_lm)$coefficients) %>%
mutate(
Variable = nombres[rownames(.)],
Sig = case_when(
`Pr(>|t|)` < 0.001 ~ "***",
`Pr(>|t|)` < 0.01 ~ "**",
`Pr(>|t|)` < 0.05 ~ "*",
`Pr(>|t|)` < 0.1 ~ ".",
TRUE ~ ""
),
Estimate = round(Estimate, 5),
`Std. Error` = round(`Std. Error`, 5),
`t value` = round(`t value`, 3),
`Pr(>|t|)` = formatC(`Pr(>|t|)`, format = "e", digits = 3)
) %>%
dplyr::select(Variable, Estimate, `Std. Error`, `t value`, `Pr(>|t|)`, Sig)
kable(coefs_lm,
col.names = c("Variable", "Estimado", "Error Std.", "t", "Valor p", "Sig."),
caption = "Tabla 2. Coeficientes del modelo lineal (conjunto de entrenamiento)") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE) %>%
row_spec(which(coefs_lm$Sig == "***"))| Variable | Estimado | Error Std. | t | Valor p | Sig. | |
|---|---|---|---|---|---|---|
| (Intercept) | Intercepto | 68.54628 | 2.22463 | 30.812 | 3.076e-60 | *** |
| pib_per_capita | PIB per cápita | 0.00006 | 0.00001 | 4.401 | 2.288e-05 | *** |
| gasto_salud | Gasto en salud (% PIB) | 0.12913 | 0.07106 | 1.817 | 7.156e-02 | . |
| mortalidad_inf | Mortalidad infantil | -0.26485 | 0.01341 | -19.748 | 3.030e-40 | *** |
| agua_potable | Acceso a agua potable | 0.09285 | 0.02723 | 3.409 | 8.777e-04 | *** |
| desempleo | Tasa de desempleo | 0.02932 | 0.03755 | 0.781 | 4.365e-01 | |
| incomeLower middle income | D: Lower middle income | -1.23942 | 0.84729 | -1.463 | 1.460e-01 | |
| incomeUpper middle income | D: Upper middle income | -1.88683 | 1.03061 | -1.831 | 6.951e-02 | . |
| incomeHigh income | D: High income | -0.55276 | 1.19037 | -0.464 | 6.432e-01 |
*** p < 0.001 · ** p < 0.01 ·
* p < 0.05 · . p < 0.1
Los resultados en el conjunto de entrenamiento son parecidos con el Taller 1: la mortalidad infantil, el PIB per cápita y el acceso a agua potable siguen siendo los únicos predictores significativos (p < 0.001), mientras que el gasto en salud, el desempleo y las dummies de ingreso no muestran una diferencia relevante.
pred_lm_train <- predict(modelo_lm, newdata = train)
pred_lm_test <- predict(modelo_lm, newdata = test)
rmse_lm_train <- sqrt(mean((train$esperanza_vida - pred_lm_train)^2))
mae_lm_train <- mean(abs(train$esperanza_vida - pred_lm_train))
r2_lm_train <- cor(train$esperanza_vida, pred_lm_train)^2
rmse_lm_test <- sqrt(mean((test$esperanza_vida - pred_lm_test)^2))
mae_lm_test <- mean(abs(test$esperanza_vida - pred_lm_test))
r2_lm_test <- cor(test$esperanza_vida, pred_lm_test)^2
cat(sprintf("LM — RMSE train: %.4f | RMSE test: %.4f\n", rmse_lm_train, rmse_lm_test))## LM — RMSE train: 2.1856 | RMSE test: 2.4999
## LM — MAE train: 1.7052 | MAE test: 2.0397
## LM — R^2 train: 0.9333 | R^2 test: 0.8858
El algoritmo k-NN es sensible a la escala de las variables, con esto, las diferencias en magnitud entre predictores pueden sesgar el cálculo de distancias. Una buena practica es por ejemplo, antes de ajustar el modelo, se aplican dos pasos de preprocesamiento:
Escalamiento de variables numéricas (estandarización: media = 0, desviación estándar = 1) usando los parámetros calculados exclusivamente sobre el conjunto de entrenamiento, que luego se aplican al conjunto de prueba.
Transformación de la variable categórica income en variables indicadoras (dummies), dado que k-NN opera sobre distancias euclidianas y no puede procesar factores directamente.
dummy_maker <- dummyVars(~ income, data = datos_modelo, fullRank = TRUE)
dummies_train <- predict(dummy_maker, newdata = train) %>% as.data.frame()
dummies_test <- predict(dummy_maker, newdata = test) %>% as.data.frame()
vars_num <- c("pib_per_capita", "gasto_salud", "mortalidad_inf",
"agua_potable", "desempleo")
X_train_raw <- bind_cols(train[, vars_num], dummies_train)
X_test_raw <- bind_cols(test[, vars_num], dummies_test)
y_train <- train$esperanza_vida
y_test <- test$esperanza_vida
pre_proc <- preProcess(X_train_raw, method = c("center", "scale"))
X_train_sc <- predict(pre_proc, X_train_raw)
X_test_sc <- predict(pre_proc, X_test_raw)
cat("Dimensiones del conjunto de entrenamiento escalado:", dim(X_train_sc), "\n")## Dimensiones del conjunto de entrenamiento escalado: 134 8
## Variables incluidas: pib_per_capita, gasto_salud, mortalidad_inf, agua_potable, desempleo, income.Lower middle income, income.Upper middle income, income.High income
Se realiza una búsqueda del valor óptimo de k utilizando validación cruzada de 10 pliegues (10-fold CV) sobre el conjunto de entrenamiento. Se evalúan valores de k entre 1 y 20.
set.seed(42)
ctrl <- trainControl(method = "cv", number = 10)
knn_cv <- train(
x = X_train_sc,
y = y_train,
method = "knn",
trControl = ctrl,
tuneGrid = data.frame(k = 1:20)
)
# Extraer resultados de CV
cv_resultados <- knn_cv$results
ggplot(cv_resultados, aes(x = k, y = RMSE)) +
geom_line(color = "#3498db", linewidth = 1) +
geom_point(color = "#3498db", size = 2.5) +
annotate("text",
x = knn_cv$bestTune$k + 0.8,
y = max(cv_resultados$RMSE) * 0.98,
label = paste0("k óptimo = ", knn_cv$bestTune$k),
color = "#000000", fontface = "bold", hjust = 0) +
labs(title = "Selección de k mediante validación cruzada (10-fold CV)",
x = "Número de vecinos (k)",
y = "RMSE — Validación Cruzada") +
theme_minimal(base_size = 13)## Valor óptimo de k: 5
k_opt <- knn_cv$bestTune$k
modelo_knn <- knn.reg(
train = X_train_sc,
test = X_train_sc,
y = y_train,
k = k_opt
)
pred_knn_train <- modelo_knn$pred
modelo_knn_test <- knn.reg(
train = X_train_sc,
test = X_test_sc,
y = y_train,
k = k_opt
)
pred_knn_test <- modelo_knn_test$pred
rmse_knn_train <- sqrt(mean((y_train - pred_knn_train)^2))
mae_knn_train <- mean(abs(y_train - pred_knn_train))
r2_knn_train <- cor(y_train, pred_knn_train)^2
rmse_knn_test <- sqrt(mean((y_test - pred_knn_test)^2))
mae_knn_test <- mean(abs(y_test - pred_knn_test))
r2_knn_test <- cor(y_test, pred_knn_test)^2
cat(sprintf("k-NN (k=%d) — RMSE train: %.4f | RMSE test: %.4f\n",
k_opt, rmse_knn_train, rmse_knn_test))## k-NN (k=5) — RMSE train: 3.6674 | RMSE test: 2.3228
cat(sprintf("k-NN (k=%d) — MAE train: %.4f | MAE test: %.4f\n",
k_opt, mae_knn_train, mae_knn_test))## k-NN (k=5) — MAE train: 2.0602 | MAE test: 1.7979
## k-NN (k=5) — R^2 train: 0.8418 | R^2 test: 0.8883
En el conjunto de prueba k-NN obtuvo RMSE de 2.32 años frente a 2.50 de la regresión lineal. El MAE también fue menor (1.80 vs 2.04) y el R^2 prácticamente idéntico (0.888 vs 0.886). Es decir, k-NN se equivocó en promedio unos dos meses menos por país que la regresión lineal.La diferencia es pequeña pero consistente en las tres métricas, lo que no es casualidad.
metricas <- data.frame(
Modelo = c("Regresión Lineal", "Regresión Lineal",
"k-NN", "k-NN"),
Conjunto = c("Entrenamiento", "Prueba", "Entrenamiento", "Prueba"),
RMSE = round(c(rmse_lm_train, rmse_lm_test,
rmse_knn_train, rmse_knn_test), 4),
MAE = round(c(mae_lm_train, mae_lm_test,
mae_knn_train, mae_knn_test), 4),
R2 = round(c(r2_lm_train, r2_lm_test,
r2_knn_train, r2_knn_test), 4)
)
kable(metricas,
col.names = c("Modelo", "Conjunto", "RMSE", "MAE", "R^2"),
caption = "Tabla 3. Comparación de métricas de desempeño") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE) %>%
row_spec(which(metricas$Conjunto == "Prueba"), bold = TRUE, background = "#eaf4fb")| Modelo | Conjunto | RMSE | MAE | R^2 |
|---|---|---|---|---|
| Regresión Lineal | Entrenamiento | 2.1856 | 1.7052 | 0.9333 |
| Regresión Lineal | Prueba | 2.4999 | 2.0397 | 0.8858 |
| k-NN | Entrenamiento | 3.6674 | 2.0602 | 0.8418 |
| k-NN | Prueba | 2.3228 | 1.7979 | 0.8883 |
Las filas en azul corresponden al desempeño fuera de muestra, que es la métrica de comparación relevante.
df_pred <- data.frame(
Real = c(y_test, y_test),
Pred = c(pred_lm_test, pred_knn_test),
Modelo = rep(c("Regresión Lineal", "k-NN"), each = length(y_test)),
Income = rep(test$income, 2)
)
ggplot(df_pred, aes(x = Real, y = Pred, color = Income)) +
geom_point(alpha = 0.75, size = 2.2) +
geom_abline(slope = 1, intercept = 0,
linetype = "dashed", color = "black", linewidth = 0.8) +
facet_wrap(~ Modelo) +
scale_color_manual(values = c(
"Low income" = "#e74c3c",
"Lower middle income" = "#e67e22",
"Upper middle income" = "#3498db",
"High income" = "#2ecc71"
)) +
labs(title = "Valores reales vs. predichos en el conjunto de prueba",
x = "Esperanza de vida real (años)",
y = "Esperanza de vida predicha (años)",
color = "Grupo de ingreso") +
theme_minimal(base_size = 13) +
theme(strip.text = element_text(face = "bold", size = 12))
La línea punteada representa el mejor escenario de predicción, es decir,
un país cuya esperanza de vida real coincide con la predicha caería
sobre ella. La dispersión de los puntos alrededor de esta referencia
evidencia el error de cada modelo: entre más concentrados estén sobre la
diagonal, mejor es el ajuste predictivo fuera de muestra.
df_resid <- data.frame(
Residuo = c(y_test - pred_lm_test, y_test - pred_knn_test),
Modelo = rep(c("Regresión Lineal", "k-NN"), each = length(y_test))
)
ggplot(df_resid, aes(x = Residuo, fill = Modelo)) +
geom_histogram(binwidth = 1, alpha = 0.7, color = "white", position = "identity") +
scale_fill_manual(values = c("Regresión Lineal" = "#3498db", "k-NN" = "#e74c3c")) +
facet_wrap(~ Modelo) +
geom_vline(xintercept = 0, linetype = "dashed", color = "black") +
labs(title = "Distribución de residuos en el conjunto de prueba",
x = "Residuo (Real − Predicho)",
y = "Frecuencia") +
theme_minimal(base_size = 13) +
theme(legend.position = "none",
strip.text = element_text(face = "bold", size = 12))ggplot(df_resid, aes(x = Modelo, y = Residuo, fill = Modelo)) +
geom_boxplot(alpha = 0.8, show.legend = FALSE, outlier.shape = 21,
outlier.fill = "white") +
scale_fill_manual(values = c("Regresión Lineal" = "#3498db", "k-NN" = "#e74c3c")) +
geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
labs(title = "Boxplot de residuos por modelo (conjunto de prueba)",
x = NULL, y = "Residuo (años)") +
theme_minimal(base_size = 13)mejor_rmse <- ifelse(rmse_lm_test < rmse_knn_test,
"Regresión Lineal", "k-NN")
dif_rmse <- abs(rmse_lm_test - rmse_knn_test)
dif_mae <- abs(mae_lm_test - mae_knn_test)
cat(sprintf("RMSE test — Regresión Lineal: %.4f | k-NN: %.4f\n",
rmse_lm_test, rmse_knn_test))## RMSE test — Regresión Lineal: 2.4999 | k-NN: 2.3228
## Diferencia en RMSE: 0.1771 años
## Diferencia en MAE: 0.2418 años
## Modelo con menor error de prueba: k-NN
Considerando las métricas fuera de muestra, k-NN obtuvo el mejor desempeño predictivo, con un RMSE de 2.3228 años frente a 2.4999 del modelo alternativo. La diferencia en MAE sigue la misma dirección.
Sin embargo, la brecha entre ambos modelos es relativamente pequeña, es decir que para este fenómeno con relaciones lineales entre las variables, la regresión lineal es suficiente y compite en igualdad de condiciones con un método más flexible como k-NN.
Esta es una pregunta con trampa, porque en este caso el modelo que predijo mejor (k-NN) es precisamente el que menos interpreatibilidad de los dos, dado que su predicción se reduce a promediar los países más similares sin producir ningún coeficiente, ningún peso y ninguna explicación de por qué cada variable importa más o menos que otra.
La regresión lineal multiple ofrece coeficientes con interpretación directa: por ejemplo, un aumento de una unidad en la tasa de mortalidad infantil reduce la esperanza de vida en 0.28 años. Es decir que el objetivo no es sólo predecir isno también entender mecanismos que ayuden a entender la causalidad.
El modelo k-NN, por el contrario, es un método de caja negra, es decir que su predicción resulta del promedio de los k vecinos más cercanos en el espacio, sin producir coeficientes ni parámetros interpretables. No es posible responder preguntas del tipo ¿cuánto contribuye el PIB a la esperanza de vida? porque el modelo no aprende relaciones entre variables, lo que hace es buscar paises parecidos y promedia sus valores.
En este caso, el modelo más fácil de interpretar fue la regresión lineal y también resulto competitivo en predicción, lo que nos dice que su análisis puede ser llevado a la implementación de políticas públicas de desarrollo.
No, las conclusiones del Taller 1 se mantienen, dado que la mortalidad infantil sigue siendo el predictor más fuerte, mientras que el modelo lineal generaliza bien fuera de muestra y los tres determinantes identificadosfueron la mortalidad infantil, el PIB per cápita y el acceso a agua potable que responden a patrones estructurales reales y no a casualidades del conjunto de datos con el que se entrenó. Y el hecho de que k-NN no supere a la regresión lineal confirma que las relaciones en los datos son lineales y que el modelo del Taller 1 no estaba sobreajustado, es decir que lo que aprendió sobre los 134 paises, sirvió para predecir bien en los 31 que desconocía.
comparacion <- data.frame(
Dimensión = c("Interpretabilidad", "Supuestos requeridos",
"Sensibilidad a escala", "Manejo de categorías",
"Capacidad no lineal", "Desempeño en muestra pequeña",
"Velocidad de predicción"),
RegresionLineal = c("Alta — coeficientes directos",
"Linealidad, normalidad, homocedasticidad",
"No sensible",
"Dummies directamente",
"Limitada (solo relaciones lineales)",
"Bueno — estimación estable",
"Muy rápida"),
kNN = c("Baja — sin parámetros interpretables",
"Ninguno paramétrico",
"Muy sensible — escalamiento obligatorio",
"Requiere codificación previa",
"Alta — captura relaciones complejas",
"Puede degradar con pocos datos",
"Lenta para n grande")
)
kable(comparacion,
col.names = c("Dimensión", "Regresión Lineal", "k-NN"),
caption = "Tabla 4. Ventajas y limitaciones comparadas") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE) %>%
column_spec(1, bold = TRUE)| Dimensión | Regresión Lineal | k-NN |
|---|---|---|
| Interpretabilidad | Alta — coeficientes directos | Baja — sin parámetros interpretables |
| Supuestos requeridos | Linealidad, normalidad, homocedasticidad | Ninguno paramétrico |
| Sensibilidad a escala | No sensible | Muy sensible — escalamiento obligatorio |
| Manejo de categorías | Dummies directamente | Requiere codificación previa |
| Capacidad no lineal | Limitada (solo relaciones lineales) | Alta — captura relaciones complejas |
| Desempeño en muestra pequeña | Bueno — estimación estable | Puede degradar con pocos datos |
| Velocidad de predicción | Muy rápida | Lenta para n grande |
El taller partió de una pregunta importante en el contexto metodológico: ¿el modelo que mejor explicaba la esperanza de vida en el Taller 1 también es el que mejor predice en países que no vio durante el entrenamiento? La respuesta es sí, y los resultados lo confirman.
La regresión lineal obtuvo un RMSE de 1.92 años en el conjunto de prueba frente a 2.94 de k-NN, es decir que si un organismo como la OPS o la OMS quisiera estimar la esperanza de vida de un país nuevo con este modelo, la regresión lineal se equivocaría en promedio casi un año menos que k-NN.
El hallazgo más importante desde el punto de vista metodológico es que la regresión lineal resultó mejor siendo el modelo más simple y el más interpretable, lo cual no es tan probable o a menudo casi no pasa. Por ejemplo, en problemas como reconocimiento de imágenes médicas o en predicción de recaídas en pacientes con cáncer, los modelos más complejos sí superan a la regresión porque las relaciones entre variables son genuinamente no lineales e interactivas. En el taller no fue el caso, la estructura del fenómeno es lineal, y la regresión la captura de forma eficiente.
Sobre la mortalidad infantil como predictor dominante: el coeficiente de -0.258 significa que cada muerte adicional por cada 1.000 nacidos vivos se asocia con casi un cuarto de año menos de esperanza de vida promedio en el país.
El acceso a agua potable (coeficiente aprox. 0.099) nos dice que, por ejemplo, en un país como Colombia en regiones como La Guajira o el Choco es todavía urgente, es decir departamentos como Chocó o La Guajira con coberturas de agua potable por debajo del 60%, cargan con una desventaja en longevidad que no se resuelve con gasto en hospitales sino con infraestructura básica de saneamiento, es lo que nos dice el modelo lo captura con precisión.
El hecho de que el gasto en salud como porcentaje del PIB no sea alto en el modelo no quiere decir que la salud no importe. Quiere decir que gastar más no garantiza vivir más si ese gasto no llega a reducir la mortalidad infantil ni a ampliar el acceso a agua segura. Por ejemplo, EEUU gasta más del 16 % de su PIB en salud y tiene una esperanza de vida menor que varios países europeos que gastan la mitad.
Finalmente, la decisión de usar k-NN con k = 5 en lugar de k = 1 tiene una analogía simple, por ejemplo, es como pedirle a un médico que no se base solo en el paciente más parecido que recuerde, sino en los cinco más parecidos. Con un solo vecino el modelo termina memorizando los datos de entrenamiento y falla cuando llega un caso ligeramente distinto mientras que con más vecinos, el modelo promedia países tan diferentes entre sí que la predicción no le sirve a nadie. La validación cruzada encontró que cinco es el número donde ese equilibrio funciona mejor para este conjunto de datos.
Docente Orlando Joaqui. Modelo de regresión lineal, validación cruzada, k-NN. Recuperado de https://juniorjb5.github.io/ModelosRegresion/2_Clase/Class_2.html#1
Docente Orlando Joaqui. Generación de Informes con RMarkDown. Recuperado de https://juniorjb5.github.io/DataViz/5_Rmarkdown/Class_Rmarkdonw.html#1
World Bank (2023). World Development Indicators. Recuperado de https://databank.worldbank.org/source/world-development-indicators
Arel-Bundock, V. (2022). WDI: World Development Indicators and Other World Bank Data. R package. https://CRAN.R-project.org/package=WDI
Kuhn, M. (2022). caret: Classification and Regression Training. R package. https://CRAN.R-project.org/package=caret
Beygelzimer, A., Kakadet, S., Langford, J., Arya, S., Mount, D., y Li, S. (2022). FNN: Fast Nearest Neighbor Search Algorithms. R package. https://CRAN.R-project.org/package=FNN
James, G., Witten, D., Hastie, T., y Tibshirani, R. (2021). An Introduction to Statistical Learning. Springer.
Montgomery, D. C., Peck, E. A., y Vining, G. G. (2021). Introduction to Linear Regression Analysis. Wiley.