Introducción

En este informe se realizará un estudio del valor de la vivienda en Boston en función de diversos factores que hacen que la tasación aumente o disminuya. Se tratará de determinar si las variables existentes en el fichero de datos a analizar tienen una cierta relación con el precio aproximado de las casas. Por otra parte, dada la gran cantidad de variables con las que contamos y el inmenso número de observaciones tomadas, prestaremos atención a aquellos pares de variables cuya correlación estadística es alta.

El fichero empleado cuenta con 506 observaciones tomadas por el Servicio del Censo de EE.UU. en 1978. Estas observaciones representan los distintos vecindarios de Boston, en las que se tuvieron en cuenta tasas de criminalidad, calidad del aire, edad de las viviendas o el nivel socioeconómico de los propios residentes, entre otras características.

Desarrollo

Para empezar, leeremos nuestro fichero de datos ‘BostonHousing’, que está ubicado en la carpeta ‘data’. El fichero descargado se encuentra en formato csv.

boston_housing <- read.csv("../data/BostonHousing.csv", sep=",", encoding = "UTF-8")

A continuación, observamos un resumen de las variables con las que contamos.

summary(boston_housing)
##       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            b         
##  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

Estas 14 variables tienen nombres poco intuitivos a la hora de querer relacionarlas entre sí. Por ello, optaremos por cambiar sus nombres de modo que nos digan qué están midiendo. Aparte, habrá que tener en cuenta que no deben ser nombres muy largos para que los gráficos se puedan ver adecuadamente.

colnames(boston_housing)<-c("Crimenes", "Habitabilidad", "Bullicio", "Rio",
                            "Conc_NO", "Rooms", "Age", "Dist_Empleo",
                            "Accesos","Carga_Fiscal", "Alu_Prof",
                            "Pob_Afro", "Pobreza", "Precio")

Estos son los significados de las variables que hemos renombrado:

  1. Crimenes(crim): Indica la tasa de criminalidad por zona (crímenes por cada 100.000 habitantes).

  2. Habitabilidad (zn): Muestra la proporción de espacio residencial para lotes de más de 25.000 pies cuadrados.

  3. Bullicio (indus): Proporción de superficie para espacios comerciales donde se aglomera gran cantidad de gente por zona (acres de negocios no minoristas).

  4. Rio (chas): Variable binaria que indica si la zona limita con el río Charles (1 sí, 0 no).

  5. Conc_NO (nox): Mide la concentración de óxidos nítricos en el aire de esa zona.

  6. Rooms (rm): Proporciona la media de habitaciones por viviendas en la zona.

  7. Age (age): Estima la proporción de viviendas construidas antes del año 1940. Cuantas más casas anteriores a esta fecha, más antigua es la zona.

  8. Dist_Empleo (dis): Anota una distancia ponderada respecto a 5 centros de empleo en Boston.

  9. Accesos (rad): Nos aporta un índice de accesibilidad a las principales vías de comunicación (autopistas, carreteras).

  10. Carga_Fiscal (tax): Marca la tasa de impuesto a la vivienda respecto a su valor total. Para dos casas semejantes los impuestos a pagar serán mayores en función de la tasa.

  11. Alu_Prof (pratio): Relaciona la cantidad alumnos en colegios por cada profesor.

  12. Pob_Afro (black): Muestra la proporción de habitantes afroamericanos.

  13. Pobreza (lstat): Nos ofrece el porcentaje de población con un nivel socioeconómico bajo.

  14. Precio (medv): Corresponde al valor mediano de las viviendas en la zona (en miles de dólares).

Comprobamos que no haya ningún dato perdido en el fichero.

any(is.na(boston_housing))
## [1] FALSE

Como estrategia, generaremos un mapa de color con el que conoceremos a priori como es la relación entre cada par de variables.

attach(boston_housing)
corrplot::corrplot(cor(boston_housing))

Probaremos a graficar la distribución de los valores medianos de las casas.

hist(boston_housing$Precio, probability = T, main = "Distribución de valores mediano de las casas", xlab = "Valor mediano de la casa")
curve(dnorm(x, mean(boston_housing$Precio), sd(boston_housing$Precio)),
      add = TRUE,col='red', xlim = c(0,50))

El histograma graficado tiene una forma singular. Según va creciendo el valor de la casa la frecuencia aumenta, hasta que el valor llega a los 25.000 dolares, donde la frecuencia se desploma para luego decrecer paulatinamente. Tras dibujar la campana de Gauss, vemos que no termina de asemejarse a una distribución normal debido a la falta de simetría en el histograma.

En el mapa de calor anterior, nos dimos cuenta de que Rooms es una de las variables que juega un papel importante a la hora de decidir el precio de la vivienda. En ese caso, reflejaremos esta relación mediante un gráfico de dispersión.

cor(Precio, Rooms)
## [1] 0.6953599
plot(Rooms, Precio, xlab = "Nº de habitaciones", ylab = "Valor mediano de la casa", pch=20)
abline(lm(data.frame(Precio, Rooms)), col = 'purple', lwd=3)

La recta se ajusta a muchos puntos, pero otros muchos se alejan demasiado. Para plasmar estos errores, podemos hacer un gráfico de residuos.

lm(Precio~Rooms)
## 
## Call:
## lm(formula = Precio ~ Rooms)
## 
## Coefficients:
## (Intercept)        Rooms  
##     -34.671        9.102
m<-function(x) -34.671 + 9.102*x
e<-Precio-m(Rooms)
plot(e, type='h', ylab='Residuos', xlab='Registros')

Obsérvese que entre los registros 350 y 475 (aproximadamente) encontramos una gran cantidad de residuos. Podríamos hacer un nuevo data frame y buscarle una explicación mediante otras variables.

par(mfrow=c(2,2))

bh_2<-boston_housing[c(350:475),]
hist(bh_2$Dist_Empleo, xlab = "Distancia media a zonas de empleo",
     main = " ")

hist(bh_2$Bullicio, xlab = "Proporción de espacios comerciales de tránsito",
     main = " ")

hist(bh_2$Conc_NO, xlab = "Concentración de NO en la zona",
     main = " ")

hist(bh_2$Precio, xlab = "Valor mediano de la casa",
     main = " ")

Estos últimos registros analizados son de casas con un valor, en su mayoría, menor a los 25.000 dolares, cifra que se corresponde con la media de la variable Precio de boston_housing. Las características de estos registros se corresponden con casas donde la distancia al empleo es corta, hay alto nivel de contaminación y son zonas donde hay bastante tránsito de gente. Pueden tratarse de viviendas que se encuentran en pleno centro de Boston. Aunque, de significar eso, las casas donde hay mayor movimiento comercial y empresarial serían las más baratas, contra todo pronóstico. Sin embargo, estos vecindarios no deberían ser de alto índice de pobreza por su constante actividad económica. Salgamos de dudas con un gráfico.

hist(bh_2$Pobreza, probability = T, xlab = "Índice de pobreza", main = "Distribución de pobreza")
curve(dnorm(x, mean(bh_2$Pobreza), sd(bh_2$Pobreza)),
      add = TRUE,col='red', xlim = c(0,40))

Nótese la casi perfecta simetría del gráfico. Al parecerse el histograma a una campana de Gauss, deducimos que se trata una distribución normal donde los propietarios más frecuentes son los que tienen un índice de pobreza entorno al 15 y 20%. Ahora bien, ¿quiere decir esto que los vecindarios que hemos seleccionado tienen un índice de pobreza medio? Deberíamos en ese caso hacer una comparación con los registros de todas las zonas.

hist(boston_housing$Pobreza, probability = T, xlab = "Índice de pobreza", main = "Distribución de pobreza (Global)")
curve(dnorm(x, mean(boston_housing$Pobreza), sd(boston_housing$Pobreza)),
      add = TRUE,col='red', xlim = c(0,40))

En esta ocasión, la curva normal se ha desplazado significativamente hacia la izquierda, donde las barras de frecuencia más altas están entorno al 10%. Además, la densidad de población con un índice de pobreza entorno al 30% ha disminuido considerablemente. Entonces, las casas de bh_2 son de zonas con un índice de pobreza generalmente mayor respecto al global, lo que da una explicación a porque para estas viviendas el valor mediano es menor y no se ajustaba a la recta de regresión.

Ahora nos centraremos en el estudio de otras variables. Apreciábamos en el mapa de calor anterior que existía una fuerte correlación positiva entre la accesibilidad a las vías de comunicación y la carga fiscal de la vivienda.

cor(Accesos, Carga_Fiscal)
## [1] 0.9102282
plot(Accesos,Carga_Fiscal, pch=20)
abline(lm(Carga_Fiscal~Accesos), col='purple')

sum(Accesos>20 & Carga_Fiscal>500)
## [1] 132
sum(Carga_Fiscal>700)
## [1] 5

Parece que no tiene sentido la alta relación entre estas dos variables tras ver la nube de puntos, pero tenemos que tener en cuenta que son variables discretas, lo que quiere decir que varios puntos (x,y) se pueden repetir varias veces.

En el diagrama distinguimos tres grupos, uno en la esquina inferior izquierda donde se aglutinan la mayoría de puntos, otro en la esquina superior derecha donde se concentran 132 registros y otro grupo más pequeño (5 registros) en la esquina superior izquierda donde están los valores atípicos. El primer grupo corresponde a casas con difíciles accesos a carreteras pero menor tasa de impuestos y el segundo grupo a viviendas con mayor accesibilidad a carreteras pero con mayor carga fiscal.

cor(Conc_NO,Bullicio)
## [1] 0.7636514

La pareja de variables Conc_NO y Bullicio también tienen buena correlación. Es lógico pensar que en aquellas zonas donde hay más tráfico sean las que más problemas de contaminación del aire tengan.

Importamos la librería tidyverse para poder ilustrar los datos con representaciones gráficas.

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.4.4     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.0
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
cor(Conc_NO, Dist_Empleo)
## [1] -0.7692301
boston_housing %>% 
ggplot(aes(x=Dist_Empleo, y=Conc_NO)) +
  geom_point() +
  geom_smooth(col='red')
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

Las variables Conc_NO y Dist_Empleo deben ser inversamente proporcionales, ya que cuanto más alejada esté la vivienda del empleo más alejada también estará de otros espacios comerciales donde existe contaminación acústica. Luego, al comparar esta vez la distancia al empleo con la contaminación del aire vemos como el valor de la correlación es muy parecido en valor absoluto con el de la anterior correlación.

cor(Dist_Empleo, Age)
## [1] -0.7478805
boston_housing %>% 
ggplot(aes(x=Dist_Empleo, y=Age)) +
  geom_point() +
  geom_smooth(col='red')
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

La distancia al empleo y la antigüedad de las viviendas es inversamente proporcional. La explicación a esto es que según las ciudades van creciendo a lo largo de los años las viviendas se construyen en zonas más periféricas, de modo que el radio del núcleo urbano va creciendo con el paso del tiempo. Por esta razón, las vecindarios con viviendas de más edad se encuentran en el casco urbano de la ciudad y las más nuevas se encuentran alejadas de los puntos neurálgicos de Boston.

Para finalizar, haremos un gráfico de tarta para mostrar cuales son las variables que más han influido en el precio.

coef_cor <- cor(boston_housing)[, "Precio"]
coef_det<-coef_cor^2
coef_det<-coef_det[-14]
pie(coef_det)

Conclusión

El set de datos BostonHousing cuenta con una gran cantidad de información a la hora de establecer una relación entre el precio de la vivienda y los factores que determinan su valor. Hay variables que han tenido un papel destacado a la hora influir en el precio, como Pobreza y Rooms, lo que refleja la importancia de tener en cuenta estos aspectos en la planificación urbana y el desarrollo de políticas públicas. Por otro lado, variables como Habitabilidad, Rio o Dist_Empleo no han ayudado mucho a determinar el valor de la casa según la zona, pero han servido para establecer una relación con otras variables abriendo nuevos caminos a futuras investigaciones en el área inmobiliaria.

En definitiva, podemos concluir que el análisis de las viviendas en Boston puede ser muy útil para tomar decisiones en cuanto a inversiones inmobiliarias o políticas de vivienda se refiere.