#Se cargan los paquetes útiles para el TP
library("tidyverse")
## -- Attaching packages ------------------------------------------------------- tidyverse 1.2.1 --
## v ggplot2 3.2.1 v purrr 0.3.2
## v tibble 2.1.3 v dplyr 0.8.3
## v tidyr 0.8.3 v stringr 1.4.0
## v readr 1.3.1 v forcats 0.4.0
## -- Conflicts ---------------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library("dplyr")
library("OneR")
library("broom")
library("fastDummies")
library("MLmetrics")
##
## Attaching package: 'MLmetrics'
## The following object is masked from 'package:base':
##
## Recall
library("ggplot2")
#Se lee el archivo se muestran dos datos simples para ver la dimension y las columnas del set de datos
properties = readRDS("ar_properties.rds")
print(paste('Cantidad de registros: ' , nrow(properties)))
## [1] "Cantidad de registros: 45904"
print(colnames(properties))
## [1] "id" "l3" "rooms" "bathrooms"
## [5] "surface_total" "surface_covered" "price" "property_type"
#Modelo de Reg. lineal multiple que contempla todas las variables menos id(no tiene nada que haer para estimar los valores de las propiedades)
model <- lm(price ~ l3 + rooms + bathrooms + surface_total + surface_covered + price + property_type, data = properties )
## Warning in model.matrix.default(mt, mf, contrasts): the response appeared
## on the right-hand side and was dropped
## Warning in model.matrix.default(mt, mf, contrasts): problem with term 6 in
## model.matrix: no columns are assigned
summary(model)
##
## Call:
## lm(formula = price ~ l3 + rooms + bathrooms + surface_total +
## surface_covered + price + property_type, data = properties)
##
## Residuals:
## Min 1Q Median 3Q Max
## -400904 -33817 -3307 24660 560915
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -109406.61 4788.67 -22.847 < 2e-16 ***
## l3Agronomía 623.53 8846.14 0.070 0.943807
## l3Almagro -4520.04 4295.24 -1.052 0.292650
## l3Balvanera -24788.27 4551.65 -5.446 5.18e-08 ***
## l3Barracas -10128.24 5351.06 -1.893 0.058397 .
## l3Barrio Norte 49921.81 4417.82 11.300 < 2e-16 ***
## l3Belgrano 69648.12 4283.55 16.259 < 2e-16 ***
## l3Boca -47540.60 7076.20 -6.718 1.86e-11 ***
## l3Boedo -19034.38 5219.54 -3.647 0.000266 ***
## l3Caballito 6220.15 4301.29 1.446 0.148153
## l3Catalinas -76321.95 33563.74 -2.274 0.022974 *
## l3Centro / Microcentro -29046.49 6781.80 -4.283 1.85e-05 ***
## l3Chacarita 11903.39 5299.02 2.246 0.024687 *
## l3Coghlan 40820.55 5462.90 7.472 8.02e-14 ***
## l3Colegiales 34073.02 4816.54 7.074 1.52e-12 ***
## l3Congreso -32314.97 5494.75 -5.881 4.10e-09 ***
## l3Constitución -47292.98 6321.63 -7.481 7.50e-14 ***
## l3Flores -22510.27 4536.15 -4.962 6.99e-07 ***
## l3Floresta -28315.65 5069.38 -5.586 2.34e-08 ***
## l3Las Cañitas 90455.90 5883.38 15.375 < 2e-16 ***
## l3Liniers -20080.34 5366.27 -3.742 0.000183 ***
## l3Mataderos -33863.43 5424.79 -6.242 4.35e-10 ***
## l3Monserrat -32431.49 5228.46 -6.203 5.59e-10 ***
## l3Monte Castro -8770.72 5949.63 -1.474 0.140445
## l3Nuñez 56958.42 4559.69 12.492 < 2e-16 ***
## l3Once -30757.83 5456.51 -5.637 1.74e-08 ***
## l3Palermo 66169.58 4221.50 15.674 < 2e-16 ***
## l3Parque Avellaneda -34398.95 7598.09 -4.527 5.99e-06 ***
## l3Parque Centenario -12288.30 5016.45 -2.450 0.014305 *
## l3Parque Chacabuco -22537.83 5314.36 -4.241 2.23e-05 ***
## l3Parque Chas 5195.26 7542.97 0.689 0.490981
## l3Parque Patricios -36808.02 5973.29 -6.162 7.24e-10 ***
## l3Paternal -13314.50 5189.69 -2.566 0.010304 *
## l3Pompeya -79977.17 8035.74 -9.953 < 2e-16 ***
## l3Puerto Madero 259015.83 5095.12 50.836 < 2e-16 ***
## l3Recoleta 64088.22 4360.34 14.698 < 2e-16 ***
## l3Retiro 26067.40 5281.27 4.936 8.01e-07 ***
## l3Saavedra 19492.00 4914.18 3.966 7.31e-05 ***
## l3San Cristobal -23739.75 4955.13 -4.791 1.67e-06 ***
## l3San Nicolás -26247.55 5168.96 -5.078 3.83e-07 ***
## l3San Telmo -5653.85 4877.12 -1.159 0.246356
## l3Tribunales -34608.17 8924.63 -3.878 0.000106 ***
## l3Velez Sarsfield -25943.69 8303.75 -3.124 0.001783 **
## l3Versalles -22232.13 6758.40 -3.290 0.001004 **
## l3Villa Crespo 1595.26 4317.54 0.369 0.711770
## l3Villa del Parque -3290.17 4866.59 -0.676 0.498997
## l3Villa Devoto 13301.39 4807.08 2.767 0.005659 **
## l3Villa General Mitre -19170.08 6802.25 -2.818 0.004831 **
## l3Villa Lugano -83039.18 6533.35 -12.710 < 2e-16 ***
## l3Villa Luro -7579.11 5404.78 -1.402 0.160833
## l3Villa Ortuzar 18667.61 6829.18 2.734 0.006269 **
## l3Villa Pueyrredón 10516.80 5349.56 1.966 0.049314 *
## l3Villa Real -8823.37 8745.56 -1.009 0.313030
## l3Villa Riachuelo -32775.66 17171.10 -1.909 0.056298 .
## l3Villa Santa Rita -5767.71 6383.86 -0.903 0.366274
## l3Villa Soldati -136489.91 18944.29 -7.205 5.90e-13 ***
## l3Villa Urquiza 30648.43 4418.91 6.936 4.09e-12 ***
## rooms -3961.27 444.58 -8.910 < 2e-16 ***
## bathrooms 34040.98 644.28 52.836 < 2e-16 ***
## surface_total 919.08 23.52 39.069 < 2e-16 ***
## surface_covered 1457.18 28.73 50.715 < 2e-16 ***
## property_typeDepartamento 92653.32 2191.23 42.284 < 2e-16 ***
## property_typePH 46779.37 2274.94 20.563 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 66580 on 45841 degrees of freedom
## Multiple R-squared: 0.7764, Adjusted R-squared: 0.7761
## F-statistic: 2568 on 62 and 45841 DF, p-value: < 2.2e-16
En la columna Estimate podemos ver los coeficientes estimados para los Beta correspondientes a las variables en la izquierda de la tabla. Se interpretan de la siguiente forma: por cada unidad que aumente la variable en la izquierda de la tabla, el precio de la vivienda aumenta(o disminuye, depende del signo) según la cantidad estimada manteniendo el resto de variables constantes. EJ: El aumento de una unidad de la superficie total de una vivienda, conlleva a un aumento de su precio, en promedio, de 919.08 manteniendo el resto de variables fijas. Para este caso, la interpretación del Intercept no tiene sentido, no hay propiedades que tengan 0 habitaciones, 0 baños, etc. Para las variables cualitativas, la interpretación es la siguiente: suponiendo que una vivienda podria cambiar de barrio, el coeficiente l3Almagro indica que si una vivienda se “moviera” de Abasto (categoria basal para l3) a Almagro, mantenidento todas las demas variables fijas (caracterisitcas de la vivienda) su precio bajaría 4520.04 dólares, en promedio.
anova(model)
Analizando las variables dummy en conjunto (con la salida de ANOVA), vemos que son significativas para explicar la variabilidad del precio de las viviendas. Individualmente, algunas no presentan una diferencia significativa con la variable basal Abasto. Algo similar pasa con la variable property_type, es significativa para el modelo y significativa individualmente con respecto a la clase basal Casa.
predictions = as.numeric(predict(model,properties %>% select(-c("id","price"))))
## Warning in predict.lm(model, properties %>% select(-c("id", "price"))):
## prediction from a rank-deficient fit may be misleading
y_true = sapply((properties %>% select(c("price"))),as.numeric)
MAE(y_pred = predictions, y_true = y_true)
## [1] 43436.75
MSE(y_pred = predictions, y_true = y_true)
## [1] 4426853280
RMSE(y_pred = predictions, y_true = y_true)
## [1] 66534.6
Podemos ver los valores de tres métricas de evaluación diferentes: Mean Absolute Error, Mean Square Error y Root Mean Square Error. El valor de MSE se ve particularmente grande debido a la penalizacion de la métrica para los errores grandes. Indica que el modelo no ajusta bien en esos casos.
plot(model)
## Warning in model.matrix.default(object, data = structure(list(price =
## c(199900, : the response appeared on the right-hand side and was dropped
## Warning in model.matrix.default(object, data = structure(list(price =
## c(199900, : problem with term 6 in model.matrix: no columns are assigned
En el primer gráfico se puede ver un scatter plot de los residuos y los valores que estima el modelo. Se puede observar un patron en los datos, las varianza aumenta para los valores mas grandes estimados indicando que el modelo no cumple con la homocedasticidad de los residuos
El segundo gráfico “Normal QQ” sirve para ver si los residuos siguen una distribución normal, si el modelo esta bien definido, los círculos que se ven en el gráfico deberian seguir el patron lineal de la recta puntueada. En este caso, en los limites del gráfico se observa un desvio de los puntos con respecto a la recta. Los residuos estandarizados no siguen esta distribución.
Por último, el graficó de los residuos en función del Leverage. Se pueden observar valores atípicos que desplazan la recta generada por el modelo hacia ellos, aumentado el valor de los residuos y el error éstandar.
Una manera más de evaluar el modelo es observando el R2, que es igual a 0,7764. Significa que las variables seleccionadas para el modello estan explicando aproximadamente, el 77% de la variabilidad del precio de las viviendas.
abasto = predict(model,newdata=data.frame(l3="Abasto",rooms = 3, bathrooms = 2,surface_total=120,surface_covered=120,property_type='Departamento'),interval="confidence")
## Warning in predict.lm(model, newdata = data.frame(l3 = "Abasto", rooms =
## 3, : prediction from a rank-deficient fit may be misleading
balva = predict(model,newdata=data.frame(l3="Balvanera",rooms = 2, bathrooms = 3,surface_total=100,surface_covered=80,property_type='PH'),interval="confidence")
## Warning in predict.lm(model, newdata = data.frame(l3 = "Balvanera", rooms =
## 2, : prediction from a rank-deficient fit may be misleading
paste("Depto en abasto:" , abasto[2],"Ph en balvanera",balva[2])
## [1] "Depto en abasto: 316347.45339207 Ph en balvanera 210389.213518492"
La predicción para el departamento en Abasto da 316.348 dólares, mientras que el PH en Balvanera 210.389 mil dólares. Es preferible tener el departamento en Abasto mirando solamente el valor de venta estimado.
Realizar un modelo sin la covariable l3 e interpretar sus resultados (todas las partes de la salida que consideren relevantes)
model2 <- lm(price ~ rooms + bathrooms + surface_total + surface_covered + price + property_type, data = properties )
## Warning in model.matrix.default(mt, mf, contrasts): the response appeared
## on the right-hand side and was dropped
## Warning in model.matrix.default(mt, mf, contrasts): problem with term 5 in
## model.matrix: no columns are assigned
summary(model2)
##
## Call:
## lm(formula = price ~ rooms + bathrooms + surface_total + surface_covered +
## price + property_type, data = properties)
##
## Residuals:
## Min 1Q Median 3Q Max
## -518799 -36177 -9643 25740 724251
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -131096.86 2750.50 -47.66 <2e-16 ***
## rooms -13348.53 519.02 -25.72 <2e-16 ***
## bathrooms 42664.68 756.37 56.41 <2e-16 ***
## surface_total 877.03 27.59 31.79 <2e-16 ***
## surface_covered 1783.80 33.53 53.21 <2e-16 ***
## property_typeDepartamento 135177.47 2513.93 53.77 <2e-16 ***
## property_typePH 68598.52 2677.46 25.62 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 79210 on 45897 degrees of freedom
## Multiple R-squared: 0.6832, Adjusted R-squared: 0.6831
## F-statistic: 1.649e+04 on 6 and 45897 DF, p-value: < 2.2e-16
Sacando la covariable l3, el modelo pierde poder para explicar la variable precio ya que su R2 es menor que en el caso antorior. Esto significa que la variable l3 contiene informacion valiosa para explicar la variable precio.
¿Cuál es el modelo que mejor explica la variabilidad del precio?
El primer modelo con la variable l3 explica en mayor medida, la variabilidad del precio de las viviendas.
metros_barrio <- properties %>%
group_by(l3) %>%
summarise(mean_price= mean(price/surface_total))
histograma <- ggplot(metros_barrio, aes(x=mean_price)) + geom_histogram(binwidth=100)
histograma <- histograma + ggtitle("Precio metro cuadrado por barrio")
histograma <- histograma + labs(x = "Precio", y = "Cantidad")
histograma <- histograma + coord_cartesian(xlim = c(0, 6000))
histograma
summary(metros_barrio$mean_price)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1093 2062 2204 2358 2579 5472
Al no encontrar un patron especificon en los datos, voy a dividir el dataset en 3 partes iguales.
metros_barrio= metros_barrio %>% filter(mean_price != min(mean_price),mean_price!=max(mean_price)) %>% mutate(barrios = bin(mean_price, nbins = 3, labels = c("BAJO", "MEDIO", "ALTO")))
ggplot(metros_barrio,aes(barrios))+geom_histogram(stat="count") + ggtitle('Grupos por Barrios')
## Warning: Ignoring unknown parameters: binwidth, bins, pad
# Combino el dataset original con el nuevo que contiene los grupos de los barrios
properties <- merge(properties,metros_barrio,by='l3',all.x = T)
# quito el precio promedio y los barrios para el nuevo modelo
properties_new <- properties %>% select(-c(l3,mean_price))
#creo el nuevo modelo
model_new <- lm(price~rooms + bathrooms + surface_total + surface_covered + barrios + property_type,properties_new)
summary(model_new)
##
## Call:
## lm(formula = price ~ rooms + bathrooms + surface_total + surface_covered +
## barrios + property_type, data = properties_new)
##
## Residuals:
## Min 1Q Median 3Q Max
## -415149 -34477 -3694 24836 568100
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -148630.05 2568.39 -57.87 <2e-16 ***
## rooms -4729.13 446.13 -10.60 <2e-16 ***
## bathrooms 35184.62 649.60 54.16 <2e-16 ***
## surface_total 956.03 23.45 40.76 <2e-16 ***
## surface_covered 1417.50 28.63 49.51 <2e-16 ***
## barriosMEDIO 31001.38 1432.31 21.64 <2e-16 ***
## barriosALTO 95847.91 1461.58 65.58 <2e-16 ***
## property_typeDepartamento 95344.72 2162.93 44.08 <2e-16 ***
## property_typePH 49529.90 2277.74 21.75 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 67100 on 45365 degrees of freedom
## (530 observations deleted due to missingness)
## Multiple R-squared: 0.7573, Adjusted R-squared: 0.7572
## F-statistic: 1.769e+04 on 8 and 45365 DF, p-value: < 2.2e-16
Con el nuevo modelo podemos ver que todas las covariables son significativas. El R2 no varió mucho. La nueva variable barrio debe interpretarse de la siguiente manera: si “movieramos” una casa de un barrio con precios por metro cuadrado bajos a uno con precios moderados, manteniendo sus caracteristicas, el precio aumentaria 31001.38 dólares en promedio.
El modelo que parece explicar mejor la variabilidad es el que contiene a l3 por tener un R2 Ajustado mayor(un poco). Tambien, con el primer modelo tenemos informacion sobre los barrios de forma individual, que con el modelo de barrios no.
properties_new <- properties_new %>%
mutate(surface_patio = surface_total-surface_covered)
# Vemos la nueva variable
summary(properties_new$surface_patio)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 0.000 5.000 9.338 10.000 91.000
model_new <- lm(price~rooms + bathrooms + surface_patio + surface_covered + barrios + property_type,properties_new)
summary(model_new)
##
## Call:
## lm(formula = price ~ rooms + bathrooms + surface_patio + surface_covered +
## barrios + property_type, data = properties_new)
##
## Residuals:
## Min 1Q Median 3Q Max
## -415149 -34477 -3694 24836 568100
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -148630.05 2568.39 -57.87 <2e-16 ***
## rooms -4729.13 446.13 -10.60 <2e-16 ***
## bathrooms 35184.62 649.60 54.16 <2e-16 ***
## surface_patio 956.03 23.45 40.76 <2e-16 ***
## surface_covered 2373.52 15.17 156.44 <2e-16 ***
## barriosMEDIO 31001.38 1432.31 21.64 <2e-16 ***
## barriosALTO 95847.91 1461.58 65.58 <2e-16 ***
## property_typeDepartamento 95344.72 2162.93 44.08 <2e-16 ***
## property_typePH 49529.90 2277.74 21.75 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 67100 on 45365 degrees of freedom
## (530 observations deleted due to missingness)
## Multiple R-squared: 0.7573, Adjusted R-squared: 0.7572
## F-statistic: 1.769e+04 on 8 and 45365 DF, p-value: < 2.2e-16
Surface_patio no contiene contradicciones. Si las tuviera, lo consideraria un error y las borraría. El coeficiente estimado para la variable surface_covered se interpreta como el aumento del precio promedio de una propiedad cuando la superficie cubierta aumenta en un metro cuadrado. Análogamente se puede interpretar surface_patio. El aumento del precio es mayor cuando aumenta la superficie cubierta que cuando aumenta la superficie descubierta.
plot(model_new)
El análisis es el mismo que en el caso anterior, no se presenta homoedasticidad de la varianza y los residuos no siguen una distribución normal. En el último gráficose observa que hay puntos alejados pero el leverage es menor que en la evalución del modelo anterior.
properties_log <- properties_new %>%
mutate(price=log(price),rooms=log(rooms),bathrooms=log(bathrooms),surface_covered=log(surface_covered))
model_log <- lm(price~rooms+bathrooms+surface_patio+surface_covered+property_type+barrios,data = properties_log)
summary(model_log)
##
## Call:
## lm(formula = price ~ rooms + bathrooms + surface_patio + surface_covered +
## property_type + barrios, data = properties_log)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.3123 -0.1452 -0.0030 0.1359 1.1231
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.309e+00 1.868e-02 444.814 < 2e-16 ***
## rooms -1.633e-02 3.760e-03 -4.343 1.41e-05 ***
## bathrooms 1.858e-01 3.786e-03 49.073 < 2e-16 ***
## surface_patio 4.189e-03 7.866e-05 53.250 < 2e-16 ***
## surface_covered 7.796e-01 4.427e-03 176.109 < 2e-16 ***
## property_typeDepartamento 2.157e-01 7.131e-03 30.246 < 2e-16 ***
## property_typePH 6.257e-02 7.541e-03 8.297 < 2e-16 ***
## barriosMEDIO 1.995e-01 4.792e-03 41.635 < 2e-16 ***
## barriosALTO 4.817e-01 4.891e-03 98.483 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2245 on 45365 degrees of freedom
## (530 observations deleted due to missingness)
## Multiple R-squared: 0.8208, Adjusted R-squared: 0.8207
## F-statistic: 2.597e+04 on 8 and 45365 DF, p-value: < 2.2e-16
Este nuevo modelo mejora la explicación de la variabilidad con un R2 Ajustado=0.8202 frente al anterior. La nueva interpretacion para los parámetros a los cuales se les aplicó log es la siguiente: tomando como ejemplo surface_covered, si aumentamos 1% la superficie cubierta de la casa, el precio aumenta 0.7796% en promedio.
plot(model_log)
En este caso los residuos no parecen tener una estructura, acercandoce mas a la homocedasticidad de la varianza. La recta en el QQ plot se apega mucho mas los puntos del grafico, indicando que los residuos siguen la distribución normal.
properties_nested <- properties %>%
mutate(surface_patio = surface_total - surface_covered) %>%
select(-c(surface_total)) %>%
nest(-property_type)
head(properties_nested)
df_model <- function(datos) {
modelo <- lm("price ~ l3 + rooms + bathrooms + surface_covered + surface_patio" , data = datos)
return(modelo)
}
model_nested = properties_nested %>%
mutate(
model = map(data, df_model),
lmtidies = map(model, tidy),
descripcion = map(model, glance)
)
model_nested %>%
unnest(descripcion)
Podemos ver que el modelo que contiene solo los datos de los departamentos logra explicar mayor variabilidad que el resto. Es interesante tambien que el sigma para el modelo de departamentos se encuentra entre medio de los otros, siendo que tiene muchos mas datos y podría aumentar mucho el error de los residuos.
model_nested %>% unnest(lmtidies)
model_nested %>% unnest(lmtidies) %>% filter(term == 'surface_patio' |term == 'bathrooms' |term == 'rooms' | term == 'surface_covered') %>% arrange(term)
Analizando los coeficientes de la superficie cubierta, patio, habitaciones y baño vemos que los departamentos aumentan mucho su valor, comparado con el resto de viviendas, cuando se les añade mas baños. En el caso de las habitaciones, un PH y una casa aumentan su valor, mientras que en un departamento se reduce. Quizas sea un indicio de que se prefieren los departamentos abiertos con pocas habitaciones. Se observa tambien que aumentando la superficie cuebierta o descubierta, el precio crece mucho mas en los casos de los departamentos que en el resto.