Introducción

Este documento presenta un análisis integral de datos enfocado en técnicas estadísticas y visualización. A lo largo de mi trayectoria como analista, he trabajado con diversos conjuntos de datos donde la combinación de métodos descriptivos e inferenciales permite extraer insights valiosos para la toma de decisiones.

El objetivo aquí es mostrar un flujo de trabajo completo: desde la exploración inicial hasta la aplicación de modelos estadísticos, siempre manteniendo un enfoque práctico y orientado a resultados.


1. Exploración y Limpieza de Datos

Vamos a trabajar con el conjunto de datos mtcars, un clásico que nos permite demostrar técnicas fundamentales. Aunque es un dataset conocido, la forma en que lo abordamos es lo que marca la diferencia en un análisis profesional.

# Cargamos y preparamos los datos
datos <- mtcars %>%
  mutate(
    transmission = factor(am, levels = c(0, 1), labels = c("Automática", "Manual")),
    cylinders = factor(cyl),
    efficiency_class = cut(mpg, 
                          breaks = c(0, 15, 20, 25, Inf),
                          labels = c("Baja", "Media", "Alta", "Muy Alta"))
  )

# Vista preliminar
head(datos) %>%
  kable(caption = "Primeras observaciones del dataset") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
Primeras observaciones del dataset
mpg cyl disp hp drat wt qsec vs am gear carb transmission cylinders efficiency_class
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 Manual 6 Alta
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 Manual 6 Alta
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 Manual 4 Alta
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 Automática 6 Alta
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 Automática 8 Media
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 Automática 6 Media

Estadísticas Descriptivas

Una buena práctica es comenzar con un resumen estadístico que nos dé una visión general de la distribución de nuestras variables.

# Resumen de variables numéricas clave
resumen <- datos %>%
  select(mpg, hp, wt, qsec) %>%
  summarise(across(everything(), 
                   list(Media = mean,
                        Mediana = median,
                        DE = sd,
                        Min = min,
                        Max = max))) %>%
  pivot_longer(everything(), 
               names_to = c("Variable", "Estadístico"),
               names_sep = "_") %>%
  pivot_wider(names_from = Estadístico, values_from = value)

resumen %>%
  kable(digits = 2, caption = "Estadísticos descriptivos principales") %>%
  kable_styling(bootstrap_options = c("striped", "hover"))
Estadísticos descriptivos principales
Variable Media Mediana DE Min Max
mpg 20.09 19.20 6.03 10.40 33.90
hp 146.69 123.00 68.56 52.00 335.00
wt 3.22 3.33 0.98 1.51 5.42
qsec 17.85 17.71 1.79 14.50 22.90

2. Visualizaciones Exploratorias

La visualización es fundamental para entender patrones que las estadísticas por sí solas no revelan. Aquí muestro algunas técnicas que uso frecuentemente en mi trabajo.

Distribuciones Univariadas

# Densidad con anotaciones estadísticas
media_mpg <- mean(datos$mpg)
mediana_mpg <- median(datos$mpg)

ggplot(datos, aes(x = mpg)) +
  geom_histogram(aes(y = ..density..), bins = 12, 
                 fill = "#3498db", alpha = 0.7, color = "white") +
  geom_density(color = "#2c3e50", size = 1.2) +
  geom_vline(xintercept = media_mpg, linetype = "dashed", 
             color = "#e74c3c", size = 1) +
  geom_vline(xintercept = mediana_mpg, linetype = "dotted", 
             color = "#27ae60", size = 1) +
  annotate("text", x = media_mpg + 2, y = 0.06, 
           label = paste("Media:", round(media_mpg, 2)), 
           color = "#e74c3c", size = 4) +
  annotate("text", x = mediana_mpg - 2, y = 0.065, 
           label = paste("Mediana:", round(mediana_mpg, 2)), 
           color = "#27ae60", size = 4) +
  labs(title = "Distribución de Eficiencia de Combustible",
       subtitle = "Millas por galón (MPG) en la muestra",
       x = "MPG", y = "Densidad") +
  theme_custom

La distribución muestra una ligera asimetría hacia la derecha, con algunos vehículos de alta eficiencia que funcionan como outliers positivos.

Comparaciones por Grupos

# Boxplot comparativo con puntos individuales
ggplot(datos, aes(x = transmission, y = mpg, fill = transmission)) +
  geom_boxplot(alpha = 0.6, outlier.shape = NA) +
  geom_jitter(width = 0.2, alpha = 0.5, size = 2.5) +
  scale_fill_manual(values = c("#e67e22", "#9b59b6")) +
  stat_summary(fun = mean, geom = "point", shape = 23, 
               size = 4, fill = "yellow", color = "black") +
  labs(title = "Eficiencia según Tipo de Transmisión",
       subtitle = "El rombo amarillo indica la media del grupo",
       x = "Tipo de Transmisión",
       y = "Millas por Galón (MPG)") +
  theme_custom +
  theme(legend.position = "none")

Vemos claramente que los vehículos con transmisión manual tienden a ser más eficientes. Este es un hallazgo que amerita una prueba estadística formal.


3. Análisis de Correlación

Entender las relaciones entre variables es crucial. Voy a explorar esto desde múltiples ángulos.

# Matriz de correlación
variables_num <- datos %>% 
  select(mpg, cyl, disp, hp, drat, wt, qsec, vs, am, gear, carb)

matriz_cor <- cor(variables_num)

# Visualización elegante
corrplot(matriz_cor, method = "color", type = "upper", 
         order = "hclust", 
         addCoef.col = "black", 
         number.cex = 0.7,
         tl.col = "black", tl.srt = 45,
         col = colorRampPalette(c("#d73027", "white", "#4575b4"))(200),
         title = "Matriz de Correlaciones - Variables del Vehículo",
         mar = c(0,0,2,0))

Las correlaciones más fuertes son las esperadas: peso (wt) y cilindros (cyl) tienen correlación negativa fuerte con MPG. El desplazamiento del motor (disp) y la potencia (hp) también muestran asociaciones fuertes entre sí.

Relación Peso-Eficiencia

# Scatter plot con regresión y bandas de confianza
ggplot(datos, aes(x = wt, y = mpg)) +
  geom_point(aes(color = cylinders, size = hp), alpha = 0.7) +
  geom_smooth(method = "lm", se = TRUE, color = "#34495e", 
              fill = "#95a5a6", alpha = 0.3, size = 1.2) +
  scale_color_brewer(palette = "Set1", name = "Cilindros") +
  scale_size_continuous(name = "Potencia (HP)", range = c(3, 10)) +
  labs(title = "Relación entre Peso y Eficiencia de Combustible",
       subtitle = "El tamaño de los puntos representa la potencia del motor",
       x = "Peso (1000 lbs)",
       y = "Millas por Galón (MPG)") +
  theme_custom

La relación lineal negativa es evidente: a mayor peso, menor eficiencia. Los vehículos de 4 cilindros (en rojo) se agrupan en la zona de bajo peso y alta eficiencia.


4. Pruebas de Hipótesis

Ahora vamos a formalizar algunas de las observaciones visuales con pruebas estadísticas.

Test t: Transmisión y Eficiencia

# Prueba t de dos muestras
test_resultado <- t.test(mpg ~ transmission, data = datos, var.equal = FALSE)

# Presentación de resultados
cat("Prueba t de Welch\n")
## Prueba t de Welch
cat("=====================================\n")
## =====================================
cat("H0: Las medias de MPG son iguales entre transmisiones\n")
## H0: Las medias de MPG son iguales entre transmisiones
cat("H1: Las medias de MPG son diferentes\n\n")
## H1: Las medias de MPG son diferentes
cat("Estadístico t:", round(test_resultado$statistic, 3), "\n")
## Estadístico t: -3.767
cat("Grados de libertad:", round(test_resultado$parameter, 2), "\n")
## Grados de libertad: 18.33
cat("Valor p:", format.pval(test_resultado$p.value, digits = 3), "\n")
## Valor p: 0.00137
cat("IC 95%: [", round(test_resultado$conf.int[1], 2), ",", 
    round(test_resultado$conf.int[2], 2), "]\n")
## IC 95%: [ -11.28 , -3.21 ]

Con un valor p < 0.05, rechazamos la hipótesis nula. Hay evidencia estadística suficiente para afirmar que el tipo de transmisión está asociado con diferencias significativas en la eficiencia de combustible.

ANOVA: Cilindros y Potencia

# ANOVA de un factor
modelo_anova <- aov(hp ~ cylinders, data = datos)
summary(modelo_anova)
##             Df Sum Sq Mean Sq F value   Pr(>F)    
## cylinders    2 104031   52015   36.18 1.32e-08 ***
## Residuals   29  41696    1438                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Comparaciones post-hoc
tukey_result <- TukeyHSD(modelo_anova)
# Visualización de intervalos de confianza Tukey
tukey_df <- as.data.frame(tukey_result$cylinders)
tukey_df$comparison <- rownames(tukey_df)

ggplot(tukey_df, aes(x = comparison, y = diff)) +
  geom_point(size = 4, color = "#e74c3c") +
  geom_errorbar(aes(ymin = lwr, ymax = upr), width = 0.2, size = 1) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
  coord_flip() +
  labs(title = "Comparaciones Múltiples de Tukey",
       subtitle = "Diferencias en potencia (HP) entre grupos de cilindros",
       x = "Comparación entre Grupos",
       y = "Diferencia de Medias (IC 95%)") +
  theme_custom

Todas las comparaciones son significativas: cada aumento en cilindros está asociado con un incremento sustancial en la potencia del motor.


5. Modelado Estadístico

Finalmente, construyo un modelo de regresión lineal múltiple para predecir la eficiencia.

# Modelo multivariado
modelo <- lm(mpg ~ wt + hp + am + cyl, data = datos)

# Resumen del modelo
summary(modelo)
## 
## Call:
## lm(formula = mpg ~ wt + hp + am + cyl, data = datos)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.4765 -1.8471 -0.5544  1.2758  5.6608 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 36.14654    3.10478  11.642 4.94e-12 ***
## wt          -2.60648    0.91984  -2.834   0.0086 ** 
## hp          -0.02495    0.01365  -1.828   0.0786 .  
## am           1.47805    1.44115   1.026   0.3142    
## cyl         -0.74516    0.58279  -1.279   0.2119    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.509 on 27 degrees of freedom
## Multiple R-squared:  0.849,  Adjusted R-squared:  0.8267 
## F-statistic: 37.96 on 4 and 27 DF,  p-value: 1.025e-10
# Gráficos de diagnóstico
par(mfrow = c(2, 2))
plot(modelo, which = c(1, 2, 3, 5), col = "#3498db", pch = 19)

par(mfrow = c(1, 1))

El modelo explica aproximadamente el 84% de la varianza en MPG (R² ajustado). Los residuos muestran un comportamiento razonablemente normal, aunque hay algunos puntos influyentes que podrían investigarse más a fondo.

Predicciones del Modelo

# Predicciones vs valores reales
datos$prediccion <- predict(modelo)

ggplot(datos, aes(x = mpg, y = prediccion)) +
  geom_point(aes(color = transmission), size = 3, alpha = 0.7) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", 
              color = "gray30", size = 1) +
  scale_color_manual(values = c("#e67e22", "#9b59b6"),
                     name = "Transmisión") +
  labs(title = "Valores Observados vs Predichos",
       subtitle = "Línea de referencia indica predicción perfecta",
       x = "MPG Observado",
       y = "MPG Predicho") +
  theme_custom


Conclusiones

Este análisis demuestra un flujo de trabajo completo desde la exploración hasta el modelado:

  1. Exploración visual: Las visualizaciones revelaron patrones claros en las relaciones entre variables
  2. Validación estadística: Las pruebas de hipótesis confirmaron diferencias significativas entre grupos
  3. Modelado predictivo: El modelo de regresión múltiple captura bien la variabilidad en la eficiencia

En mi experiencia, este tipo de análisis iterativo—donde alternamos entre visualización, estadística descriptiva e inferencial—es lo que realmente genera valor en proyectos de ciencia de datos. No se trata solo de aplicar técnicas, sino de contar una historia coherente con los datos.


Información de Sesión

sessionInfo()
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 10 x64 (build 19045)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=Spanish_Colombia.utf8  LC_CTYPE=Spanish_Colombia.utf8   
## [3] LC_MONETARY=Spanish_Colombia.utf8 LC_NUMERIC=C                     
## [5] LC_TIME=Spanish_Colombia.utf8    
## 
## time zone: America/Bogota
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] kableExtra_1.4.0   knitr_1.50         RColorBrewer_1.1-3 gridExtra_2.3     
##  [5] corrplot_0.95      scales_1.4.0       lubridate_1.9.4    forcats_1.0.1     
##  [9] stringr_1.5.2      dplyr_1.1.4        purrr_1.1.0        readr_2.1.5       
## [13] tidyr_1.3.1        tibble_3.3.0       ggplot2_4.0.0      tidyverse_2.0.0   
## 
## loaded via a namespace (and not attached):
##  [1] sass_0.4.10       generics_0.1.4    xml2_1.4.0        lattice_0.22-7   
##  [5] stringi_1.8.7     hms_1.1.4         digest_0.6.37     magrittr_2.0.4   
##  [9] evaluate_1.0.5    grid_4.5.1        timechange_0.3.0  fastmap_1.2.0    
## [13] Matrix_1.7-3      jsonlite_2.0.0    mgcv_1.9-3        viridisLite_0.4.2
## [17] textshaping_1.0.4 jquerylib_0.1.4   cli_3.6.5         rlang_1.1.6      
## [21] splines_4.5.1     withr_3.0.2       cachem_1.1.0      yaml_2.3.10      
## [25] tools_4.5.1       tzdb_0.5.0        vctrs_0.6.5       R6_2.6.1         
## [29] lifecycle_1.0.4   pkgconfig_2.0.3   pillar_1.11.1     bslib_0.9.0      
## [33] gtable_0.3.6      glue_1.8.0        systemfonts_1.3.1 xfun_0.53        
## [37] tidyselect_1.2.1  rstudioapi_0.17.1 farver_2.1.2      nlme_3.1-168     
## [41] htmltools_0.5.8.1 rmarkdown_2.30    svglite_2.2.1     labeling_0.4.3   
## [45] compiler_4.5.1    S7_0.2.0