A partir del análisis de bases de datos comúnmente utilizadas en estudios de predicción de riesgos en salud, surge el interés por comprender cómo diversos factores individuales pueden influir en los costos asociados a la atención médica. En particular, considerando el papel del sobrepeso y la obesidad como determinantes relevantes en la carga sanitaria global, resulta pertinente explorar su impacto económico.
En este contexto, se plantea la siguiente pregunta de investigación:
¿Cuál es la relación entre el índice de masa corporal (IMC) y los costos médicos anuales en los adultos registrados en la base de datos Insurance.csv durante el periodo disponible en el conjunto de datos?
Determinar la relación existente entre el índice de masa corporal (IMC) y los costos médicos anuales en adultos del dataset Insurance.csv, con el fin de identificar la influencia del IMC en el gasto sanitario mediante un modelo de regresión lineal múltiple, utilizando los datos recolectados por la base pública durante el periodo en el que fueron registrados.
La formulación de hipótesis se deriva del objetivo central del estudio, enfocado en establecer si el Índice de Masa Corporal (IMC) influye de manera significativa en los costos médicos anuales, tanto de forma directa como al controlar por variables demográficas y clínicas relevantes.
# ==============================================================================
# ANÁLISIS DE REGRESIÓN - COSTOS MÉDICOS (INSURANCE)
# análisis robusto, modelado y diagnóstico automático.
# ==============================================================================
# ------------------------------------------------------------------------------
# 1. INSTALACIÓN Y CARGA DE LIBRERÍAS
# ------------------------------------------------------------------------------
# Lista maestra de paquetes necesarios
paquetes <- c("tidyverse", "janitor", "skimr", "moments", "patchwork",
"broom", "caret", "car", "lmtest", "sandwich", "purrr")
# Instalación automática si faltan paquetes
nuevos_paquetes <- paquetes[!(paquetes %in% installed.packages()[,"Package"])]
if(length(nuevos_paquetes)) install.packages(nuevos_paquetes)
# Carga de librerías
suppressPackageStartupMessages({
library(tidyverse)
library(janitor)
library(skimr)
library(moments)
library(patchwork)
library(broom)
library(caret)
library(car) # VIF
library(lmtest) # Breusch-Pagan, Durbin-Watson
library(sandwich) # Errores robustos
})
# ------------------------------------------------------------------------------
# 2. CARGA DE DATOS (Inteligente: Local o URL)
# ------------------------------------------------------------------------------
cat("\n--- CARGANDO DATOS ---\n")
##
## --- CARGANDO DATOS ---
if (file.exists("insurance.csv")) {
insurance <- read_csv("insurance.csv", show_col_types = FALSE)
cat("-> Datos cargados desde archivo local 'insurance.csv'.\n")
} else {
insurance <- read_csv("https://raw.githubusercontent.com/stedy/Machine-Learning-with-R-datasets/master/insurance.csv",
show_col_types = FALSE)
cat("-> Datos cargados desde repositorio URL.\n")
}
## -> Datos cargados desde repositorio URL.
# Guardar copia raw
insurance_raw <- insurance
#------------------------------------------------------------------------------
# 3. SCRUBBING (Limpieza) E INGENIERÍA DE VARIABLES
# ------------------------------------------------------------------------------
# Limpieza de nombres y duplicados
insurance <- insurance %>%
clean_names() %>%
distinct()
# Imputación preventiva de NAs (si existieran)
na_counts <- colSums(is.na(insurance))
if (sum(na_counts) > 0) {
insurance <- insurance %>%
mutate(across(where(is.numeric), ~ ifelse(is.na(.), median(., na.rm = TRUE), .))) %>%
mutate(across(where(is.character), ~ ifelse(is.na(.), names(sort(table(.), decreasing = TRUE))[1], .)))
}
# Conversión de tipos y Creación de Variables Derivadas (Categorías útiles)
insurance <- insurance %>%
mutate(
# Tipos correctos
age = as.integer(age),
bmi = as.numeric(bmi),
children = as.integer(children),
sex = factor(sex),
smoker = factor(smoker),
region = factor(region),
charges = as.numeric(charges),
# Variables derivadas (Feature Engineering)
age_group = cut(age, breaks = c(17,29,44,59,120),
labels = c("18-29","30-44","45-59","60+"), right = TRUE),
bmi_cat = cut(bmi, breaks = c(-Inf,18.5,25,30,Inf),
labels = c("Underweight","Normal","Overweight","Obese"), right = FALSE)
)
cat("Dimensiones finales:", dim(insurance)[1], "filas x", dim(insurance)[2], "columnas.\n")
## Dimensiones finales: 1337 filas x 9 columnas.
# ------------------------------------------------------------------------------
# 4. ANÁLISIS EXPLORATORIO (EDA) Y DETECCIÓN DE OUTLIERS
# ------------------------------------------------------------------------------
cat("\n--- ESTADÍSTICOS DESCRIPTIVOS (Charges) ---\n")
##
## --- ESTADÍSTICOS DESCRIPTIVOS (Charges) ---
x <- insurance$charges
desc_stats <- tibble(
Media = mean(x), Mediana = median(x), SD = sd(x),
Asimetria = skewness(x), Curtosis = kurtosis(x),
Min = min(x), Max = max(x)
)
print(desc_stats)
## # A tibble: 1 × 7
## Media Mediana SD Asimetria Curtosis Min Max
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 13279. 9386. 12110. 1.51 4.59 1122. 63770.
Interpretación: Los costos médicos presentan una alta variabilidad y una fuerte asimetría hacia la derecha. La media es mucho mayor que la mediana, lo que indica la presencia de valores extremos elevados.
# Detección de Outliers (Método IQR)
Q1 <- quantile(x, .25); Q3 <- quantile(x, .75); IQR_val <- IQR(x)
lim_inf <- Q1 - 1.5 * IQR_val
lim_sup <- Q3 + 1.5 * IQR_val
outliers_iqr <- insurance %>% filter(charges < lim_inf | charges > lim_sup)
cat("\nNúmero de outliers detectados (IQR):", nrow(outliers_iqr), "\n")
##
## Número de outliers detectados (IQR): 139
Interpretación: Se identificó un número considerable de valores atípicos (139), lo que confirma que los costos médicos incluyen casos extremos de gasto muy elevado. Estos valores influyen en la dispersión y asimetría de la variable charges.
glimpse(insurance)
## Rows: 1,337
## Columns: 9
## $ age <int> 19, 18, 28, 33, 32, 31, 46, 37, 37, 60, 25, 62, 23, 56, 27, …
## $ sex <fct> female, male, male, male, male, female, female, female, male…
## $ bmi <dbl> 27.900, 33.770, 33.000, 22.705, 28.880, 25.740, 33.440, 27.7…
## $ children <int> 0, 1, 3, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, …
## $ smoker <fct> yes, no, no, no, no, no, no, no, no, no, no, yes, no, no, ye…
## $ region <fct> southwest, southeast, southeast, northwest, northwest, south…
## $ charges <dbl> 16884.924, 1725.552, 4449.462, 21984.471, 3866.855, 3756.622…
## $ age_group <fct> 18-29, 18-29, 18-29, 30-44, 30-44, 30-44, 45-59, 30-44, 30-4…
## $ bmi_cat <fct> Overweight, Obese, Obese, Normal, Overweight, Overweight, Ob…
print(summary(insurance))
## age sex bmi children smoker
## Min. :18.00 female:662 Min. :15.96 Min. :0.000 no :1063
## 1st Qu.:27.00 male :675 1st Qu.:26.29 1st Qu.:0.000 yes: 274
## Median :39.00 Median :30.40 Median :1.000
## Mean :39.22 Mean :30.66 Mean :1.096
## 3rd Qu.:51.00 3rd Qu.:34.70 3rd Qu.:2.000
## Max. :64.00 Max. :53.13 Max. :5.000
## region charges age_group bmi_cat
## northeast:324 Min. : 1122 18-29:416 Underweight: 20
## northwest:324 1st Qu.: 4746 30-44:392 Normal :225
## southeast:364 Median : 9386 45-59:415 Overweight :386
## southwest:325 Mean :13279 60+ :114 Obese :706
## 3rd Qu.:16658
## Max. :63770
Interpretación: La base contiene 1.337 registros de pacientes. La edad va de 18 a 64 años, con una mediana de 39 años. El BMI oscila entre 15.96 y 53.13, con una media de 30.66, lo que indica que la mayoría de personas están en sobrepeso u obesidad. La variable children varía entre 0 y 5 hijos. El 79% de los individuos no fuma (1.063 personas), mientras que el 21% son fumadores (274 personas). Las regiones están equilibradas, con cerca de 320–360 individuos por zona. Los costos médicos (charges) van desde 1.122 USD hasta 63.770 USD, con una mediana de 9.386 USD y una media de 13.279 USD, reflejando nuevamente la presencia de valores extremos altos. Las categorías de BMI muestran que 706 personas (53%) están en obesidad, 386 en sobrepeso y solo 20 en bajo peso.
print(insurance %>% count(sex) %>% mutate(freq_rel = n/sum(n)))
## # A tibble: 2 × 3
## sex n freq_rel
## <fct> <int> <dbl>
## 1 female 662 0.495
## 2 male 675 0.505
print(insurance %>% count(smoker) %>% mutate(freq_rel = n/sum(n)))
## # A tibble: 2 × 3
## smoker n freq_rel
## <fct> <int> <dbl>
## 1 no 1063 0.795
## 2 yes 274 0.205
print(insurance %>% count(region) %>% mutate(freq_rel = n/sum(n)))
## # A tibble: 4 × 3
## region n freq_rel
## <fct> <int> <dbl>
## 1 northeast 324 0.242
## 2 northwest 324 0.242
## 3 southeast 364 0.272
## 4 southwest 325 0.243
Interpretación: La muestra está equilibrada por sexo, con 49.5% mujeres y 50.5% hombres. La mayoría de los individuos no fuma (79.5%), mientras que el 20.5% son fumadores. Las cuatro regiones tienen tamaños muy similares: northeast (24.2%), northwest (24.2%), southeast (27.2%) y southwest (24.3%), lo que asegura una representación geográfica uniforme en el análisis.
p1 <- ggplot(insurance, aes(x = charges)) +
geom_histogram(bins=40, fill="steelblue", color="white") + theme_minimal() +
labs(title="Distribucion de Costos")
p2 <- ggplot(insurance, aes(x = smoker, y = charges, fill=smoker)) +
geom_boxplot() + theme_minimal() +
labs(title="Costos vs Fumar")
p3 <- ggplot(insurance, aes(x = bmi, y = charges, color=smoker)) +
geom_point(alpha=0.5) + theme_minimal() +
labs(title="BMI vs Costos")
(p1 | p2) / p3
Interpretación: La distribución de los costos es altamente asimétrica:
la mayoría de personas tiene gastos entre 0 y 20.000 USD, pero existen
valores que superan los 60.000 USD. En el boxplot, los no fumadores
presentan costos concentrados entre 2.000 y 15.000 USD, mientras que los
fumadores muestran valores mucho más altos, típicamente entre 20.000 y
45.000 USD, llegando incluso a superar los 60.000 USD. En el gráfico BMI
vs Costos, se observa que al aumentar el BMI, los costos tienden a
subir. Este efecto es más fuerte en fumadores, quienes concentran los
valores más altos, especialmente cuando el BMI supera 30.
# C. Estadísticos Descriptivos Detallados (Charges)
x <- insurance$charges
estadisticos <- list(
media = mean(x),
mediana = median(x),
sd = sd(x),
var = var(x),
rango = range(x),
iqr = IQR(x),
cv = sd(x)/mean(x), # Coeficiente de variación
asimetria = skewness(x),
curtosis = kurtosis(x)
)
cat("\n--- 4.3 ESTADÍSTICOS DETALLADOS (CHARGES) ---\n")
##
## --- 4.3 ESTADÍSTICOS DETALLADOS (CHARGES) ---
print(estadisticos)
## $media
## [1] 13279.12
##
## $mediana
## [1] 9386.161
##
## $sd
## [1] 12110.36
##
## $var
## [1] 146660811
##
## $rango
## [1] 1121.874 63770.428
##
## $iqr
## [1] 11911.37
##
## $cv
## [1] 0.911985
##
## $asimetria
## [1] 1.51369
##
## $curtosis
## [1] 4.593743
Interpretación: Los costos médicos presentan una distribución altamente dispersa: la media es 13.279 USD y la mediana 9.386 USD, con un rango entre 1.122 y 63.770 USD. La desviación estándar es muy alta (12.110 USD) y el coeficiente de variación (0.91) indica gran variabilidad relativa. La asimetría positiva (1.51) y la curtosis elevada (4.59) confirman la presencia de valores extremos y colas pesadas en la distribución.
# D. Matriz de Correlación
correlaciones <- cor(insurance %>% select(charges, bmi, age, children), use = "complete.obs")
print(correlaciones)
## charges bmi age children
## charges 1.00000000 0.19840083 0.29830821 0.06738935
## bmi 0.19840083 1.00000000 0.10934361 0.01275466
## age 0.29830821 0.10934361 1.00000000 0.04153621
## children 0.06738935 0.01275466 0.04153621 1.00000000
Interpretación: Los costos médicos (charges) muestran correlación positiva con la edad (r = 0.30) y con el BMI (r = 0.20), indicando que mayores edades y mayor índice de masa corporal se asocian con costos más altos. La correlación con número de hijos es muy débil (r = 0.07). En general, no se observan correlaciones fuertes entre las variables numéricas, lo que sugiere baja colinealidad inicial.
# ------------------------------------------------------------------------------
# 5. MODELADO (Regresión Lineal)
# ------------------------------------------------------------------------------
# Modelo 1: Simple (BMI + Edad)
modelo1 <- lm(charges ~ bmi + age, data = insurance)
# Modelo 2: Múltiple Completo
modelo2 <- lm(charges ~ bmi + age + smoker + children + sex + region, data = insurance)
# Modelo 3: Log-Lineal (Transformación logarítmica de la variable dependiente)
modelo3 <- lm(log(charges) ~ bmi + age + smoker + children + sex + region, data = insurance)
Interpretación: Se estiman tres modelos:
Modelo 1: Usa solo BMI y edad para predecir los costos médicos.
Modelo 2: Incluye todas las variables disponibles y permite capturar mejor la variabilidad real de los costos.
Modelo 3: Utiliza la transformación logarítmica de los costos para estabilizar la varianza y permitir interpretaciones porcentuales.
Estos modelos permiten comparar poder predictivo, efectos individuales y cumplimiento de supuestos.
# ---- FUNCION PARA CALCULAR RMSE ----
calc_rmse <- function(modelo, is_log = FALSE){
datos <- modelo$model
y_real <- datos[[1]]
y_pred <- modelo$fitted.values
if(is_log){
# Si el modelo es logarítmico, se vuelve a escala original
y_pred <- exp(y_pred)
}
sqrt(mean((y_real - y_pred)^2))
}
tabla_comparativa <- tibble(
Modelo = c("Modelo 1 (Simple)",
"Modelo 2 (Multiple)", # SIN TILDE
"Modelo 3 (Log)"),
Objeto = list(modelo1, modelo2, modelo3),
Is_Log = c(FALSE, FALSE, TRUE)
) %>%
mutate(
Stats = map(Objeto, ~glance(.x)),
RMSE = pmap_dbl(list(Objeto, Is_Log), ~ calc_rmse(..1, is_log = ..2))
) %>%
unnest(Stats) %>%
select(Modelo, adj.r.squared, sigma, AIC, RMSE, p.value) %>%
arrange(RMSE)
print(tabla_comparativa)
## # A tibble: 3 × 6
## Modelo adj.r.squared sigma AIC RMSE p.value
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Modelo 2 (Multiple) 0.749 6064. 27096. 6044. 0
## 2 Modelo 1 (Simple) 0.115 11390. 28776. 11377. 1.05e-36
## 3 Modelo 3 (Log) 0.766 0.444 1635. 18847. 0
Interpretación de la Tabla Comparativa de Modelos
Modelo 2 (Multiple) Es el modelo con el menor RMSE (≈ 6044), lo que indica que es el que mejor predice los costos médicos en las mismas unidades de charges. Su R² ajustado = 0.749, lo que significa que explica alrededor del 75% de la variabilidad en los costos. Es un modelo estadísticamente significativo (p-value ≈ 0).
Modelo 3 (Log) Tiene el mayor R² ajustado (0.766), lo que indica un buen ajuste. Sin embargo, su RMSE = 8358, que es mayor al del modelo múltiple, debido a que el modelo se ajusta en escala logarítmica y luego se retransforma. Sigue siendo un modelo útil, pero no el mejor en predicción directa.
Modelo 1 (Simple) Es el modelo más débil:
R² ajustado = 0.115
RMSE = 11377 (el mayor error)
El ajuste es pobre y explica solo el 11% de la variabilidad.
Conclusión General
El Modelo 2 (Multiple) es el mejor modelo predictivo en términos de RMSE, mientras que el Modelo 3 (Log) ofrece el mejor ajuste estadístico, pero no necesariamente la mejor predicción en la escala original.
diagnostico_completo <- function(model, nombre_modelo) {
cat("\n=======================================================\n")
cat(" REPORTE DE DIAGNOSTICO: ", nombre_modelo, "\n")
cat("=======================================================\n")
# Datos aumentados
aug <- augment(model)
residuos <- residuals(model)
# Normalidad (Shapiro)
shap <- shapiro.test(sample(residuos, min(length(residuos), 5000)))
# Breusch-Pagan
bp <- bptest(model)
# VIF
vif_msg <- "N/A"
if(length(coef(model)) > 2) {
vif_vals <- vif(model)
vif_msg <- ifelse(any(vif_vals > 5), "ALERTA: VIF mayor a 5", "Sin multicolinealidad seria")
}
cat(sprintf("-> Normalidad (Shapiro): p = %.4e (%s)\n",
shap$p.value,
ifelse(shap$p.value > 0.05, "Aproximadamente normal", "No normal")))
cat(sprintf("-> Homocedasticidad (BP): p = %.4e (%s)\n",
bp$p.value,
ifelse(bp$p.value > 0.05, "Homocedastico", "Heterocedastico")))
cat("-> Multicolinealidad (VIF): ", vif_msg, "\n")
# Coeficientes robustos
if(bp$p.value < 0.05) {
cat("\n[NOTA] Heterocedasticidad detectada. Coeficientes robustos (HC3):\n")
print(coeftest(model, vcov = vcovHC(model, type = "HC3")))
} else {
cat("\nCoeficientes estandar:\n")
print(tidy(model) %>% select(term, estimate, p.value))
}
# ------------------------- GRAFICOS -------------------------
p_res <- ggplot(aug, aes(.fitted, .resid)) +
geom_point(alpha=0.4) +
geom_hline(yintercept=0, color="red") +
labs(title="Residuals vs Fitted", x="Fitted", y="Residuals") +
theme_minimal()
p_qq <- ggplot(aug, aes(sample=.std.resid)) +
stat_qq() +
stat_qq_line(color="red") +
labs(title="Normal QQ Plot", x="Theoretical", y="Sample") +
theme_minimal()
p_scale <- ggplot(aug, aes(.fitted, sqrt(abs(.std.resid)))) +
geom_point(alpha=0.4) +
geom_smooth(se=FALSE, color="red") +
labs(title="Scale-Location", x="Fitted", y="Sqrt(|Std Resid|)") +
theme_minimal()
p_cook <- ggplot(aug, aes(seq_along(.cooksd), .cooksd)) +
geom_bar(stat="identity", width=0.2) +
labs(title="Cooks Distance", x="Obs", y="CookD") +
theme_minimal()
print(
(p_res | p_qq) /
(p_scale | p_cook) +
plot_annotation(title = paste("Diagnostic Plots -", nombre_modelo))
)
}
# Ejecutar diagnostico
diagnostico_completo(modelo1, "Modelo 1 Simple")
##
## =======================================================
## REPORTE DE DIAGNOSTICO: Modelo 1 Simple
## =======================================================
## -> Normalidad (Shapiro): p = 1.5368e-40 (No normal)
## -> Homocedasticidad (BP): p = 4.4598e-30 (Heterocedastico)
## -> Multicolinealidad (VIF): Sin multicolinealidad seria
##
## [NOTA] Heterocedasticidad detectada. Coeficientes robustos (HC3):
##
## t test of coefficients:
##
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -6403.054 1692.073 -3.7841 0.0001611 ***
## bmi 333.086 56.675 5.8771 5.268e-09 ***
## age 241.410 22.513 10.7232 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## `geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
El Modelo 1 analiza el gasto médico usando solo una relación lineal
entre la variable dependiente y un predictor principal.
p = 1.53e−40
Los residuos no siguen una distribución normal, lo que indica que el modelo no captura bien la estructura de variabilidad de los datos.
p = 4.46e−30
Se detecta heterocedasticidad, por lo cual los errores estándar clásicos no son confiables. → Por esto se interpretan los coeficientes con errores robustos HC3.
Al ser un modelo simple no existe multicolinealidad.
Intercepto = –6403.05: Valor esperado del gasto cuando la variable explicativa es cero (carece de interpretación práctica, pero sirve para la estructura del modelo).
bmi = 333.09: Cada unidad adicional de IMC incrementa el gasto promedio en aprox. 333 unidades, siendo altamente significativo.
age = 241.41: Cada año adicional de edad aumenta el gasto en 241 unidades, también muy significativo.
##Conclusión
El Modelo 1 captura una tendencia positiva entre las variables explicativas y los gastos médicos; sin embargo:
Presenta fuerte heterocedasticidad.
Los residuos no son normales.
Su capacidad explicativa es limitada (R² ajustado ≈ 0.115, muy baja).
➡El Modelo 1 describe parcialmente la relación, pero no explica bien la variabilidad del gasto médico. Requiere incluir más variables para mejorar su capacidad predictiva y sus supuestos estadísticos.
# Ejecutar diagnostico
diagnostico_completo(modelo2, "Modelo 2 Multiple")
##
## =======================================================
## REPORTE DE DIAGNOSTICO: Modelo 2 Multiple
## =======================================================
## -> Normalidad (Shapiro): p = 8.9362e-29 (No normal)
## -> Homocedasticidad (BP): p = 1.5704e-22 (Heterocedastico)
## -> Multicolinealidad (VIF): Sin multicolinealidad seria
##
## [NOTA] Heterocedasticidad detectada. Coeficientes robustos (HC3):
##
## t test of coefficients:
##
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -11936.558 1051.111 -11.3561 < 2.2e-16 ***
## bmi 339.250 31.883 10.6404 < 2.2e-16 ***
## age 256.765 11.981 21.4312 < 2.2e-16 ***
## smokeryes 23847.329 578.118 41.2499 < 2.2e-16 ***
## children 474.820 131.073 3.6226 0.0003027 ***
## sexmale -129.481 335.224 -0.3863 0.6993711
## regionnorthwest -349.227 487.373 -0.7165 0.4737783
## regionsoutheast -1035.266 503.432 -2.0564 0.0399373 *
## regionsouthwest -960.081 463.011 -2.0736 0.0383125 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## `geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
El Modelo 2 incluye las variables bmi, age, smoker, children, sex y region para explicar los gastos médicos. Sus resultados de diagnóstico muestran:
Shapiro–Wilk: p = 8.9362e−29
Interpretación: los residuos no siguen normalidad. Esto no afecta la validez de los coeficientes gracias al tamaño muestral, pero puede influir en inferencias clásicas.
Breusch–Pagan: p = 1.5704e−22
Interpretación: hay heterocedasticidad, por lo que los errores estándar normales no son confiables. → Se interpretan los resultados con errores robustos HC3.
VIF: valores bajos en todas las variables.
Interpretación: no existe multicolinealidad seria entre los predictores.
smokeryes: el efecto más fuerte → incrementa el gasto en aprox. 23,847 unidades (p < 2e−16).
age: efecto positivo importante (t = 21.43).
bmi: también significativo (t = 10.64).
children: incrementa los costos (t = 3.62).
sexmale: no significativo (p = 0.699).
Algunas regiones (southeast, southwest) muestran efectos negativos significativos.
Conclusión
Buen ajuste con un R² ajustado = 0.749,
Error de predicción razonablemente bajo (RMSE ≈ 6044),
Varios predictores relevantes con significancia robusta,
Solo presenta problemas de heterocedasticidad, corregidos con errores robustos.
➡Es un modelo amplio, informativo y estadísticamente consistente. Este modelo explica mucho mejor la variabilidad que el modelo simple.
# Ejecutar diagnostico
diagnostico_completo(modelo3, "Modelo 3 Log")
##
## =======================================================
## REPORTE DE DIAGNOSTICO: Modelo 3 Log
## =======================================================
## -> Normalidad (Shapiro): p = 7.1482e-35 (No normal)
## -> Homocedasticidad (BP): p = 1.6270e-13 (Heterocedastico)
## -> Multicolinealidad (VIF): Sin multicolinealidad seria
##
## [NOTA] Heterocedasticidad detectada. Coeficientes robustos (HC3):
##
## t test of coefficients:
##
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 7.0314797 0.0704985 99.7394 < 2.2e-16 ***
## bmi 0.0134013 0.0021653 6.1890 8.051e-10 ***
## age 0.0345390 0.0010184 33.9164 < 2.2e-16 ***
## smokeryes 1.5537619 0.0328463 47.3040 < 2.2e-16 ***
## children 0.1015405 0.0092420 10.9869 < 2.2e-16 ***
## sexmale -0.0745638 0.0245182 -3.0412 0.0024028 **
## regionnorthwest -0.0620490 0.0350168 -1.7720 0.0766279 .
## regionsoutheast -0.1573100 0.0368554 -4.2683 2.110e-05 ***
## regionsouthwest -0.1289664 0.0341099 -3.7809 0.0001632 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## `geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
El Modelo 3 (Log) fue evaluado mediante pruebas de supuestos, obteniendo los siguientes resultados:
Shapiro–Wilk: p = 7.1482e−35
Resultado: No cumple normalidad. Los residuos siguen siendo no normales incluso con la transformación log.
Breusch–Pagan: p = 1.6270e−13
Resultado: Existe heterocedasticidad fuerte. Por eso se usan errores estándar robustos (HC3).
VIF: No se detecta multicolinealidad seria. → Las variables explicativas no están fuertemente correlacionadas.
Todos los predictores son significativos (p < 0.001) excepto regionnorthwest (p = 0.0766).
Efectos principales:
smokeryes: efecto más alto (t = 47.3)
age: muy influyente (t = 33.9)
bmi: positivo y significativo (t = 6.18)
Conclusión corta
El Modelo 3 mejora la interpretabilidad y mantiene significancia en la mayoría de coeficientes, pero no corrige la no normalidad ni la heterocedasticidad, y presenta un RMSE mayor que el Modelo 2. Aunque útil, no es el mejor modelo en términos predictivos ni en cumplimiento de supuestos.
# ==============================================================================
# 8. CONCLUSIÓN FINAL
# ==============================================================================
mejor_modelo <- tabla_comparativa %>% slice(1) # El primero es el mejor por RMSE
cat("El modelo con mejor desempeño predictivo (menor RMSE) es:", mejor_modelo$Modelo, "\n")
## El modelo con mejor desempeño predictivo (menor RMSE) es: Modelo 2 (Multiple)
cat("RMSE:", round(mejor_modelo$RMSE, 2), "USD\n")
## RMSE: 6043.85 USD
cat("R2 Ajustado:", round(mejor_modelo$adj.r.squared, 4), "\n")
## R2 Ajustado: 0.7492
#CONCLUSIÓN FINAL
El Modelo 2 muestra el mejor desempeño predictivo, con un RMSE de 6,043.85 USD, lo que indica que sus predicciones se desvían poco del valor real. Además, con un R² ajustado de 0.7492, logra explicar cerca del 75% de la variación en los costos médicos. Esto confirma que las variables incluidas permiten predecir de manera sólida el gasto sanitario.