Se cargan las librerías

library(MASS)
library(pacman)
p_load(MASS, tidyverse, GGally, skimr, knitr)
options(scipen = 999)

Se carga el dataset

data("Boston")

Skim

A continuación, utilizamos la función skim() para obtener una visión general y un resumen estadístico del conjunto de datos “Boston”. Esto nos permite revisar rápidamente los tipos de variables, identificar la presencia de valores faltantes (NAs) y observar la distribución general de los datos.

(skim(Boston))
Data summary
Name Boston
Number of rows 506
Number of columns 14
_______________________
Column type frequency:
numeric 14
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
crim 0 1 3.61 8.60 0.01 0.08 0.26 3.68 88.98 ▇▁▁▁▁
zn 0 1 11.36 23.32 0.00 0.00 0.00 12.50 100.00 ▇▁▁▁▁
indus 0 1 11.14 6.86 0.46 5.19 9.69 18.10 27.74 ▇▆▁▇▁
chas 0 1 0.07 0.25 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
nox 0 1 0.55 0.12 0.38 0.45 0.54 0.62 0.87 ▇▇▆▅▁
rm 0 1 6.28 0.70 3.56 5.89 6.21 6.62 8.78 ▁▂▇▂▁
age 0 1 68.57 28.15 2.90 45.02 77.50 94.07 100.00 ▂▂▂▃▇
dis 0 1 3.80 2.11 1.13 2.10 3.21 5.19 12.13 ▇▅▂▁▁
rad 0 1 9.55 8.71 1.00 4.00 5.00 24.00 24.00 ▇▂▁▁▃
tax 0 1 408.24 168.54 187.00 279.00 330.00 666.00 711.00 ▇▇▃▁▇
ptratio 0 1 18.46 2.16 12.60 17.40 19.05 20.20 22.00 ▁▃▅▅▇
black 0 1 356.67 91.29 0.32 375.38 391.44 396.22 396.90 ▁▁▁▁▇
lstat 0 1 12.65 7.14 1.73 6.95 11.36 16.96 37.97 ▇▇▅▂▁
medv 0 1 22.53 9.20 5.00 17.02 21.20 25.00 50.00 ▂▇▅▁▁

Dim

Para conocer el tamaño exacto de nuestro conjunto de datos, utilizamos la función dim(). Esto nos devuelve de manera rápida el número total de filas (observaciones) y columnas (variables) que lo componen.

dim(Boston)
## [1] 506  14

Str

Para examinar la estructura interna del conjunto de datos, utilizamos la función str(). Esta herramienta nos proporciona un resumen compacto de todas las columnas, mostrando su tipo de dato (numérico, entero, factor, etc.) y una vista previa de los primeros valores de cada variable.

str(Boston)
## 'data.frame':    506 obs. of  14 variables:
##  $ crim   : num  0.00632 0.02731 0.02729 0.03237 0.06905 ...
##  $ zn     : num  18 0 0 0 0 0 12.5 12.5 12.5 12.5 ...
##  $ indus  : num  2.31 7.07 7.07 2.18 2.18 2.18 7.87 7.87 7.87 7.87 ...
##  $ chas   : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ nox    : num  0.538 0.469 0.469 0.458 0.458 0.458 0.524 0.524 0.524 0.524 ...
##  $ rm     : num  6.58 6.42 7.18 7 7.15 ...
##  $ age    : num  65.2 78.9 61.1 45.8 54.2 58.7 66.6 96.1 100 85.9 ...
##  $ dis    : num  4.09 4.97 4.97 6.06 6.06 ...
##  $ rad    : int  1 2 2 3 3 3 5 5 5 5 ...
##  $ tax    : num  296 242 242 222 222 222 311 311 311 311 ...
##  $ ptratio: num  15.3 17.8 17.8 18.7 18.7 18.7 15.2 15.2 15.2 15.2 ...
##  $ black  : num  397 397 393 395 397 ...
##  $ lstat  : num  4.98 9.14 4.03 2.94 5.33 ...
##  $ medv   : num  24 21.6 34.7 33.4 36.2 28.7 22.9 27.1 16.5 18.9 ...

Summary

Para obtener un panorama estadístico rápido de todas las variables, utilizamos la función summary(). Esta herramienta nos entrega las medidas de tendencia central y de posición básicas, como la media, la mediana, los valores mínimos y máximos, así como los cuartiles para cada columna numérica.

(summary(Boston))
##       crim                zn             indus            chas        
##  Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46   Min.   :0.00000  
##  1st Qu.: 0.08205   1st Qu.:  0.00   1st Qu.: 5.19   1st Qu.:0.00000  
##  Median : 0.25651   Median :  0.00   Median : 9.69   Median :0.00000  
##  Mean   : 3.61352   Mean   : 11.36   Mean   :11.14   Mean   :0.06917  
##  3rd Qu.: 3.67708   3rd Qu.: 12.50   3rd Qu.:18.10   3rd Qu.:0.00000  
##  Max.   :88.97620   Max.   :100.00   Max.   :27.74   Max.   :1.00000  
##       nox               rm             age              dis        
##  Min.   :0.3850   Min.   :3.561   Min.   :  2.90   Min.   : 1.130  
##  1st Qu.:0.4490   1st Qu.:5.886   1st Qu.: 45.02   1st Qu.: 2.100  
##  Median :0.5380   Median :6.208   Median : 77.50   Median : 3.207  
##  Mean   :0.5547   Mean   :6.285   Mean   : 68.57   Mean   : 3.795  
##  3rd Qu.:0.6240   3rd Qu.:6.623   3rd Qu.: 94.08   3rd Qu.: 5.188  
##  Max.   :0.8710   Max.   :8.780   Max.   :100.00   Max.   :12.127  
##       rad              tax           ptratio          black       
##  Min.   : 1.000   Min.   :187.0   Min.   :12.60   Min.   :  0.32  
##  1st Qu.: 4.000   1st Qu.:279.0   1st Qu.:17.40   1st Qu.:375.38  
##  Median : 5.000   Median :330.0   Median :19.05   Median :391.44  
##  Mean   : 9.549   Mean   :408.2   Mean   :18.46   Mean   :356.67  
##  3rd Qu.:24.000   3rd Qu.:666.0   3rd Qu.:20.20   3rd Qu.:396.23  
##  Max.   :24.000   Max.   :711.0   Max.   :22.00   Max.   :396.90  
##      lstat            medv      
##  Min.   : 1.73   Min.   : 5.00  
##  1st Qu.: 6.95   1st Qu.:17.02  
##  Median :11.36   Median :21.20  
##  Mean   :12.65   Mean   :22.53  
##  3rd Qu.:16.95   3rd Qu.:25.00  
##  Max.   :37.97   Max.   :50.00

Medidas descriptivas

Variables continuas clave

Para enfocar nuestro análisis, definimos un vector con las variables de mayor interés y utilizamos la función select() del paquete dplyr para extraerlas. Con esto creamos un nuevo subconjunto de datos llamado Boston_g1, del cual mostramos sus primeras filas para confirmar la selección.

variables_g1 <- c("medv", "rm", "lstat", "crim", "tax")
Boston_g1 <- Boston %>% select(all_of(variables_g1))
(head(Boston_g1))
##   medv    rm lstat    crim tax
## 1 24.0 6.575  4.98 0.00632 296
## 2 21.6 6.421  9.14 0.02731 242
## 3 34.7 7.185  4.03 0.02729 242
## 4 33.4 6.998  2.94 0.03237 222
## 5 36.2 7.147  5.33 0.06905 222
## 6 28.7 6.430  5.21 0.02985 222

Media de una y varias variables

Para iniciar con el análisis numérico específico, calculamos la media aritmética de la variable medv. Esto nos da un punto de referencia rápido sobre el valor promedio en esta zona.

mean(Boston_g1$medv)
## [1] 22.53281

En lugar de calcular el promedio variable por variable, optimizamos el proceso utilizando la función sapply(). Esto nos permite aplicar la función mean a todo nuestro subconjunto de variables de forma simultánea, obteniendo una lista rápida con los promedios de cada una.

(sapply(Boston[variables_g1], mean))
##       medv         rm      lstat       crim        tax 
##  22.532806   6.284634  12.653063   3.613524 408.237154

Desviación estándar

Para obtener una visión conjunta de las medidas de tendencia central, aplicamos la función sapply(). Esta herramienta itera sobre cada columna de nuestro grupo de variables seleccionadas y calcula su respectiva media aritmética. Así, podemos comparar fácilmente los valores promedio de características clave (como la criminalidad, el número de habitaciones y el valor de las viviendas) en una sola ejecución.

(sapply(Boston[variables_g1], sd))
##        medv          rm       lstat        crim         tax 
##   9.1971041   0.7026171   7.1410615   8.6015451 168.5371161

Histogramas

Histograma de medv, rm y lstat

Para visualizar la distribución de nuestras tres variables de mayor interés (medv, rm y lstat), primero transformamos los datos a un formato largo (long format) utilizando la función pivot_longer. Posteriormente, empleamos ggplot2 para generar histogramas individuales agrupados en un solo panel mediante facet_wrap, asignando un color distintivo a cada variable para facilitar su lectura.

Boston %>% 
  select(medv, rm, lstat) %>% 
  pivot_longer(cols = everything(),
               names_to = "variable",
               values_to = "valor") %>% 
  ggplot(aes(x = valor, fill = variable)) +
  geom_histogram(color = "white", bins = 15) +
  facet_wrap(~variable, scales = "free_x") +
  scale_fill_manual(values = c(medv = "skyblue", rm = "salmon",
                               lstat = "lightgreen")) +
  theme_minimal()

Histograma de lstat

ggplot(Boston, aes(x = lstat)) +
  geom_histogram(fill = "lightgreen", color = "white", bins = 15) +
  theme_minimal()

Histograma de medv

ggplot(Boston, aes(x = medv)) +
  geom_histogram(fill = "skyblue", color = "white", bins = 23) +
  theme_minimal()

Histograma de rm

ggplot(Boston, aes(x = rm)) +
  geom_histogram(fill = "salmon", color = "white", bins = 23) +
  theme_minimal()

Interpretación

Al observar los histogramas, notamos que el número de habitaciones (rm) presenta una distribución bastante simétrica y cercana a la normalidad. Por el contrario, el porcentaje de población de menor estatus (lstat) muestra una clara asimetría positiva (sesgo hacia la derecha). Por su parte, el valor de las viviendas (medv) tiene una distribución que se aproxima a una campana, pero con un ligero sesgo y un pico atípico en el extremo derecho (cerca del valor 50), lo que sugiere un tope en la medición de las casas más costosas.

Boxplots

Boxplot de medv y lstat

Para profundizar en la dispersión de los datos, generamos un diagrama de caja (boxplot) para las variables medv y lstat. Al igual que con los histogramas, transformamos los datos a formato largo con pivot_longer y utilizamos ggplot2 junto con geom_boxplot(). Esto nos permite visualizar en un mismo gráfico la mediana, el rango intercuartílico y los posibles valores atípicos de ambas variables.

Boston %>% 
  select(medv, lstat) %>% 
  pivot_longer(cols = everything(),
               names_to = "variable",
               values_to = "valor") %>% 
  ggplot(aes(x = valor, y = valor, fill = variable)) +
  geom_boxplot() +
  scale_fill_brewer(palette = "Set2") +  
  theme_minimal()

Boxplot de medv

ggplot(Boston, aes(y = medv)) +
  geom_boxplot(fill = "red") +
  theme_minimal()

Boxplot de rm

ggplot(Boston, aes(y = rm)) +
  geom_boxplot(fill = "blue") +
  theme_minimal()

Boxplot de lstat

ggplot(Boston, aes(y = lstat)) +
  geom_boxplot(fill = "green") +
  theme_minimal()

Interpretación

Al observar los boxplots, podemos notar que el valor mediano de las viviendas (medv) es superior y presenta una mayor dispersión total en comparación con lstat. Además, es evidente que medv concentra una gran cantidad de valores atípicos (puntos negros) en la parte superior de su distribución, lo que indica la presencia de viviendas con precios inusualmente altos. Por su parte, lstat muestra una distribución más concentrada en valores bajos, con solo algunos valores atípicos en el extremo superior.

Gráfico de dispersión

Relación de medv

Para evaluar visualmente la relación entre el valor de las viviendas (medv) y nuestras otras variables explicativas, creamos diagramas de dispersión (scatter plots) múltiples. En esta ocasión, adaptamos el uso de pivot_longer excluyendo a medv de la transformación (cols = -medv), lo que nos permite mantenerla constante como nuestra variable dependiente en el eje Y. Con geom_point() y facet_wrap(), generamos una cuadrícula que facilita la comparación simultánea.

Boston %>% 
  select(medv, rm, lstat, crim, tax) %>% 
  pivot_longer(cols = -medv,
               names_to = "variable",
               values_to = "valor") %>% 
  ggplot(aes(x = valor, y = medv, color = variable)) +
  geom_point() +
  facet_wrap(~variable, scales = "free_x") +
  scale_fill_brewer(palette = "Set2") +  
  scale_color_manual(values = c(rm = "blue", lstat = "red", crim = "purple", tax = "orange")) +
  theme_minimal()

Medv vs lstat

ggplot(Boston, aes(x = lstat, y = medv)) +
    geom_point(color = "red") +
    theme_minimal()

Medv vs crim(escala log)

ggplot(Boston, aes(x = crim, y = medv)) +
  scale_x_log10() +
  geom_point(color = "purple") +
  theme_minimal()

Medv vs tax

ggplot(Boston, aes(x = tax, y = medv)) +
  geom_point(color = "orange") +
  theme_minimal()

Interpretación

Los diagramas de dispersión revelan patrones muy distintos en la interacción con el valor de la vivienda:

  • rm (Habitaciones): Muestra una clara y fuerte relación lineal positiva; a medida que aumenta el número promedio de habitaciones, el valor de la propiedad sube consistentemente.

  • lstat (Población de menor estatus): Presenta una fuerte relación negativa, con una ligera forma curva. Las zonas con un mayor porcentaje de población de menor estatus socioeconómico están fuertemente asociadas con valores de vivienda más bajos.

  • crim (Criminalidad): Observamos un patrón en forma de “L”. Los valores de propiedad más altos se concentran casi exclusivamente en zonas donde la tasa de criminalidad es cercana a cero.

  • tax (Impuestos): La relación es más difusa en el centro de la distribución, pero destaca una marcada concentración vertical de datos en un índice de impuestos específico (cerca de 700), lo que sugiere una característica atípica en ese grupo de zonas que valdría la pena investigar.

Matriz de correlación visual

Para sintetizar la información visual y numérica en un solo paso, utilizamos la función ggpairs(). Esta potente herramienta genera una matriz que combina gráficos de densidad para cada variable en la diagonal principal, diagramas de dispersión bivariados en el triángulo inferior, y los coeficientes de correlación de Pearson correspondientes en el triángulo superior, enfocándonos en las variables medv, rm y lstat.

ggpairs(Boston[, c("medv", "rm", "lstat")])

Interpretación

Los coeficientes calculados confirman numéricamente las tendencias observadas previamente. Existe una correlación positiva fuerte (r = 0.695) entre el número de habitaciones (rm) y el valor mediano de la vivienda (medv). Por otro lado, la variable lstat muestra una fuerte correlación negativa con el valor de la vivienda (r = -0.738). Resulta interesante observar también la relación entre las variables predictoras: existe una correlación negativa considerable (r = -0.614) entre rm y lstat, indicando que las viviendas más grandes tienden a concentrarse en zonas con menor porcentaje de población de bajo estatus socioeconómico. Los asteriscos (***) en todos los coeficientes indican que estas correlaciones son altamente significativas a nivel estadístico.