El precio de las propiedades está determinado por muchos factores, entre ellos, la superficie, la cantidad de ambientes, la ubicación, el estado o la vista. A continuación se desarrollaran algunos modelos de regresión lineal múltiple para intentar establecer las relaciones que existen entre algunos de estos factores y el precio de la propiedad.
Las variables a utilizar son:
price: precio de la propiedadl3: variable indicadora del barriorooms: cantidad de habitacionesbathrooms: cantidad de bañossurface_total: superficie totalsurface_covered: superficie cubiertaproperty_type: tipo de propiedad, puede ser un departamento, un ph o una casa# Cargo los paquetes a utilizar:
library(tidyverse)
library(plotly)
library(modelr)
library(tidymodels)
library(ggridges)
library(ggthemes)
library(ggplot2)
library(purrr)
# Como primer paso, cargo el dataset
datos <- readRDS("./ar_properties.rds")
# Paso a factores las variables categóricas
datos$l3 <- as.factor(datos$l3)
datos$property_type <- as.factor(datos$property_type)
Una vez cargado el dataset, creo un modelo para predecir el precio de las propiedades con todas las covariables. El modelo a estimar es el que se encuentra a continuación, en el mismo y en todos los modelos siguientes, se simplificó la notación de los betas de las variables dummy:
\[ Price = \beta_0 + \beta_1l3 + \beta_2rooms + \beta_3bathrooms + \beta_4surface\_total + \beta_5surface\_covered + \beta_6property\_type \]
# Utilizo la función "lm" para crear el modelo de Regresión Lineal Múltiple
modelo <- lm( price ~ l3+ rooms+ bathrooms+ surface_total+ surface_covered+ property_type, data = datos)
tidy(modelo,conf.int = TRUE,conf.level = 0.95)
glance(modelo)
Este modelo se caracteriza por tener un estimador para cada uno de los barrios. Como se observa en la salida del modelo, hay 13 barrios (Agronomía, Almagro, Barracas, Villa Real, entre otros) pero 12 coeficientes. Esto se debe a que son variables dummy, tomando como variable de control al barrio “Abasto”, es decir si la variable coinicde con el barrio vale 1, en caso contrario 0. Hay algunos coeficientes de variables de barrios no significativos, como Almagro o Villa Rita: esto significa que las variables no deberían ser tenidas en cuenta en el análisis del precio. Los barrios con coeficientes negativos implican que su precio esperado sea menor que si el barrio fuese el barrio control y lo contrario pasa con el coeficientes positivos. Otras variables dummy son las property_type significativas y positivas, es decir que el precio de los PH o Departamentos tienen una influencia positiva en el precio estimado de la propiedad con respecto a la variable control correspondiente a casas. Todas los demás coeficientes de las variables, rooms, bathrooms, surface_total, surface_covered, significativas así como el intercept. En este modelo es contraintuitivo que el coeficiente de rooms sea negativo, indicando que al agregar un cuarto el precio esperado del inmueble disminuiría. Esto es una señal que el modelo podría no ser óptimo.
En este caso el coeficiente de determinación, \(R^2\), es de 0,7764, esto significa que el modelo explica el 77% de de la variabilidad total del precio.
Como el valor p para la prueba F de la prueba de significación general es menor al nivel de significación 0.05, rechazo la hipótesis nula de que todos los coeficientes de las variables son iguales a 0, es decir concluyo que el modelo proporciona un mejor ajuste que el modelo dado solo por el intercept.
Para este punto, la idea es comparar dos tipos de propiedades y decidir cual sería mejor tener para vender:
# Con la función predict comparo el valor total de cada uno de las propiedades dadas las características del problema
predict.list <- predict(modelo,
newdata = data.frame(l3 = c("Abasto", "Balvanera"), rooms = c(3,2), bathrooms=c(2,3), surface_total=c(120,100), surface_covered=c(120,80), property_type=c("Departamento","PH")), se.fit = FALSE)
tidy(predict.list)
## # A tibble: 2 x 2
## names x
## <chr> <dbl>
## 1 1 324596.
## 2 2 215268.
La predicción arroja que el valor esperado del departamento en Abasto sea de USD324.596 y que el PH en Almagro valga USD215.268. Por lo tanto, concluyo que sería más beneficioso tener el departamento en el barrio de Abasto.
l3.Analizo la regresión lineal múltiple si no se incluyera la variable l3:
\[ Price = \beta_0 + \beta_1rooms + \beta_2bathrooms + \beta_3surface\_total + \beta_4surface\_covered + \beta_5property\_type \]
# Este modelo es idéntico al anterior pero sin agregar la variable "l3" en el sumando.
modelo2 <- lm( price ~ rooms+ bathrooms+ surface_total+ surface_covered+ property_type, data = datos)
tidy(modelo2,conf.int = TRUE,conf.level = 0.95)
glance(modelo2)
Este modelo, al igual que el primero tiene un p-valor del estadístico F menor a 0.05, esto significa que este modelo es mejor que uno sin predictores aparte del intercept. El valor de \(R^2\) es 0,68 y todos los coeficientes de los estimadores son significativos para el modelo. Como es de esperarse al aumentar la cantidad de baños, la superficie total o la superficie cubierta el precio esperado aumenta. Igual que en el modelo anterior, a priori es de esperarse que el coeficiente de rooms sea positivo en vez de negativo.
Para comparar este modelo con el anterior utilizo \(R^2\) ajustado ya que los modelos cuentan con distinta cantidad de variables explicativas. El modelo que mejor explica la variabilidad del precio es el primero, esto se ve en un valor de \(R^2\) ajustado aproximadamente un 13% más elevado.
barrios.Para este modelo, cree una nueva variable barrios que divide a los barrios según el precio por metro cuadrado promedio de las propiedades en ellos. Esta división se define por los grupos alto, medio y bajo. El primer paso que realizo es un análisis exploratorio para definir los puntos de corte de esta nueva variable.
# Creo la variable precio por m2
datos$preciom2 <- datos$price / datos$surface_total
# Realizo el análisis exploratorio mediante un histograma de precio por m2 de todos los barrios
ggplot(datos, aes(x=preciom2)) +
geom_histogram(position="identity", color="black", fill="pink")+
labs(title = "Histograma de precio por m2" )
# Veo los valores más significativos de la variable a través de la función summary
summary(datos$preciom2)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 513.3 2200.0 2666.7 2767.5 3207.5 12363.6
En el histograma puedo observar que la variable precio por m2 presenta una distribución asimétrica positiva. El precio mínimo es de USD513,3 y el máximo es USD12363,3.
# Realizo un boxplot para ver si existen valores atipicos dentro de la variable
ggplot(datos, aes(x="", y=preciom2)) +
geom_boxplot(fill="pink") + labs(title="Boxplot para precio por m2",x="",y="Precio por m2 (USD)")
Dado este gráfico de boxplot puedo observar que hay valores atípicos dentro del precio promedio de las propiedades. Para realizar un análisis más robusto, decido utilizar la mediana como medida de precio por barrio en vez del promedio.
# Creo la variable mediana de precio
medprecio <- datos %>%
group_by(l3) %>%
summarise(medPrecio = median(preciom2))
datos <- merge(x = datos, y = medprecio, by = "l3", all.x = TRUE)
# Veo el resumen de los valores que adopta la mediana de los precios
summary(datos$medPrecio)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 846.2 2374.4 2552.1 2704.9 3203.6 5426.4
# Utilizo la mediana del precio por m2 que es menos sensible que la media para graficar el precio por m2 por barrio. rafico también 2 lineas correspondientes al primer cuartil 1 y al tercer cuartil.
datos %>%
group_by(l3)%>%
summarise(Precio = median(preciom2))%>%
ggplot(aes(x = reorder(l3,Precio), y = Precio))+
geom_bar(stat = "identity", color="black", fill="pink")+
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
labs(title="Mediana de precio por m2 por barrio",x="Barrios", y="Precio por m2 (USD)")+
geom_hline(yintercept=2200, color = "black", linetype="dashed")+
geom_hline(yintercept=3000, color = "black", linetype="dashed")
Los puntos de corte utilizados para crear la nueva variable
barrios que divide a los barrios según el precio por metro cuadrado de las propiedades utilicé el primer cuartil como límite superior para el grupo bajo y en vez de utilizar el tercer cuartil para el límite inferior del grupo alto tomé el salto de precios entre Coghlan y Colegiales.
datos$barrio <- cut(datos$medPrecio, breaks = c(0,2374,3000,6000),
labels = c("bajo", "medio", "alto"),
include.lowest = TRUE)
# Paso la varaible "barrio" a categórica.
datos$barrio <- as.factor(datos$barrio)
# Veo cuantas propiedades quedaron en cada una de las nuevas clases de la variable
table(datos$barrio)
##
## bajo medio alto
## 11093 17292 17519
# Veo que barrios quedaron en cada variable
barrio_alto <- datos %>% filter(barrio=="alto") %>% select(l3) %>% unique()
barrio_medio <- datos %>% filter(barrio=="medio") %>% select(l3) %>% unique()
barrio_bajo <- datos %>% filter(barrio=="bajo") %>% select(l3) %>% unique()
Los barrios bajos son Agronomía, Balvanera, Barracas, Boca, Boedo, Catalinas, Centro / Microcentro, Congreso, Constitución, Flores, Floresta, Liniers, Mataderos, Monserrat, Monte Castro, Once, Parque Avellaneda, Parque Chacabuco, Parque Patricios, Paternal, Pompeya, San Cristobal, San Nicolás, Tribunales, Velez Sarsfield, Versalles, Villa Devoto, Villa General Mitre, Villa Lugano, Villa Luro, Villa Real, Villa Riachuelo, Villa Santa Rita y Villa Soldati. Allí hay listadas 11093 propiedades.
Los barrios medios son Abasto, Almagro, Caballito, Chacarita, Coghlan, Colegiales, Parque Centenario, Parque Chas, Retiro, Saavedra, San Telmo, Villa Crespo, Villa del Parque, Villa Ortuzar, Villa Pueyrredón y Villa Urquiza. Allí hay listadas 30099 propiedades.
Finalmente, con esta nueva variable paso a calcular el nuevo modelo lineal que predice el precio esperado de las propiedades.
\[ Price = \beta_0 + \beta_1rooms + \beta_2bathrooms + \beta_3surface\_total + \beta_4surface\_covered + \beta_5property\_type + \beta_6barrio \]
modelo3 <- lm( price ~ rooms+ bathrooms+ surface_total+ surface_covered+ property_type + barrio, data = datos)
tidy(modelo3,conf.int = TRUE,conf.level = 0.95)
glance(modelo3)
En este tercer modelo, al igual que los anteriores, presenta un estadístico F con p-valor menor a 0,05 y un \(R^2\) de 0,7484, intermedio entre los valores del primer y segundo modelo. Además, todos los coeficientes de las variables son significativas. Como en los modelos anteriores, el aumento de las superficies, la cantidad de baños o si es un departamento o Ph hace que el valor esperado sea mayor. La variable control es el barrio bajo, las variables barriomedio y barrioalto tienen coeficientes positivos como es de esperarse ya que las propiedades de barrios bajos son las que tienen la mediana de precio menor.
El modelo que explica mejor la variabilidad de los datos es el primero, el que utiliza la variable l3. A pesar que el valor de \(R^2\) ajustado es un poco mayor en el primer modelo, este tercer modelo es mucho más simple y todas las variables tienen coeficientes significativos. Elegiría como más útil a este modelo ya que creo que la simplicidad es un factor importante a tener en cuenta.
surface_patio.Dado que la interpretación de los coeficientes de las variables surface_covered y surface_total puede ser un poco problemática ya que se encuentran correlacionadas, construyo una nueva variable llamada surface_patio para la diferencia entre ambas superficies:
datos$surface_patio <- datos$surface_total - datos$surface_covered
summary(datos$surface_patio)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 0.000 5.000 9.338 10.000 91.000
En este caso, no hay ningun elemento cuya superficie total sea menor que la superficie cubierta pero si hubiese se lo eliminaría del análisis.
El modelo lineal múltiple a estimar dado por las variables surface_patio y surface_covered sería el siguiente:
\[ Price = \beta_0 + \beta_1rooms + \beta_2bathrooms + \beta_3surface\_covered + \beta_4surface\_patio + \beta_5property\_type + \beta_6barrio \]
modelo4 <- lm( price ~ rooms+ bathrooms+ surface_covered + surface_patio + property_type + barrio, data = datos)
tidy(modelo4,conf.int = TRUE,conf.level = 0.95)
glance(modelo4)
Este modelo, al igual que los anteriores, el estadistico F tiene un p-valor < 0.05 por lo tanto el modelo es estadísticamente significativo. Tiene un coeficiente de determinación \(R^2\) ajustado de 0,7483 comparable con los modelos anteriores y todas las variables significativas. El coeficiente de la variable surface_covered es positivo al igual que el surface_patio pero los valores son 2552,56 y 884,77 respectivamente. Esto significa que para el modelo, aumenta más el valor esperado de la propiedad al agregar un \(m^2\) de superficie cubierta que al agregar un \(m^2\) de superficie descubierta. El análisis de las variables barriomedio, barrioalto, property_typePH y property_typeDepartamento es análogo al del modelo anterior.
# Cuando se hace un plot de un modelo lineal podemos ver los gráficos para el estudio de los residuos
plot(modelo4)
Analizo los cuatro gráficos correspondiente a los residuos:
La transformación a través de logaritmos convierte las relaciones multiplicativas en relaciones aditivas y, de la misma manera, convierte las tendencias exponenciales en tendencias lineales. Es por eso que, al aplicar logaritmos a variables que están relacionadas multiplicativamente y/o crecen exponencialmente con el tiempo, generalmente se puede explicar su comportamiento linealmente. Las variables que podrían mejorar al transfomrarse linealmente son: precio, rooms, bathrooms y surface_covered. No se toma el surface_patio ya que cuenta con valores iguales a 0. El modelo quedaría:
\[ log(price) = \beta_0 + \beta_1log(rooms) + \beta_2log(bathrooms) + \beta_3log(surface\_covered) + \beta_4property\_type + \beta_5barrio + \beta_6surface\_patio \]
modelo5 <- lm( log(price) ~ log(rooms)+ log(bathrooms)+ log(surface_covered) + surface_patio + property_type + barrio, data = datos)
tidy(modelo5,conf.int = TRUE,conf.level = 0.95)
glance(modelo5)
El modelo tiene significancia global dada por el estadístico F. El \(R^2\) ajustado es el más alto de todos los modelos probados, es decir, este modelo es el que tiene una mayor fuerza de asociación lineal entre las variables y el precio. El último modelo tenía una variabilidad explicada de 74,83% mientras que este 82,02%.
El resultado del intercepto no tiene utilidad práctica, es el valor que toma log(precio) cuando la suma de todas las variables explciativas da 0. El coeficiente de log(rooms) es la elasticidad del precio respecto a rooms, en este caso el valor es de -0,03. Esto implica que por cada aumento del 1% de la cantidad de cuartos hay una disminución del 0.03% en el precio esperado de las propiedades. Para el coeficiente de log(bathrooms) podemos hacer el mismo análisis: si aumenta un 1% la cantidad de baños, hay un aumento de un 0,18% en el precio esperado de las propiedades. En el caso de log(surface_covered) el aumento del precio esperado sería de un 0.8%. En el caso de las varaibles que no fueron transformadas con la aplicación del logaritmo, el análisis difiere. El precio esperado de las propiedades aumenta un 0.4% por cada \(m^2\) de superficie descubierta, aumenta un 20% si se trata de un departamento o 5% si se tratara de un Ph. Para las variables dummy el análisis sería parecido: si se tratara de un barrio medio el precio esperado aumentaria casi un 18% o fuese un barrio alto un 42%.
En esta sección construyo para cada tipo de propiedad el modelo que incluye surface_patio en vez de surface_total. Para realizarlo de manera prolija y práctica utilizo la función map.
\[ Price_{property\_type }= \beta_0 + \beta_1rooms + \beta_2bathrooms + \beta_3surface\_total + \beta_4surface\_covered + \beta_5barrio \]
# Primero agrupo la data por tipo de propiedad
by_property_type <- datos %>%
group_by(property_type) %>%
nest()
# Creo la funcion de regresión lineal para usarla dentro de la función map
funcion_modelo <- function(df) {
modelo4 <- lm( price ~ rooms + bathrooms + surface_covered + surface_patio + barrio, data = df)
}
models <- map(by_property_type$data, funcion_modelo)
# Para cada tipo de departamento se calcula la función lineal múltiple y se agrega al dataframe
by_property_type <- by_property_type %>%
mutate(model = map(data, funcion_modelo))
# Extraigo de cada propiedad los resultados del cálculo de las métricas del modelo
glnc <- by_property_type %>%
mutate(glnc = map(model, glance)) %>%
unnest(glnc, .drop = TRUE)
glnc
Los tres modelos resultan significativos, es decir, se rechaza la hipótesis que todas los coeficientes de las variables sean nulos. Como los tres modelos cuentan con las mismas variables explicativas, podemos comparar cuan bien ajustan a los datos con el velor de \(R^2\): el modelo correspondiente a los departamentos presenta el valor más alto y el de las casas el menor. A pesar de ello, ninguno de los tres modelos supera en \(R^2\) del quinto modelo transformando algunas variables con el uso del logaritmo.