library(MASS)
library(pacman)
p_load(MASS, tidyverse, GGally, skimr, knitr)
options(scipen = 999)
data("Boston")
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))
| 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 | ▂▇▅▁▁ |
Para tener una primera impresión de los datos reales, utilizamos la función head(). Esto nos permite visualizar las primeras seis observaciones del conjunto de datos
(head(Boston))
## crim zn indus chas nox rm age dis rad tax ptratio black lstat
## 1 0.00632 18 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98
## 2 0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14
## 3 0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03
## 4 0.03237 0 2.18 0 0.458 6.998 45.8 6.0622 3 222 18.7 394.63 2.94
## 5 0.06905 0 2.18 0 0.458 7.147 54.2 6.0622 3 222 18.7 396.90 5.33
## 6 0.02985 0 2.18 0 0.458 6.430 58.7 6.0622 3 222 18.7 394.12 5.21
## medv
## 1 24.0
## 2 21.6
## 3 34.7
## 4 33.4
## 5 36.2
## 6 28.7
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
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 ...
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
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
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
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
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()
ggplot(Boston, aes(x = lstat)) +
geom_histogram(fill = "lightgreen", color = "white", bins = 15) +
theme_minimal()
ggplot(Boston, aes(x = medv)) +
geom_histogram(fill = "skyblue", color = "white", bins = 23) +
theme_minimal()
ggplot(Boston, aes(x = rm)) +
geom_histogram(fill = "salmon", color = "white", bins = 23) +
theme_minimal()
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.
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()
ggplot(Boston, aes(y = medv)) +
geom_boxplot(fill = "red") +
theme_minimal()
ggplot(Boston, aes(y = rm)) +
geom_boxplot(fill = "blue") +
theme_minimal()
ggplot(Boston, aes(y = lstat)) +
geom_boxplot(fill = "green") +
theme_minimal()
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.
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()
ggplot(Boston, aes(x = lstat, y = medv)) +
geom_point(color = "red") +
theme_minimal()
ggplot(Boston, aes(x = crim, y = medv)) +
scale_x_log10() +
geom_point(color = "purple") +
theme_minimal()
ggplot(Boston, aes(x = tax, y = medv)) +
geom_point(color = "orange") +
theme_minimal()
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.
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")])
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.