title: “Clasificación de países según esperanza de vida” author: “Dana Portillo, Gustavo Mosquera, Juan David Rosales” date: “2025-05-07” output: html_document: toc: true toc_float: true theme: cerulean code_folding: hide —
En la actualidad la esperanza de vida se ha convertido en un indicador clave del desarrollo y la calidad de vida de las personas. Comprender qué factores la determinan y predecir si un país presenta una alta esperanza de vida permite a su vez poder identificar las desigualdades que existen entre dichas naciones.
Este estudio aplica técnicas de clasificación supervisada, como el modelo(kNN) y árboles de decisión, para predecir si un país tiene una esperanza de vida alta, a partir de variables como el PIB per cápita, el gasto en salud y la mortalidad infantil.
A partir de diferentes fuentes se recopiló la información necesaria para crear la base de datos. Se utilizaron 10 variables las cuales son:
Mortalidad infantil: La mortalidad infantil representa el número de muertes de niños menores de un año por cada 1,000 nacidos vivos y sirve como un indicador clave de las condiciones de salud y calidad de vida de una población.
Consumo de alcohol: El consumo de alcohol, medido en litros de alcohol puro por persona mayor de 15 años al año, refleja los patrones de consumo que pueden estar vinculados con enfermedades no transmisibles.
Esperanza de vida: Es el promedio de años que se espera que viva una persona al nacer, lo que resume las condiciones generales de salud y desarrollo.
Uso de servicios de agua potable: Mide el porcentaje de la población con acceso a agua segura, siendo esencial para prevenir enfermedades y garantizar el bienestar.
Continente: La variable continente permite agrupar los países por región geográfica, facilitando comparaciones regionales.
PIB per capita: El PIB per cápita, ajustado por paridad del poder adquisitivo (PPA), muestra el ingreso promedio por persona, lo que ayuda a entender el nivel económico de un país.
Muertes totales por enfermedades cardiovasculares: Indican la carga de patologías del corazón y sistema circulatorio, reflejando desafíos de salud pública.
Tasa de suicidios: La tasa de suicidios, expresada por cada 100,000 habitantes, es un indicador crítico de salud mental.
Indice de desarrollo humano: Combina indicadores de salud, educación e ingreso para mostrar el desarrollo integral de un país.
Gasto público en educación: Representa el porcentaje del PIB destinado a este sector, lo que evidencia el compromiso del Estado con el capital humano y el desarrollo social.
# 1. Cargar y preparar los datos
datos <- read_excel("Base_de_datos1.xlsx", sheet = "Sheet1")
# Cambiar nombre de columnas
colnames(datos)[7] <- "PIB_per_capita"
colnames(datos)[colnames(datos) == "Muertes totales por enfermedades cardiovasculares"] <- "Muertes_cardio"
colnames(datos)[colnames(datos) == "Tasa de suicidios (ajustada por edad)"] <- "Suicidios"
colnames(datos)[colnames(datos) == "Indice de desarrollo humano"] <- "IDH"
colnames(datos)[colnames(datos) == "Gasto publico en educacion como porcentaje del PIB"] <- "Gasto_educacion"
A continuación se presentan estadísticas resumidas de las variables cuantitativas consideradas en el modelo. Estas variables han sido recolectadas para diversos países y están asociadas a factores sociales, económicos y de salud
summary(datos)
## Año Mortalidad_Infantil Consumo_de_alcohol_Per_Capita
## Min. :2019 Min. : 0.2288 Min. : 0.000
## 1st Qu.:2019 1st Qu.: 0.4062 1st Qu.: 1.995
## Median :2019 Median : 1.1316 Median : 6.515
## Mean :2019 Mean : 2.1322 Mean : 6.223
## 3rd Qu.:2019 3rd Qu.: 2.6091 3rd Qu.:10.340
## Max. :2019 Max. :11.6929 Max. :16.990
## Esperanza_de_vida Uso_de_servicios_de_agua_potable Continente
## Min. :31.53 Min. : 6.113 Length:106
## 1st Qu.:70.29 1st Qu.: 47.568 Class :character
## Median :75.61 Median : 81.239 Mode :character
## Mean :74.30 Mean : 70.987
## 3rd Qu.:81.31 3rd Qu.: 97.900
## Max. :84.42 Max. :100.000
## PIB_per_capita Muertes_cardio Suicidios IDH
## Min. : 1145 Min. : 145.4 Min. : 0.7094 Min. :0.3910
## 1st Qu.: 6963 1st Qu.: 8094.1 1st Qu.: 5.0901 1st Qu.:0.6680
## Median : 18103 Median : 22700.9 Median : 8.1838 Median :0.7825
## Mean : 30128 Mean : 82451.4 Mean : 9.1048 Mean :0.7664
## 3rd Qu.: 46849 3rd Qu.: 70914.2 3rd Qu.:11.2195 3rd Qu.:0.8952
## Max. :134106 Max. :950694.7 Max. :37.4085 Max. :0.9610
## Gasto_educacion
## Min. : 0.3585
## 1st Qu.: 3.3106
## Median : 4.2595
## Mean : 4.4582
## 3rd Qu.: 5.2610
## Max. :13.7687
# Crear variable binaria
datos$esperanza_alta <- ifelse(datos$Esperanza_de_vida >= 81, "Alta", "Baja")
datos$esperanza_alta <- as.factor(datos$esperanza_alta)
# Comprobar que la variable fue creada correctamente
table(datos$esperanza_alta)
##
## Alta Baja
## 29 77
La esperanza de vida muestra una distribución asimétrica hacia la izquierda (sesgo negativo), con una fuerte concentración en valores altos. Esto indica que la mayoría de los países considerados en el análisis tienen una esperanza de vida relativamente alta, lo cual es señal de condiciones de vida y salud relativamente buenas a nivel global.
p1 <- ggplot(datos, aes(x = Esperanza_de_vida)) +
geom_histogram(bins = 30, fill = "green", color = "black") +
theme_minimal() +
labs(title = "Histograma de la esperanza de vida",
x = "Esperanza de vida",
y = "Frecuencia")
plotly::ggplotly(p1)
Europa destaca como el continente con mejores indicadores de esperanza de vida, mientras que África se encuentra completamente en la categoría de esperanza de vida baja. Asia y Oceanía presentan una combinación, reflejando desigualdades internas. Esto sugiere diferencias marcadas en el acceso a servicios de salud, condiciones de vida y desarrollo socioeconómico entre continentes.
# Distribución por continente
p6 <- ggplot(datos, aes(x = Continente, fill = esperanza_alta)) +
geom_bar(position = "fill") +
labs(title = "Distribución de esperanza de vida por continente", y = "Proporción", x = "Continente")
plotly::ggplotly(p6)
Europa destaca como el continente con mayor esperanza de vida y menor variabilidad, mientras que África presenta la mayor desigualdad y los valores más bajos. América y Oceanía están en posiciones intermedias, y Asia muestra una mejora notable con una esperanza de vida generalmente alta, aunque con cierta variabilidad.
p2 <- ggplot(datos, aes(x = Continente, y = Esperanza_de_vida, fill = Continente)) +
geom_boxplot() +
labs(title = "Esperanza de Vida por Continente") +
theme_minimal() +
theme(legend.position = "none")
plotly::ggplotly(p2)
Un mayor IDH está fuertemente asociado con una alta esperanza de vida. Los países con esperanza de vida alta tienden a tener un IDH consistentemente alto y homogéneo, mientras que los países con esperanza de vida baja presentan una gran variabilidad en su desarrollo humano, con una tendencia general hacia valores más bajos.
# Leer archivo Excel (ajusta la ruta si es necesario)
df <- read_excel("Base_de_datos1.xlsx")
# Crear variable binaria "esperanza_alta"
df <- df %>%
mutate(
esperanza_alta = ifelse(Esperanza_de_vida >= 80, "Alta", "Baja"),
esperanza_alta = as.factor(esperanza_alta)
)
# Filtrar NA
df_filtrado <- df %>%
drop_na(`Indice de desarrollo humano`, esperanza_alta)
# Gráfico de violín + boxplot + puntos
ggplot(df_filtrado, aes(x = esperanza_alta, y = `Indice de desarrollo humano`, fill = esperanza_alta)) +
geom_violin(trim = FALSE, alpha = 0.6, scale = "width") +
geom_boxplot(width = 0.1, fill = "white", outlier.shape = NA) +
geom_jitter(width = 0.1, size = 1, alpha = 0.6, color = "black") +
labs(
title = "Distribución del IDH según Esperanza de Vida Alta",
x = "Esperanza de vida alta",
y = "Índice de Desarrollo Humano (IDH)"
) +
theme_minimal() +
scale_fill_manual(values = c("Alta" = "#69b3a2", "Baja" = "#404080")) +
theme(
plot.title = element_text(hjust = 0.5, face = "bold"),
legend.position = "none",
axis.text = element_text(size = 10)
)
Existe una fuerte asociación positiva entre el PIB per cápita y el IDH, pero no es completamente lineal. El gráfico refleja que el crecimiento económico tiende a ir acompañado de un mejor desarrollo humano, aunque hay factores adicionales (como educación, salud o desigualdad) que también influyen.
p3 <- ggplot(datos, aes(x = PIB_per_capita, y = IDH)) +
geom_point(aes(color = Continente), alpha = 0.7, size = 3) +
geom_smooth(method = "lm", se = FALSE, color = "black", linetype = "dashed") +
labs(title = "Relacion entre PIB per capita e IDH",
x = "PIB per capita", y = "Indice de Desarrollo Humano") +
theme_minimal()
plotly::ggplotly(p3)
## `geom_smooth()` using formula = 'y ~ x'
Aunque las medianas son similares, la variabilidad es mucho mayor en países con esperanza de vida baja,los países con esperanza de vida baja tienen más casos extremos (outliers), con algunos reportando tasas de suicidio alarmantemente altas.
Esto indica que, en contextos con baja esperanza de vida, podrían existir factores adicionales que incrementan el riesgo de suicidios en ciertos países, pero no de forma generalizada.
p1 <- ggplot(datos, aes(x = esperanza_alta, y = Suicidios)) +
geom_boxplot(fill = "skyblue") +
labs(title = "Suicidios vs Esperanza de vida alta", x = "Esperanza de vida alta", y = "Suicidios")
ggplotly(p1)
# 1. Cargar y preparar datos
datos <- read_excel("Base_de_datos1.xlsx", sheet = "Sheet1")
datos$esperanza_alta <- as.factor(ifelse(datos$Esperanza_de_vida >= 75, "Alta", "Baja"))
# 2. Crear conjuntos de entrenamiento y prueba
set.seed(28)
index_muestra <- sample(nrow(datos), 100)
index_entrena <- sample(index_muestra, 50)
index_test <- index_muestra[!index_muestra %in% index_entrena]
# 1. Cargar y preparar datos
datos <- read_excel("Base_de_datos1.xlsx", sheet = "Sheet1")
datos$esperanza_alta <- as.factor(ifelse(datos$Esperanza_de_vida >= 75, "Alta", "Baja"))
# 2. Crear conjuntos de entrenamiento y prueba
set.seed(28)
index_muestra <- sample(nrow(datos), 100)
index_entrena <- sample(index_muestra, 50)
index_test <- index_muestra[!index_muestra %in% index_entrena]
# 3. Separar inputs y outputs
entrena_input <- datos[index_entrena, c("Mortalidad_Infantil", "Consumo_de_alcohol_Per_Capita", "Uso_de_servicios_de_agua_potable")]
entrena_output <- datos$esperanza_alta[index_entrena]
test_input <- datos[index_test, c("Mortalidad_Infantil", "Consumo_de_alcohol_Per_Capita", "Uso_de_servicios_de_agua_potable")]
test_output <- datos$esperanza_alta[index_test]
# 4. Aplicar KNN (k=3)
test_output_kNN <- class::knn(entrena_input, test_input, entrena_output, k = 3)
# 5. Evaluar modelo con matriz de confusión detallada (como en tu ejemplo)
cat("\n# Matrix de confusión\n\n")
##
## # Matrix de confusión
conf_matrix <- confusionMatrix(test_output_kNN, test_output, positive = "Alta")
print(conf_matrix)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Alta Baja
## Alta 23 5
## Baja 1 21
##
## Accuracy : 0.88
## 95% CI : (0.7569, 0.9547)
## No Information Rate : 0.52
## P-Value [Acc > NIR] : 7.217e-08
##
## Kappa : 0.7611
##
## Mcnemar's Test P-Value : 0.2207
##
## Sensitivity : 0.9583
## Specificity : 0.8077
## Pos Pred Value : 0.8214
## Neg Pred Value : 0.9545
## Prevalence : 0.4800
## Detection Rate : 0.4600
## Detection Prevalence : 0.5600
## Balanced Accuracy : 0.8830
##
## 'Positive' Class : Alta
##
# 6. Data frame comparativo (igual que en código guía)
comparacion <- data.frame(Predicho = test_output_kNN, Real = test_output)
print("\nComparación predicciones vs reales:")
## [1] "\nComparación predicciones vs reales:"
print(head(comparacion))
## Predicho Real
## 1 Baja Baja
## 2 Baja Baja
## 3 Alta Alta
## 4 Alta Alta
## 5 Baja Baja
## 6 Alta Alta
# 7. Optimizar k (1-50) - Manteniendo estructura original
resultado <- data.frame(k = 1:50, precision = sapply(1:50, function(n) {
mean(class::knn(entrena_input, test_input, entrena_output, k = n) == test_output)
}))
# 8. Gráfico interactivo (sin cambios)
p <- plot_ly(resultado, x = ~k, y = ~precision, type = 'scatter', mode = 'lines+markers',
line = list(color = 'blue', width = 2),
marker = list(color = 'red', size = 8),
hoverinfo = 'text',
text = ~paste('k:', k, '<br>Precisión:', round(precision, 3))) %>%
layout(title = "Precisión del modelo KNN por valor de k",
xaxis = list(title = "Número de vecinos (k)"),
yaxis = list(title = "Precisión"))
# Mostrar gráfico interactivo
p
El modelo kNN funciona muy bien para este conjunto de datos. El alto recall indica que casi no se le escapan países que realmente tienen alta esperanza de vida (muy bajo falso negativo). Sin embargo, comete algunos errores al etiquetar como “alta” a países que en realidad son “baja” (falsos positivos).
El balance entre sensibilidad y especificidad es muy bueno, lo que significa que el modelo es confiable tanto para detectar casos positivos como negativos. El valor Kappa > 0.75 indica un acuerdo excelente entre las predicciones del modelo y la realidad (muy por encima del azar).
datos <- read_excel("Base_de_datos1.xlsx", sheet = "Sheet1")
datos$esperanza_alta <- ifelse(datos$Esperanza_de_vida >= 81, "Alta", "Baja")
datos$esperanza_alta <- as.factor(datos$esperanza_alta)
datos_modelo <- datos %>%
select(
esperanza_alta,
Mortalidad_Infantil,
Consumo_de_alcohol_Per_Capita,
Uso_de_servicios_de_agua_potable,
Continente,
PIB = `PIB per cápita (PPA, dólares internacionales 2021)`,
Muertes = `Muertes totales por enfermedades cardiovasculares`,
Suicidios = `Tasa de suicidios (ajustada por edad)`,
IDH = `Indice de desarrollo humano`,
Gasto_educ = `Gasto publico en educacion como porcentaje del PIB`
) %>%
mutate(Continente = as.factor(Continente)) %>%
na.omit()
set.seed(28)
train_index <- createDataPartition(datos_modelo$esperanza_alta, p = 0.75, list = FALSE)
datos_train <- datos_modelo[train_index, ]
datos_test <- datos_modelo[-train_index, ]
modelo_rpart <- rpart(
formula = esperanza_alta ~ .,
data = datos_train,
method = "class",
control = rpart.control(cp = 0.01, minsplit = 20, maxdepth = 5, xval = 10)
)
rpart.plot(modelo_rpart, type = 3, extra = 104, box.palette = "Blues", shadow.col = "gray", nn = TRUE)
pred_rpart <- predict(modelo_rpart, newdata = datos_test, type = "class")
prob_rpart <- predict(modelo_rpart, newdata = datos_test, type = "prob")[,2]
resultados <- confusionMatrix(pred_rpart, datos_test$esperanza_alta, positive = "Alta")
print(resultados)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Alta Baja
## Alta 5 2
## Baja 2 17
##
## Accuracy : 0.8462
## 95% CI : (0.6513, 0.9564)
## No Information Rate : 0.7308
## P-Value [Acc > NIR] : 0.1322
##
## Kappa : 0.609
##
## Mcnemar's Test P-Value : 1.0000
##
## Sensitivity : 0.7143
## Specificity : 0.8947
## Pos Pred Value : 0.7143
## Neg Pred Value : 0.8947
## Prevalence : 0.2692
## Detection Rate : 0.1923
## Detection Prevalence : 0.2692
## Balanced Accuracy : 0.8045
##
## 'Positive' Class : Alta
##
importancia <- varImp(modelo_rpart)
importancia %>% arrange(desc(Overall)) %>% print()
## Overall
## IDH 26.005263
## PIB 24.288755
## Mortalidad_Infantil 19.125806
## Uso_de_servicios_de_agua_potable 18.721299
## Continente 8.217215
## Suicidios 2.819577
## Consumo_de_alcohol_Per_Capita 1.814815
## Muertes 0.000000
## Gasto_educ 0.000000
El hecho de que el árbol logre un AUC alto significa que el modelo no solo es preciso, sino que separa muy bien las clases (la curva ROC muestra una separación robusta entre verdaderos positivos y falsos positivos).
pred_roc <- prediction(prob_rpart, datos_test$esperanza_alta)
perf_roc <- performance(pred_roc, "tpr", "fpr")
plot(perf_roc, colorize = TRUE, main = "Curva ROC - Árbol RPART")
abline(a = 0, b = 1, lty = 2, col = "gray")
auc_value <- performance(pred_roc, "auc")@y.values[[1]]
legend("bottomright", legend = paste("AUC =", round(auc_value, 3)), box.lty = 0)
cat("Exactitud (Accuracy):", round(resultados$overall['Accuracy'], 3), "\n")
## Exactitud (Accuracy): 0.846
cat("Sensibilidad (Recall):", round(resultados$byClass['Sensitivity'], 3), "\n")
## Sensibilidad (Recall): 0.714
cat("Especificidad:", round(resultados$byClass['Specificity'], 3), "\n")
## Especificidad: 0.895
cat("AUC:", round(auc_value, 3), "\n")
## AUC: 0.932
Los árboles (rpart y tree) destacan por su capacidad explicativa, mostrando qué factores dividen las clases y cuáles son las reglas de decisión.
## 1. Asegurar nombres de columnas consistentes
names(datos_train) <- make.names(names(datos_train))
names(datos_test) <- make.names(names(datos_test))
## 2. Entrenamiento y poda (código original)
arbol_clasificacion <- tree(
formula = esperanza_alta ~ .,
data = datos_train,
control = tree.control(nobs = nrow(datos_train), minsize = 20, mindev = 0.005)
)
arbol_podado <- prune.tree(arbol_clasificacion, best = 5)
## Warning in prune.tree(arbol_clasificacion, best = 5): best is bigger than tree
## size
## 3. Visualización del árbol
plot(arbol_podado)
text(arbol_podado, pretty = 0)
summary(arbol_podado)
##
## Classification tree:
## tree(formula = esperanza_alta ~ ., data = datos_train, control = tree.control(nobs = nrow(datos_train),
## minsize = 20, mindev = 0.005))
## Variables actually used in tree construction:
## [1] "IDH" "Uso_de_servicios_de_agua_potable"
## Number of terminal nodes: 3
## Residual mean deviance: 0.1969 = 15.16 / 77
## Misclassification error rate: 0.0625 = 5 / 80
## 4. Generación de probabilidades (CORREGIDO)
probabilidades <- predict(arbol_podado, newdata = datos_test, type = "vector")[,2]
## 5. Curva ROC y AUC
library(ROCR)
pred_roc <- prediction(probabilidades, datos_test$esperanza_alta)
perf_roc <- performance(pred_roc, "tpr", "fpr")
plot(perf_roc, colorize = TRUE, main = "Curva ROC - Árbol de Decisión")
abline(a = 0, b = 1, lty = 2)
auc_value <- performance(pred_roc, "auc")@y.values[[1]]
legend("bottomright", legend = paste("AUC =", round(auc_value, 3)), bty = "n")