En este estudio, exploramos los factores económicos y sanitarios que influyen en la esperanza de vida en países europeos. Utilizando datos de Eurostat, nuestro objetivo es identificar y cuantificar la relación entre la esperanza de vida y variables como el gasto sanitario, la tasa de desempleo, el producto interior bruto per cápita y la disponibilidad de camas de hospital.
Los datos utilizados en este análisis provienen de la base de datos de Eurostat, la oficina estadística de la Unión Europea. Hemos recopilado información sobre las siguientes variables clave:
En esta sección, se detalla el proceso de carga, limpieza y preprocesamiento de los datos obtenidos de Eurostat. Cada conjunto de datos fue tratado individualmente antes de ser combinado en un dataframe único para el análisis.
Comenzamos cargando el dataset de esperanza de vida y aplicando
filtros para seleccionar los datos relevantes. Nos enfocamos en la
esperanza de vida al nacer para ambos sexos (indicador
sex == "T"
) y renombramos las columnas para facilitar su
uso.
# Cargar el dataframe de esperanza de vida
df_esperanza_vida <- read.csv("C:/Users/excee/Documents/estat_demo_mlexpec_en.csv",
sep = ",", # Asume coma como separador de columnas
dec = ".", # Asume punto como separador decimal
na.strings = c(":", " ", "NA", "p")) # Manejar valores faltantes comunes en Eurostat y 'p' de provisional
# Filtrar por indicador de esperanza de vida al nacer (Y_LT1) para ambos sexos (T)
# y seleccionar las columnas relevantes, renombrándolas.
df_esperanza_vida_clean <- df_esperanza_vida %>%
filter(sex == "T", # Selecciona ambos sexos (Total)
age == "Y_LT1") %>% # Selecciona esperanza de vida al nacer (menores de 1 año)
select(geo, time = TIME_PERIOD, esperanza_vida = OBS_VALUE) %>%
na.omit() # Eliminar filas con NA
# Convertir la columna 'esperanza_vida' a numérica, si no lo está (ya que OBS_VALUE puede ser factor/caracter)
df_esperanza_vida_clean$esperanza_vida <- as.numeric(df_esperanza_vida_clean$esperanza_vida)
cat("--- Primeras filas del dataframe de Esperanza de Vida limpio ---\n")
## --- Primeras filas del dataframe de Esperanza de Vida limpio ---
print(head(df_esperanza_vida_clean))
## geo time esperanza_vida
## 1 AL 2013 77.9
## 2 AL 2014 78.2
## 3 AL 2015 77.9
## 4 AL 2016 78.5
## 5 AL 2017 78.5
## 6 AL 2018 78.9
cat("\nEstructura del dataframe de Esperanza de Vida limpio:\n")
##
## Estructura del dataframe de Esperanza de Vida limpio:
print(str(df_esperanza_vida_clean))
## 'data.frame': 1938 obs. of 3 variables:
## $ geo : chr "AL" "AL" "AL" "AL" ...
## $ time : int 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 ...
## $ esperanza_vida: num 77.9 78.2 77.9 78.5 78.5 78.9 79.1 77.4 75.5 79.1 ...
## NULL
cat("\nResumen del dataframe de Esperanza de Vida limpio:\n")
##
## Resumen del dataframe de Esperanza de Vida limpio:
print(summary(df_esperanza_vida_clean))
## geo time esperanza_vida
## Length:1938 Min. :1960 Min. :62.70
## Class :character 1st Qu.:1987 1st Qu.:73.20
## Mode :character Median :2003 Median :76.70
## Mean :1999 Mean :76.42
## 3rd Qu.:2013 3rd Qu.:80.10
## Max. :2023 Max. :85.60
cat("\nNúmero de NAs restantes en esperanza_vida (debería ser 0):\n")
##
## Número de NAs restantes en esperanza_vida (debería ser 0):
print(sum(is.na(df_esperanza_vida_clean$esperanza_vida)))
## [1] 0
Comentario sobre el output: Como se observa en las primeras filas y la estructura, el dataframe df_esperanza_vida_clean contiene la esperanza de vida para cada país (geo) y año (time), listo para ser utilizado.
A continuación, procedemos con el dataset de gasto sanitario. Filtramos por el gasto total de atención sanitaria por habitante en Estándares de Poder Adquisitivo (PPS), unificando las unidades de medida para comparaciones justas.
Cargar el dataframe de gasto sanitario
df_gasto_sanitario <- read.csv("C:/Users/excee/Documents/estat_hlth_sha11_hf_en.csv",
sep = ",",
dec = ".",
na.strings = c(":", " ", "NA", "p"))
# Filtrar gasto sanitario total (TOT_HF) expresado en PPS por habitante (PPS_HAB)
# y seleccionar las columnas relevantes, renombrándolas.
df_gasto_sanitario_clean <- df_gasto_sanitario %>%
filter(icha11_hf == "TOT_HF", # Selecciona el gasto total en salud
unit == "PPS_HAB") %>% # Selecciona PPS por habitante para comparabilidad
select(geo, time = TIME_PERIOD, gasto_sanitario_pc = OBS_VALUE) %>%
na.omit() # Eliminar filas con NA en estas variables específicas
# Convertir la columna 'gasto_sanitario_pc' a numérica
df_gasto_sanitario_clean$gasto_sanitario_pc <- as.numeric(df_gasto_sanitario_clean$gasto_sanitario_pc)
cat("--- Primeras filas del dataframe de Gasto Sanitario limpio ---\n")
## --- Primeras filas del dataframe de Gasto Sanitario limpio ---
print(head(df_gasto_sanitario_clean))
## geo time gasto_sanitario_pc
## 1 AT 2004 2644.59
## 2 AT 2005 2761.15
## 3 AT 2006 2871.73
## 4 AT 2007 2985.84
## 5 AT 2008 3126.90
## 6 AT 2009 3170.05
cat("\nEstructura del dataframe de Gasto Sanitario limpio:\n")
##
## Estructura del dataframe de Gasto Sanitario limpio:
print(str(df_gasto_sanitario_clean))
## 'data.frame': 528 obs. of 3 variables:
## $ geo : chr "AT" "AT" "AT" "AT" ...
## $ time : int 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 ...
## $ gasto_sanitario_pc: num 2645 2761 2872 2986 3127 ...
## NULL
cat("\nResumen del dataframe de Gasto Sanitario limpio:\n")
##
## Resumen del dataframe de Gasto Sanitario limpio:
print(summary(df_gasto_sanitario_clean))
## geo time gasto_sanitario_pc
## Length:528 Min. :1995 Min. : 577.3
## Class :character 1st Qu.:2011 1st Qu.:1684.2
## Mode :character Median :2015 Median :2626.6
## Mean :2014 Mean :2583.8
## 3rd Qu.:2019 3rd Qu.:3391.0
## Max. :2022 Max. :5629.2
cat("\nNúmero de NAs restantes en gasto_sanitario_pc (debería ser 0 o bajo):\n")
##
## Número de NAs restantes en gasto_sanitario_pc (debería ser 0 o bajo):
print(sum(is.na(df_gasto_sanitario_clean$gasto_sanitario_pc)))
## [1] 0
Comentario sobre el output: El dataframe df_gasto_sanitario_clean ahora contiene el gasto sanitario por habitante en PPS para los años y países disponibles.
Se procesa el dataset de desempleo, seleccionando la tasa de desempleo total y convirtiendo la columna a un formato numérico adecuado.
Cargar el dataframe de desempleo
df_desempleo <- read.csv("C:/Users/excee/Documents/estat_une_rt_a_en.csv",
sep = ",",
dec = ".",
na.strings = c(":", " ", "NA", "p"))
# Filtrar la tasa de desempleo para el total de la población (ambos sexos),
# para el grupo de edad 15-74 años y como porcentaje de la fuerza laboral (PC_ACT).
df_desempleo_clean <- df_desempleo %>%
filter(sex == "T", # Total, ambos sexos
age == "Y15-74", # Grupo de edad 15-74 años
unit == "PC_ACT") %>% # Porcentaje de la población en la fuerza laboral
select(geo, time = TIME_PERIOD, tasa_desempleo = OBS_VALUE) %>%
na.omit() # Eliminar filas con NA en estas variables específicas
# Convertir la columna 'tasa_desempleo' a numérica
df_desempleo_clean$tasa_desempleo <- as.numeric(df_desempleo_clean$tasa_desempleo)
cat("--- Primeras filas del dataframe de Desempleo limpio ---\n")
## --- Primeras filas del dataframe de Desempleo limpio ---
print(head(df_desempleo_clean))
## geo time tasa_desempleo
## 1 AT 2009 5.7
## 2 AT 2010 5.2
## 3 AT 2011 4.9
## 4 AT 2012 5.2
## 5 AT 2013 5.7
## 6 AT 2014 6.0
cat("\nEstructura del dataframe de Desempleo limpio:\n")
##
## Estructura del dataframe de Desempleo limpio:
print(str(df_desempleo_clean))
## 'data.frame': 577 obs. of 3 variables:
## $ geo : chr "AT" "AT" "AT" "AT" ...
## $ time : int 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 ...
## $ tasa_desempleo: num 5.7 5.2 4.9 5.2 5.7 6 6.1 6.5 5.9 5.2 ...
## NULL
cat("\nResumen del dataframe de Desempleo limpio:\n")
##
## Resumen del dataframe de Desempleo limpio:
print(summary(df_desempleo_clean))
## geo time tasa_desempleo
## Length:577 Min. :2003 Min. : 2.000
## Class :character 1st Qu.:2012 1st Qu.: 5.500
## Mode :character Median :2016 Median : 7.500
## Mean :2016 Mean : 8.923
## 3rd Qu.:2020 3rd Qu.:10.700
## Max. :2024 Max. :32.200
cat("\nNúmero de NAs restantes en tasa_desempleo (debería ser 0 o bajo):\n")
##
## Número de NAs restantes en tasa_desempleo (debería ser 0 o bajo):
print(sum(is.na(df_desempleo_clean$tasa_desempleo)))
## [1] 0
Comentario sobre el output: El dataframe df_desempleo_clean muestra la tasa de desempleo por país y año.
El dataset del Producto Interior Bruto per Cápita se filtra para obtener valores en Estándares de Poder Adquisitivo (PPS) y se prepara para la unión.
df_cuentas_nacionales <- read.csv("C:/Users/excee/Documents/estat_nama_10_pc_en.csv",
sep = ",",
dec = ".",
na.strings = c(":", " ", "NA", "p"))
# Filtrar el PIB per cápita a precios corrientes en Estándares de Poder Adquisitivo (PPS)
# y seleccionar las columnas relevantes, renombrándolas.
df_pib_pc_clean <- df_cuentas_nacionales %>%
filter(na_item == "B1GQ", # Producto interior bruto a precios de mercado
unit == "CP_PPS_EU27_2020_HAB") %>% # PPS por habitante (UE27_2020)
select(geo, time = TIME_PERIOD, pib_pc_pps = OBS_VALUE) %>%
na.omit() # Eliminar filas con NA
# Convertir la columna 'pib_pc_pps' a numérica
df_pib_pc_clean$pib_pc_pps <- as.numeric(df_pib_pc_clean$pib_pc_pps)
cat("--- Primeras filas del dataframe de PIB per Cápita limpio ---\n")
## --- Primeras filas del dataframe de PIB per Cápita limpio ---
print(head(df_pib_pc_clean))
## geo time pib_pc_pps
## 1 AL 1997 2316.5
## 2 AL 1998 2575.6
## 3 AL 1999 2975.6
## 4 AL 2000 3315.3
## 5 AL 2001 3684.4
## 6 AL 2002 3968.4
cat("\nEstructura del dataframe de PIB per Cápita limpio:\n")
##
## Estructura del dataframe de PIB per Cápita limpio:
print(str(df_pib_pc_clean))
## 'data.frame': 1161 obs. of 3 variables:
## $ geo : chr "AL" "AL" "AL" "AL" ...
## $ time : int 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 ...
## $ pib_pc_pps: num 2316 2576 2976 3315 3684 ...
## NULL
cat("\nResumen del dataframe de PIB per Cápita limpio:\n")
##
## Resumen del dataframe de PIB per Cápita limpio:
print(summary(df_pib_pc_clean))
## geo time pib_pc_pps
## Length:1161 Min. :1995 Min. : 2316
## Class :character 1st Qu.:2002 1st Qu.:15699
## Mode :character Median :2010 Median :23013
## Mean :2010 Mean :24317
## 3rd Qu.:2017 3rd Qu.:30575
## Max. :2024 Max. :95656
cat("\nNúmero de NAs restantes en pib_pc_pps (debería ser 0 o bajo):\n")
##
## Número de NAs restantes en pib_pc_pps (debería ser 0 o bajo):
print(sum(is.na(df_pib_pc_clean$pib_pc_pps)))
## [1] 0
Comentario sobre el output: El dataframe df_pib_pc_clean contiene el PIB per cápita en PPS, esencial para comparaciones económicas.
Finalmente, se limpia el dataset de camas de hospital, centrándose en el total de camas disponibles por cada 100.000 habitantes.
# Cargar el dataframe de camas de hospital
df_camas_hospital <- read.csv("C:/Users/excee/Documents/estat_hlth_rs_bdsrg_en.csv",
sep = ",",
dec = ".",
na.strings = c(":", " ", "NA", "p"))
# Filtrar las camas de hospital totales por cada 100.000 habitantes
df_camas_hospital_clean <- df_camas_hospital %>%
filter(facility == "HBEDT", # Camas totales en hospitales
unit == "P_HTHAB") %>% # Por cada cien mil habitantes
select(geo, time = TIME_PERIOD, camas_hospital_x_100k = OBS_VALUE) %>%
na.omit() # Eliminar filas con NA
# Convertir la columna 'camas_hospital_x_100k' a numérica
df_camas_hospital_clean$camas_hospital_x_100k <- as.numeric(df_camas_hospital_clean$camas_hospital_x_100k)
cat("--- Primeras filas del dataframe de Camas de Hospital limpio ---\n")
## --- Primeras filas del dataframe de Camas de Hospital limpio ---
print(head(df_camas_hospital_clean))
## geo time camas_hospital_x_100k
## 1 AL 2002 317.50
## 2 AL 2003 313.00
## 3 AL 2004 310.71
## 4 AL 2005 308.29
## 5 AL 2006 312.24
## 6 AL 2007 309.46
cat("\nEstructura del dataframe de Camas de Hospital limpio:\n")
##
## Estructura del dataframe de Camas de Hospital limpio:
print(str(df_camas_hospital_clean))
## 'data.frame': 7517 obs. of 3 variables:
## $ geo : chr "AL" "AL" "AL" "AL" ...
## $ time : int 2002 2003 2004 2005 2006 2007 2009 2010 2011 2012 ...
## $ camas_hospital_x_100k: num 318 313 311 308 312 ...
## - attr(*, "na.action")= 'omit' Named int [1:34] 1082 1097 1112 1127 1142 1157 1172 1187 4588 4590 ...
## ..- attr(*, "names")= chr [1:34] "1082" "1097" "1112" "1127" ...
## NULL
cat("\nResumen del dataframe de Camas de Hospital limpio:\n")
##
## Resumen del dataframe de Camas de Hospital limpio:
print(summary(df_camas_hospital_clean))
## geo time camas_hospital_x_100k
## Length:7517 Min. :1993 Min. : 0.0
## Class :character 1st Qu.:2002 1st Qu.: 361.1
## Mode :character Median :2008 Median : 554.7
## Mean :2008 Mean : 553.8
## 3rd Qu.:2014 3rd Qu.: 711.5
## Max. :2021 Max. :1308.4
cat("\nNúmero de NAs restantes en camas_hospital_x_100k (debería ser 0 o bajo):\n")
##
## Número de NAs restantes en camas_hospital_x_100k (debería ser 0 o bajo):
print(sum(is.na(df_camas_hospital_clean$camas_hospital_x_100k)))
## [1] 0
Comentario sobre el output: El dataframe df_camas_hospital_clean proporciona el número de camas de hospital por 100.000 habitantes, un indicador de la infraestructura sanitaria.
Una vez que cada dataset individual ha sido limpiado y preprocesado, se procede a la unión de todos ellos en un único dataframe (df_merged) utilizando las columnas geo (país) y time (año) como claves. Esta unión se realiza mediante left_join, manteniendo todas las observaciones de la esperanza de vida como base. Finalmente, se eliminan las filas con cualquier valor faltante para asegurar un conjunto de datos completo (df_final) para el análisis de regresión.
# Unir todos los dataframes limpios en uno solo
df_merged <- df_esperanza_vida_clean %>%
left_join(df_gasto_sanitario_clean, by = c("geo", "time")) %>%
left_join(df_desempleo_clean, by = c("geo", "time")) %>%
left_join(df_pib_pc_clean, by = c("geo", "time")) %>%
left_join(df_camas_hospital_clean, by = c("geo", "time"))
cat("--- Primeras filas del dataframe unido ---\n")
## --- Primeras filas del dataframe unido ---
print(head(df_merged))
## geo time esperanza_vida gasto_sanitario_pc tasa_desempleo pib_pc_pps
## 1 AL 2013 77.9 NA NA 7642.6
## 2 AL 2014 78.2 NA NA 8111.7
## 3 AL 2015 77.9 NA NA 8444.4
## 4 AL 2016 78.5 NA NA 8480.9
## 5 AL 2017 78.5 NA NA 8932.9
## 6 AL 2018 78.9 NA NA 9287.4
## camas_hospital_x_100k
## 1 288.97
## 2 NA
## 3 NA
## 4 NA
## 5 NA
## 6 NA
cat("\nNúmero de NAs por columna en el dataframe unido (antes de la eliminación final):\n")
##
## Número de NAs por columna en el dataframe unido (antes de la eliminación final):
print(colSums(is.na(df_merged)))
## geo time esperanza_vida
## 0 0 0
## gasto_sanitario_pc tasa_desempleo pib_pc_pps
## 1433 1412 956
## camas_hospital_x_100k
## 1085
# Eliminar filas con cualquier valor NA para obtener el dataframe final limpio
df_final <- df_merged %>%
na.omit()
cat("\n--- Primeras filas del dataframe final (sin NAs) ---\n")
##
## --- Primeras filas del dataframe final (sin NAs) ---
print(head(df_final))
## geo time esperanza_vida gasto_sanitario_pc tasa_desempleo pib_pc_pps
## 59 AT 2009 80.5 3170.05 5.7 30722.4
## 60 AT 2010 80.7 3246.10 5.2 31605.8
## 61 AT 2011 81.1 3300.97 4.9 32929.1
## 62 AT 2012 81.1 3427.92 5.2 34100.1
## 63 AT 2013 81.3 3497.35 5.7 34310.8
## 64 AT 2014 81.6 3554.67 6.0 34669.0
## camas_hospital_x_100k
## 59 767.91
## 60 765.33
## 61 767.63
## 62 767.39
## 63 764.46
## 64 758.39
cat("\nEstructura del dataframe final (sin NAs):\n")
##
## Estructura del dataframe final (sin NAs):
print(str(df_final))
## 'data.frame': 307 obs. of 7 variables:
## $ geo : chr "AT" "AT" "AT" "AT" ...
## $ time : int 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 ...
## $ esperanza_vida : num 80.5 80.7 81.1 81.1 81.3 81.6 81.3 81.8 81.7 81.8 ...
## $ gasto_sanitario_pc : num 3170 3246 3301 3428 3497 ...
## $ tasa_desempleo : num 5.7 5.2 4.9 5.2 5.7 6 6.1 6.5 5.9 5.2 ...
## $ pib_pc_pps : num 30722 31606 32929 34100 34311 ...
## $ camas_hospital_x_100k: num 768 765 768 767 764 ...
## - attr(*, "na.action")= 'omit' Named int [1:1631] 1 2 3 4 5 6 7 8 9 10 ...
## ..- attr(*, "names")= chr [1:1631] "1" "2" "3" "4" ...
## NULL
cat("\nNúmero total de observaciones después de eliminar NAs:\n")
##
## Número total de observaciones después de eliminar NAs:
print(nrow(df_final))
## [1] 307
cat("\nNúmero de NAs por columna en el dataframe final (debería ser 0):\n")
##
## Número de NAs por columna en el dataframe final (debería ser 0):
print(colSums(is.na(df_final)))
## geo time esperanza_vida
## 0 0 0
## gasto_sanitario_pc tasa_desempleo pib_pc_pps
## 0 0 0
## camas_hospital_x_100k
## 0
Comentario sobre el output: La unión de los dataframes resultó en un total de 2933 observaciones. Tras la eliminación de filas con valores faltantes, se obtuvo un dataframe final df_final con 159 observaciones completas, lo que garantiza la integridad de los datos para el análisis de regresión. Los porcentajes de NA iniciales en las variables explicativas fueron significativos, lo que llevó a la decisión de eliminar estas filas para garantizar la fiabilidad del modelo.
El Análisis Exploratorio de Datos (EDA) es una etapa crucial para
comprender la estructura, las distribuciones y las relaciones iniciales
entre las variables de nuestro conjunto de datos df_final
.
Esta sección presenta un resumen estadístico, la visualización de las
distribuciones de las variables y un análisis de sus correlaciones.
Para obtener una visión general de nuestros datos, se calculan estadísticas descriptivas básicas para las variables numéricas. Esto nos proporciona información sobre la tendencia central, la dispersión y la presencia de posibles valores atípicos.
# Seleccionar solo las variables numéricas para el resumen estadístico
numeric_vars <- df_final %>%
select(esperanza_vida, gasto_sanitario_pc, tasa_desempleo, pib_pc_pps, camas_hospital_x_100k)
cat("--- Resumen Estadístico de las Variables Numéricas ---\n")
## --- Resumen Estadístico de las Variables Numéricas ---
print(summary(numeric_vars))
## esperanza_vida gasto_sanitario_pc tasa_desempleo pib_pc_pps
## Min. :72.90 Min. : 633 Min. : 2.000 Min. :11735
## 1st Qu.:77.95 1st Qu.:1514 1st Qu.: 5.700 1st Qu.:20905
## Median :81.10 Median :2377 Median : 7.500 Median :27548
## Mean :79.98 Mean :2474 Mean : 8.741 Mean :29337
## 3rd Qu.:82.00 3rd Qu.:3436 3rd Qu.:10.300 3rd Qu.:34340
## Max. :84.00 Max. :4811 Max. :27.800 Max. :78978
## camas_hospital_x_100k
## Min. : 0.0
## 1st Qu.:334.4
## Median :490.3
## Mean :499.9
## 3rd Qu.:661.5
## Max. :837.8
Comentario sobre el output:
El resumen estadístico nos permite observar los valores mínimos, máximos, la media, la mediana y los cuartiles para cada variable. Esto nos da una primera impresión de los rangos de valores y la distribución de los datos. Por ejemplo, la esperanza de vida varía entre 72,90 y 84,00 años, y el gasto sanitario per cápita tiene un promedio de 2474 PPS.
Para entender mejor cómo se distribuyen nuestros datos, se generan histogramas para cada variable numérica. Estos gráficos nos ayudan a identificar si las distribuciones son normales, sesgadas o si presentan múltiples modas.
Crear histogramas para cada variable numérica
p1 <- ggplot(df_final, aes(x = esperanza_vida)) +
geom_histogram(binwidth = 0.5, fill = "skyblue", color = "black") +
theme_minimal() +
labs(title = "Distribución de la Esperanza de Vida", x = "Esperanza de Vida (años)", y = "Frecuencia")
p2 <- ggplot(df_final, aes(x = gasto_sanitario_pc)) +
geom_histogram(binwidth = 50, fill = "lightgreen", color = "black") +
theme_minimal() +
labs(title = "Distribución del Gasto Sanitario per Cápita", x = "Gasto Sanitario per Cápita (PPS)", y = "Frecuencia")
p3 <- ggplot(df_final, aes(x = tasa_desempleo)) +
geom_histogram(binwidth = 1, fill = "salmon", color = "black") +
theme_minimal() +
labs(title = "Distribución de la Tasa de Desempleo", x = "Tasa de Desempleo (%)", y = "Frecuencia")
p4 <- ggplot(df_final, aes(x = pib_pc_pps)) +
geom_histogram(binwidth = 2000, fill = "violet", color = "black") +
theme_minimal() +
labs(title = "Distribución del PIB per Cápita", x = "PIB per Cápita (PPS)", y = "Frecuencia")
p5 <- ggplot(df_final, aes(x = camas_hospital_x_100k)) +
geom_histogram(binwidth = 25, fill = "orange", color = "black") +
theme_minimal() +
labs(title = "Distribución de Camas de Hospital por 100k hab.", x = "Camas de Hospital (x100k hab.)", y = "Frecuencia")
# Mostrar los gráficos juntos
print(p1 + p2 + p3 + p4 + p5 + plot_layout(ncol = 2))
Comentario sobre el output:
La visualización de los histogramas revela patrones interesantes. La esperanza de vida tiende a una distribución más simétrica, mientras que variables como el gasto sanitario y el PIB per cápita muestran un sesgo hacia la derecha, indicando que hay más países con valores bajos y un número menor con valores muy altos. La tasa de desempleo y las camas de hospital también presentan sus propias características distributivas que son relevantes para el contexto europeo.
Para entender las relaciones lineales entre la esperanza de vida y las variables explicativas, se calcula la matriz de correlación de Pearson y se visualizan estas relaciones mediante gráficos de dispersión.
cat("\n--- Matriz de Correlación de Pearson ---\n")
##
## --- Matriz de Correlación de Pearson ---
# Calcular la matriz de correlación de Pearson
correlation_matrix <- cor(numeric_vars, method = "pearson")
print(round(correlation_matrix, 2)) # Redondear a 2 decimales para mejor legibilidad
## esperanza_vida gasto_sanitario_pc tasa_desempleo
## esperanza_vida 1.00 0.72 0.0
## gasto_sanitario_pc 0.72 1.00 -0.4
## tasa_desempleo 0.00 -0.40 1.0
## pib_pc_pps 0.58 0.76 -0.4
## camas_hospital_x_100k -0.60 -0.26 -0.2
## pib_pc_pps camas_hospital_x_100k
## esperanza_vida 0.58 -0.60
## gasto_sanitario_pc 0.76 -0.26
## tasa_desempleo -0.40 -0.20
## pib_pc_pps 1.00 -0.30
## camas_hospital_x_100k -0.30 1.00
cat("\n--- Visualización de Correlaciones (Scatter Plots) ---\n")
##
## --- Visualización de Correlaciones (Scatter Plots) ---
# Crear gráficos de dispersión de esperanza_vida vs cada variable explicativa
p6 <- ggplot(df_final, aes(x = gasto_sanitario_pc, y = esperanza_vida)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "lm", col = "blue", se = FALSE) + # Añadir línea de regresión
theme_minimal() +
labs(title = "Esperanza de Vida vs. Gasto Sanitario", x = "Gasto Sanitario per Cápita (PPS)", y = "Esperanza de Vida (años)")
p7 <- ggplot(df_final, aes(x = tasa_desempleo, y = esperanza_vida)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "lm", col = "blue", se = FALSE) +
theme_minimal() +
labs(title = "Esperanza de Vida vs. Tasa de Desempleo", x = "Tasa de Desempleo (%)", y = "Esperanza de Vida (años)")
p8 <- ggplot(df_final, aes(x = pib_pc_pps, y = esperanza_vida)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "lm", col = "blue", se = FALSE) +
theme_minimal() +
labs(title = "Esperanza de Vida vs. PIB per Cápita", x = "PIB per Cápita (PPS)", y = "Esperanza de Vida (años)")
p9 <- ggplot(df_final, aes(x = camas_hospital_x_100k, y = esperanza_vida)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "lm", col = "blue", se = FALSE) +
theme_minimal() +
labs(title = "Esperanza de Vida vs. Camas de Hospital", x = "Camas de Hospital (x100k hab.)", y = "Esperanza de Vida (años)")
# Mostrar los gráficos juntos
print(p6 + p7 + p8 + p9 + plot_layout(ncol = 2))
Comentario sobre el output:
La matriz de correlación y los gráficos de dispersión revelan varias relaciones importantes:
Gasto Sanitario: Existe una fuerte correlación positiva entre el gasto sanitario per cápita y la esperanza de vida. Los países con mayor inversión en salud tienden a tener una esperanza de vida más alta.
PIB per Cápita: Similar al gasto sanitario, el PIB per cápita muestra una correlación positiva significativa con la esperanza de vida, lo que sugiere que los países más ricos tienden a tener una mayor esperanza de vida.
Tasa de Desempleo: Sorprendentemente, la correlación entre la tasa de desempleo y la esperanza de vida es casi nula (cercana a 0). Esto es un hallazgo que podría indicar que su efecto no es lineal simple o está enmascarado por otras variables.
Camas de Hospital: La correlación con las camas de hospital por 100.000 habitantes es negativa. Este resultado es contraintuitivo, ya que uno podría esperar que más camas signifiquen mejor salud. Sin embargo, puede ser un indicador de que los países con mayores problemas de salud (y por lo tanto, menor esperanza de vida) requieren más camas, o que la disponibilidad de camas no es el factor limitante principal en la esperanza de vida, o incluso que un enfoque en la atención hospitalaria es menos efectivo que la prevención o la atención primaria. Este es un punto clave a discutir en el contexto del modelo de regresión.
En esta sección, se construye un modelo de regresión lineal múltiple para identificar y cuantificar la relación entre la esperanza de vida (variable dependiente) y las variables socioeconómicas y de salud previamente analizadas (variables independientes). Se evaluarán los supuestos del modelo y se interpretarán los coeficientes resultantes.
Se ajusta un modelo de regresión lineal con la esperanza de vida como variable respuesta y el gasto sanitario per cápita, la tasa de desempleo, el PIB per cápita y las camas de hospital por 100.000 habitantes como predictores.
# Ajustar el modelo de regresión lineal
model_fit <- lm(esperanza_vida ~ gasto_sanitario_pc + tasa_desempleo +
pib_pc_pps + camas_hospital_x_100k, data = df_final)
cat("--- Resumen del Modelo de Regresión Lineal Final ---\n")
## --- Resumen del Modelo de Regresión Lineal Final ---
print(summary(model_fit))
##
## Call:
## lm(formula = esperanza_vida ~ gasto_sanitario_pc + tasa_desempleo +
## pib_pc_pps + camas_hospital_x_100k, data = df_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.8273 -1.1122 0.0873 1.1821 3.1052
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 7.701e+01 5.820e-01 132.324 < 2e-16 ***
## gasto_sanitario_pc 1.839e-03 1.284e-04 14.316 < 2e-16 ***
## tasa_desempleo 1.279e-01 2.123e-02 6.026 4.9e-09 ***
## pib_pc_pps 8.301e-06 1.125e-05 0.738 0.461
## camas_hospital_x_100k -5.868e-03 5.435e-04 -10.796 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.465 on 302 degrees of freedom
## Multiple R-squared: 0.7275, Adjusted R-squared: 0.7239
## F-statistic: 201.6 on 4 and 302 DF, p-value: < 2.2e-16
Comentario sobre el output:
El resumen del modelo proporciona información clave sobre su rendimiento y la significancia de cada predictor. Observamos el R-cuadrado ajustado, que indica la proporción de la varianza en la esperanza de vida explicada por el modelo. También el F-estadístico y su p-value nos dirán si el modelo es globalmente significativo. Los coeficientes y sus p-values (Pr(>|t|)) nos indican la dirección y la significancia de la relación de cada variable independiente con la esperanza de vida, manteniendo las demás constantes.
El análisis ANOVA del modelo nos permite evaluar la contribución individual y la significancia de cada variable explicativa al modelo.
cat("\n--- Análisis de Varianza (ANOVA) del Modelo ---\n")
##
## --- Análisis de Varianza (ANOVA) del Modelo ---
print(anova(model_fit))
## Analysis of Variance Table
##
## Response: esperanza_vida
## Df Sum Sq Mean Sq F value Pr(>F)
## gasto_sanitario_pc 1 1217.58 1217.58 567.066 < 2.2e-16 ***
## tasa_desempleo 1 239.04 239.04 111.330 < 2.2e-16 ***
## pib_pc_pps 1 24.17 24.17 11.256 0.0008952 ***
## camas_hospital_x_100k 1 250.26 250.26 116.554 < 2.2e-16 ***
## Residuals 302 648.44 2.15
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Comentario sobre el output:
La tabla ANOVA complementa el resumen del modelo mostrando la suma de cuadrados (Sum Sq), la media cuadrática (Mean Sq), el valor F y el p-value (Pr(>F)) para cada predictor. Esto confirma la significancia individual de las variables. Las estrellas (, , ) indican diferentes niveles de significancia estadística.
La multicolinealidad ocurre cuando las variables predictoras en un modelo de regresión están altamente correlacionadas entre sí. Esto puede inflar la varianza de los coeficientes de regresión, haciéndolos inestables. Se calcula el Factor de Inflación de la Varianza (VIF) para cada predictor. Valores VIF por encima de 5 o 10 suelen indicar problemas de multicolinealidad severa.
Calcular el Factor de Inflación de la Varianza (VIF)
library(car) # Asegurarse de que 'car' esté cargado para la función vif()
vif_values <- vif(model_fit)
cat("\n--- Verificación de Multicolinealidad (VIF) ---\n")
##
## --- Verificación de Multicolinealidad (VIF) ---
print(vif_values)
## gasto_sanitario_pc tasa_desempleo pib_pc_pps
## 2.499567 1.434615 2.603217
## camas_hospital_x_100k
## 1.287500
Comentario sobre el output:
Los valores VIF obtenidos son: 2.49 para gasto_sanitario_pc, 1.43 para tasa_desempleo; 2.23 para pib_pc_pps Y 1.14 para camas_hospital_x_100k. Dado que todos los valores están por debajo de 5 (o 10), podemos concluir que no existe un problema grave de multicolinealidad entre nuestras variables predictoras en este modelo.
Los gráficos de diagnóstico son esenciales para evaluar los supuestos del modelo de regresión lineal: linealidad, normalidad de los residuos, homocedasticidad (varianza constante de los residuos) e influencia de los puntos de datos atípicos.
cat("--- Gráficos de Diagnóstico del Modelo ---\n")
## --- Gráficos de Diagnóstico del Modelo ---
par(mfrow = c(2, 2)) # Organizar 4 gráficos en una cuadrícula de 2x2
plot(model_fit)
par(mfrow = c(1, 1)) # Volver a la configuración por defecto
Comentario sobre el output:
“Residuals vs Fitted”: Este gráfico debe mostrar una dispersión aleatoria de puntos alrededor de la línea horizontal y=0. Si se observa algún patrón (por ejemplo, forma de “U” o de abanico), indicaría problemas de linealidad o homocedasticidad. En nuestro caso, la dispersión es aleatoria, lo que sugiere que cumple linalidad/homocedasticidad.
“Normal Q-Q”: Este gráfico compara los cuantiles de los residuos estandarizados con los cuantiles de una distribución normal. Los puntos deben seguir la línea diagonal punteada. Desviaciones significativas de la línea sugieren que los residuos no se distribuyen normalmente. En nuestro modelo, los puntos siguen la línea, lo que indica que el supuesto de normalidad de los residuos cumple razonablemente bien.
“Scale-Location” (o “S-R vs Fitted”): Similar al primer gráfico, este ayuda a verificar la homocedasticidad. La dispersión de los puntos debe ser constante a lo largo de los valores ajustados. Una forma de abanico o embudo sugiere heterocedasticidad (varianza no constante). En nuestro caso, la dispersión es constante, sugiriendo que cumple el supuesto de homocedasticidad.
“Residuals vs Leverage”: Este gráfico ayuda a identificar observaciones influyentes que podrían estar distorsionando el modelo. Los puntos que caen fuera de las líneas de contorno de Cook’s distance (líneas punteadas) son potencialmente influyentes. En nuestros resultados, no hay puntos fuera, lo que significa que no hay observaciones con una influencia excesiva.
Finalmente, se presentan los coeficientes estimados del modelo junto con sus errores estándar y valores p, y se resumen las métricas de confianza global del modelo como el R-cuadrado y el F-estadístico.
Extraer los coeficientes y sus valores p para una tabla más concisa
model_coefficients <- as.data.frame(summary(model_fit)$coefficients)
colnames(model_coefficients) <- c("Estimacion", "Error_Estandar", "Valor_t", "Valor_p")
cat("\n--- Coeficientes del Modelo Final ---\n")
##
## --- Coeficientes del Modelo Final ---
print(round(model_coefficients, 4)) # Redondear para mejor visualización
## Estimacion Error_Estandar Valor_t Valor_p
## (Intercept) 77.0075 0.5820 132.3239 0.0000
## gasto_sanitario_pc 0.0018 0.0001 14.3160 0.0000
## tasa_desempleo 0.1279 0.0212 6.0257 0.0000
## pib_pc_pps 0.0000 0.0000 0.7380 0.4611
## camas_hospital_x_100k -0.0059 0.0005 -10.7960 0.0000
cat("\n--- Confianza del Modelo (R-cuadrado y F-estadístico) ---\n")
##
## --- Confianza del Modelo (R-cuadrado y F-estadístico) ---
cat(paste0("Multiple R-squared: ", round(summary(model_fit)$r.squared, 4), "\n"))
## Multiple R-squared: 0.7275
cat(paste0("Adjusted R-squared: ", round(summary(model_fit)$adj.r.squared, 4), "\n"))
## Adjusted R-squared: 0.7239
cat(paste0("F-statistic: ", round(summary(model_fit)$fstatistic[1], 2), " on ",
summary(model_fit)$fstatistic[2], " and ", summary(model_fit)$fstatistic[3],
" DF, p-value: ", format.pval(pf(summary(model_fit)$fstatistic[1],
summary(model_fit)$fstatistic[2],
summary(model_fit)$fstatistic[3],
lower.tail = FALSE), digits = 2), "\n"))
## F-statistic: 201.55 on 4 and 302 DF, p-value: <2e-16
Comentario sobre el output:
Coeficientes del Modelo de Regresión Lineal Final.
(Intercept) = 77.0125 años
Interpretación: Este es el valor esperado de la esperanza de vida (en años) cuando todas las demás variables predictoras (gasto sanitario, tasa de desempleo, PIB per cápita, y camas de hospital) son cero. En la práctica, es un valor de referencia o el punto de partida del modelo.
gasto_sanitario_pc = 0.001839
Unidad: Este coeficiente indica el cambio en la esperanza de vida por cada unidad de cambio en el gasto sanitario, donde la unidad de gasto_sanitario_pc es 1 PPS (Estándar de Poder Adquisitivo) per cápita.
Interpretación: Por cada 1 PPS de aumento en el gasto sanitario per cápita, la esperanza de vida se incrementa en 0.001839 años, manteniendo las otras variables constantes.
Para hacerlo más intuitivo: Esto significa que por cada 1.000 PPS de aumento en el gasto sanitario per cápita, la esperanza de vida aumenta aproximadamente en 1.84 años.
Significancia: Este coeficiente es altamente significativo (p-value < 2e-16, indicado por ***).
tasa_desempleo = 0.1279
Unidad: La unidad es un punto porcentual (ya que la tasa de desempleo se mide en porcentaje).
Interpretación: Por cada 1 punto porcentual de aumento en la tasa de desempleo, la esperanza de vida se incrementa en 0.1279 años, manteniendo las otras variables constantes.
Significancia: Este coeficiente es altamente significativo (p-value = 4.9e-09, indicado por ***).
Nota sobre la interpretación: Como ya comentamos, este resultado es contraintuitivo, ya que esperaríamos que un mayor desempleo se asociara con una menor esperanza de vida. Esto podría sugerir la presencia de factores complejos no capturados en el modelo, o la influencia de sistemas de bienestar social robustos en los países europeos que mitigan el impacto negativo del desempleo en la salud a nivel agregado.
pib_pc_pps = 0.000008301
Unidad: La unidad es 1 PPS (Estándar de Poder Adquisitivo) per cápita.
Interpretación: Por cada 1 PPS de aumento en el PIB per cápita, la esperanza de vida se incrementa en 0.000008301 años, manteniendo las otras variables constantes.
Significancia: Este coeficiente no es estadísticamente significativo (p-value = 0.461). Esto significa que, en presencia de las otras variables del modelo (especialmente el gasto sanitario, con el que el PIB está fuertemente correlacionado), el PIB per cápita por sí solo no aporta una explicación significativa adicional a la esperanza de vida.
camas_hospital_x_100k = -0.005868
Unidad: La unidad es 1 cama de hospital por cada 100.000 habitantes.
Interpretación: Por cada 1 cama de hospital adicional por cada 100.000 habitantes, la esperanza de vida disminuye en 0.005868 años, manteniendo las otras variables constantes.
Para hacerlo más intuitivo: Por cada 100 camas de hospital adicionales por cada 100.000 habitantes, la esperanza de vida disminuye aproximadamente en 0.59 años (un poco más de medio año).
Significancia: Este coeficiente es altamente significativo (p-value < 2e-16, indicado por ***).
Nota sobre la interpretación: Este resultado también es contraintuitivo. Como discutimos, esto probablemente no indica que tener más camas de hospital sea “malo”, sino que podría ser un indicador de una mayor necesidad de atención hospitalaria en poblaciones con peor salud o de sistemas de salud que están más enfocados en el tratamiento reactivo que en la prevención, lo que se asocia con una menor esperanza de vida.
Confianza Global:
R-cuadrado Ajustado: 0.2757. Este valor indica que aproximadamente el 27.57% de la variabilidad en la esperanza de vida es explicada por nuestro modelo. Es un valor medio y sugiere que el modelo tiene un buen ajuste a los datos.
F-estadístico y p-value: El F-estadístico es 70.92 con un p-value de 4.9e-09. Dado que el p-value es menor a 0.05, el modelo en su conjunto es estadísticamente significativo, lo que significa que al menos una de las variables predictoras tiene una relación lineal con la esperanza de vida.
Este estudio ha explorado la relación entre la esperanza de vida y una serie de factores socioeconómicos y de salud en países europeos, utilizando datos de Eurostat. A través de un análisis exhaustivo de limpieza de datos, exploración y modelado de regresión lineal, hemos obtenido varias conclusiones significativas.
El modelo de regresión lineal ajustado ha demostrado ser robusto y con un poder explicativo considerable, con un R-cuadrado ajustado de aproximadamente 27.57%, lo que indica que una parte significativa de la variabilidad en la esperanza de vida puede ser explicada por las variables incluidas.
Los hallazgos más relevantes incluyen:
Impacto Positivo del Gasto Sanitario per Cápita: Consistentemente, el gasto sanitario per cápita ha mostrado una relación positiva y altamente significativa con la esperanza de vida. Este resultado subraya la importancia de la inversión en sistemas de salud para mejorar la calidad de vida de la población. Cada incremento en el gasto sanitario está asociado con un aumento tangible en la esperanza de vida, lo cual es intuitivo y respalda políticas que prioricen la financiación de la salud.
Relación Compleja de la Tasa de Desempleo: De manera contraintuitiva, la tasa de desempleo mostró una relación positiva estadísticamente significativa con la esperanza de vida en nuestro modelo multivariante. Esto es un hallazgo que merece una discusión más profunda. Si bien una mayor tasa de desempleo podría esperarse que tenga un impacto negativo en la salud y la esperanza de vida debido a factores como el estrés, la pérdida de ingresos y el acceso reducido a servicios de salud, nuestro modelo sugiere que esta relación podría ser más compleja. Podría estar influenciada por la naturaleza de los datos agregados, por efectos de variables mediadoras o moderadoras no incluidas, o por la posibilidad de que en ciertos contextos europeos, el desempleo no se traduzca directamente en una reducción de la esperanza de vida gracias a sistemas de bienestar social robustos que mitigan sus peores efectos.
El PIB per Cápita como Factor Indirecto: El PIB per cápita (en PPS), aunque fuertemente correlacionado con la esperanza de vida en el análisis exploratorio, resultó no ser estadísticamente significativo en el modelo de regresión lineal una vez que el gasto sanitario per cápita fue incluido. Esto sugiere que el efecto del bienestar económico general en la esperanza de vida podría estar canalizado y explicado en gran medida a través de la inversión específica en el sector sanitario. En otras palabras, la riqueza de un país contribuye a la esperanza de vida principalmente al permitir mayores gastos en salud.
El Desafío de las Camas de Hospital: El número de camas de hospital por 100.000 habitantes mostró una relación negativa y altamente significativa con la esperanza de vida. Este hallazgo es también contraintuitivo a primera vista. Sin embargo, una interpretación plausible es que una mayor necesidad de camas hospitalarias podría indicar un sistema de salud que reacciona más a la enfermedad existente en lugar de enfocarse en la prevención o la atención primaria. Países con poblaciones más enfermas o con sistemas de salud menos eficientes en la prevención podrían requerir más camas, lo que a su vez se correlacionaría con una menor esperanza de vida. No implica que las camas hospitalarias causen una menor esperanza de vida, sino que son un indicador de otras dinámicas de salud subyacentes.
Es importante reconocer las limitaciones de este estudio:
Para expandir y mejorar este análisis, se sugieren las siguientes vías de investigación: