Se realizó un filtro para conservar únicamente los datos referentes a ‘Apartamento’.
datosVivienda$tipo <- replace (datosVivienda$tipo, datosVivienda$tipo %in% c("casa","CASA","APARTAMENTO","apto"), c("Casa","Casa","Apartamento","Apartamento"))
vivienda5<- subset(datosVivienda,tipo=='Apartamento')
print.data.frame(head(vivienda5, n=3))
## id zona piso estrato preciom areaconst parqueaderos banios
## 1 1212 Zona Norte 01 5 260 90 1 2
## 2 1724 Zona Norte 01 5 240 87 1 3
## 3 2326 Zona Norte 01 4 220 52 2 2
## habitaciones tipo barrio longitud latitud
## 1 3 Apartamento acopi -76.51350 3.45891
## 2 3 Apartamento acopi -76.51700 3.36971
## 3 3 Apartamento acopi -76.51974 3.42627
summary(vivienda5)
## id zona piso estrato
## Min. : 3 Length:5100 Length:5100 Min. :3.000
## 1st Qu.:2180 Class :character Class :character 1st Qu.:4.000
## Median :4158 Mode :character Mode :character Median :5.000
## Mean :4284 Mean :4.727
## 3rd Qu.:6556 3rd Qu.:6.000
## Max. :8317 Max. :6.000
##
## preciom areaconst parqueaderos banios
## Min. : 58.0 Min. : 35.0 Min. : 1.000 Min. :0.000
## 1st Qu.: 175.0 1st Qu.: 68.0 1st Qu.: 1.000 1st Qu.:2.000
## Median : 279.0 Median : 90.0 Median : 1.000 Median :2.000
## Mean : 366.9 Mean :112.8 Mean : 1.568 Mean :2.617
## 3rd Qu.: 430.0 3rd Qu.:130.0 3rd Qu.: 2.000 3rd Qu.:3.000
## Max. :1950.0 Max. :932.0 Max. :10.000 Max. :8.000
## NA's :869
## habitaciones tipo barrio longitud
## Min. :0.000 Length:5100 Length:5100 Min. :-76.59
## 1st Qu.:3.000 Class :character Class :character 1st Qu.:-76.54
## Median :3.000 Mode :character Mode :character Median :-76.53
## Mean :2.971 Mean :-76.53
## 3rd Qu.:3.000 3rd Qu.:-76.52
## Max. :9.000 Max. :-76.46
##
## latitud
## Min. :3.334
## 1st Qu.:3.380
## Median :3.419
## Mean :3.419
## 3rd Qu.:3.453
## Max. :3.498
##
str(vivienda5)
## tibble [5,100 × 13] (S3: tbl_df/tbl/data.frame)
## $ id : num [1:5100] 1212 1724 2326 4386 7497 ...
## $ zona : chr [1:5100] "Zona Norte" "Zona Norte" "Zona Norte" "Zona Norte" ...
## $ piso : chr [1:5100] "01" "01" "01" "01" ...
## $ estrato : num [1:5100] 5 5 4 5 6 4 5 3 3 6 ...
## $ preciom : num [1:5100] 260 240 220 310 520 320 385 100 175 820 ...
## $ areaconst : num [1:5100] 90 87 52 137 98 108 103 49 80 377 ...
## $ parqueaderos: num [1:5100] 1 1 2 2 2 2 2 NA 1 1 ...
## $ banios : num [1:5100] 2 3 2 3 2 3 2 1 2 4 ...
## $ habitaciones: num [1:5100] 3 3 3 4 2 3 3 2 3 4 ...
## $ tipo : chr [1:5100] "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
## $ barrio : chr [1:5100] "acopi" "acopi" "acopi" "acopi" ...
## $ longitud : num [1:5100] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:5100] 3.46 3.37 3.43 3.38 3.44 ...
Se realizó un anális exploratorio revisando la correlación entre la variable respuesta precio de la casa y las siguientes variables:
plot_ly(vivienda5, x = ~areaconst, y = ~preciom)
## No trace type specified:
## Based on info supplied, a 'scatter' trace seems appropriate.
## Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
La relación con respecto del precio y el área construida muestra una correlación positiva, mucho más marcada en los precios hasta 1000 y áreas menores a 400, depsues de eso la relación comienza a ser menos evidente con algunos outliers.
El precio con respecto al estrato tiene una relación creciente, con un mayor precio total a medida que el estrato aumenta. Sin embargo la varianza entre precios en el mismo estrato.
plot_ly(vivienda5, x = ~estrato, y = ~preciom)
## No trace type specified:
## Based on info supplied, a 'scatter' trace seems appropriate.
## Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
La relación con los baños no es tan evidente, el precio aumenta generalmente hasta cuatro baños, luego se mantiene relativamente estable. Sin embargo los apartamento sin baño tambien tienen precios altos.
plot_ly(vivienda5, x = ~banios, y = ~preciom)
## No trace type specified:
## Based on info supplied, a 'scatter' trace seems appropriate.
## Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
La relación con el número de habitaciones se comporta muy similar al número de baños, aumentando de forma positiva hasta cuatro habitaciones y luego se dispersa y disminuye poco a poco.
plot_ly(vivienda5, x = ~habitaciones, y = ~preciom)
## No trace type specified:
## Based on info supplied, a 'scatter' trace seems appropriate.
## Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
El análisis de las zonas de la ciudad con respecto al precio muestra que la zona Oeste tiene los precios más altos, aunque tienen una varianza grande y precios mínimos comparables al resto de las zonas. La zona Oriente tiene los menores precios seguida de la zona centro.
plot_ly(vivienda5, x = ~zona, y = ~preciom, type = "box")
Antes de proceder con la creación del modelo, se realizó un tratamiento de los datos faltantes. Para las variables piso y parqueadero que tienen valores faltantes, se creó un vector con los valores faltantes para esas variables, donde “TRUE” representa los datos faltantes. Estos valores faltantes se analizaron contra algunas variables como tipo de casa y estrato:
Para el caso de piso faltante, no se ve una distribución particular y los faltantes están homogéneamente distribuidos, entonces no es posible imputar esto valores con un 0 o el promedio dado que sería un error, por este motivo se van a eliminar los registros que tengan datos faltantes para esta variables.
Para el caso de parqueadero faltante, se ve una distribución particular cuando se analiza contra estrato, teniendo en cuenta esta distribución es posible inferir que los datos faltantes representan un 0, donde las viviendas de estratos más bajos no tienen casi parqueaderos pero las de estratos altos sí. Por este motivo se van a reemplazar los datos faltantes por 0.
Luego de estos ajustes ya no quedan datos faltantes:
md.pattern(vivienda5)
## id zona estrato preciom areaconst parqueaderos banios habitaciones tipo
## 3719 1 1 1 1 1 1 1 1 1
## 1381 1 1 1 1 1 1 1 1 1
## 0 0 0 0 0 0 0 0 0
## barrio longitud latitud piso
## 3719 1 1 1 1 0
## 1381 1 1 1 0 1
## 0 0 0 1381 1381
vivienda5 = na.omit(vivienda5)
md.pattern(vivienda5)
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## 3719 1 1 1 1 1 1 1 1 1
## 0 0 0 0 0 0 0 0 0
## tipo barrio longitud latitud
## 3719 1 1 1 1 0
## 0 0 0 0 0
Posterior a resto, se realizó la estimación del modelo:
modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = vivienda5)
summary(modelo1)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = vivienda5)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1767.05 -50.51 -3.28 42.56 989.76
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -210.35391 15.03286 -13.993 <2e-16 ***
## areaconst 2.06801 0.04834 42.783 <2e-16 ***
## estrato 44.61633 3.11009 14.346 <2e-16 ***
## habitaciones -32.80136 3.72542 -8.805 <2e-16 ***
## parqueaderos 67.45598 3.73369 18.067 <2e-16 ***
## banios 52.29583 3.45623 15.131 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 129.4 on 3713 degrees of freedom
## Multiple R-squared: 0.7853, Adjusted R-squared: 0.7851
## F-statistic: 2717 on 5 and 3713 DF, p-value: < 2.2e-16
Todos los coeficientes son estadísticamente significativos y el valor del r2 es relativamente bueno, con un 0,78 predice casi el 80% de la varianza del los datos con el modelo creado, para mejorar este modelo de podrían eliminar algunos valores atípico y crear variables dummie para las variables categóricas como estrato, adicionalmente se pueden hacer alguna transformación matemática en los datos para que cumplan los supuestos y mejore su rendimiento.
Los coeficientes de este modelo se pueden interpretrar de la siguiente manera:
Estos resultados son lógicos en su gran mayoria, donde las categorias con
Al realizar un análisis gráfico de los supuestos, se observa que no se cumplen de forma adecuada:
En la primera gráfica se puede observar que la relación no es completamente lineal, dado que la tendencia tiene una curvatura para arriba en las puntas, mucho más marcada .
En la segunda gráfica se puede comprobar que los errores no siguen una distribución normal y no se ajustan a la línea, en especial despues de 2.
En la tercera gráfica se revisa que los datos no son homocedásticos dado que no sigue una línea recta.
En la cuarta gráfica se observa que hay dos valores atípicos muy grandes a más de 0.5 de distancia de cook y uno a más de 1, estos se deberían revisar en detalle porque tienen un gran efecto en el modelo y sería mejor eliminarlos.
plot(modelo1)
Se realiza la separación de los datos en 70% y 30%:
set.seed(42)
index<- sample(1:nrow(vivienda5), 7/10 * nrow(vivienda5))
trainingSet<- vivienda5[index,]
testSet<- vivienda5[-index,]
str(trainingSet)
## tibble [2,603 × 13] (S3: tbl_df/tbl/data.frame)
## $ id : num [1:2603] 5243 2507 7649 6700 5886 ...
## $ zona : chr [1:2603] "Zona Norte" "Zona Norte" "Zona Sur" "Zona Sur" ...
## $ piso : chr [1:2603] "03" "11" "04" "04" ...
## $ estrato : num [1:2603] 6 4 4 5 6 5 6 4 4 5 ...
## $ preciom : num [1:2603] 740 215 210 220 180 210 650 155 235 235 ...
## $ areaconst : num [1:2603] 161 71 69 115 54.5 ...
## $ parqueaderos: num [1:2603] 2 1 2 1 1 1 2 1 1 1 ...
## $ banios : num [1:2603] 3 2 2 2 2 3 4 2 2 2 ...
## $ habitaciones: num [1:2603] 3 2 3 3 1 3 4 3 2 3 ...
## $ tipo : chr [1:2603] "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
## $ barrio : chr [1:2603] "santa monica" "prados del norte" "el refugio" "el limonar" ...
## $ longitud : num [1:2603] -76.5 -76.5 -76.6 -76.5 -76.5 ...
## $ latitud : num [1:2603] 3.46 3.47 3.4 3.4 3.45 ...
## - attr(*, "na.action")= 'omit' Named int [1:1381] 16 17 18 19 20 21 22 23 24 25 ...
## ..- attr(*, "names")= chr [1:1381] "16" "17" "18" "19" ...
str(testSet)
## tibble [1,116 × 13] (S3: tbl_df/tbl/data.frame)
## $ id : num [1:1116] 7497 5424 2323 8109 8179 ...
## $ zona : chr [1:1116] "Zona Norte" "Zona Norte" "Zona Norte" "Zona Oeste" ...
## $ piso : chr [1:1116] "02" "03" "05" "01" ...
## $ estrato : num [1:1116] 6 4 6 4 3 4 6 3 6 3 ...
## $ preciom : num [1:1116] 520 320 450 150 140 120 1050 98 950 118 ...
## $ areaconst : num [1:1116] 98 108 103 55 60 60 240 62 217 60 ...
## $ parqueaderos: num [1:1116] 2 2 2 0 1 0 3 0 3 0 ...
## $ banios : num [1:1116] 2 3 3 1 2 1 5 2 5 1 ...
## $ habitaciones: num [1:1116] 2 3 4 2 2 3 4 3 4 2 ...
## $ tipo : chr [1:1116] "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
## $ barrio : chr [1:1116] "acopi" "acopi" "acopi" "aguacatal" ...
## $ longitud : num [1:1116] -76.5 -76.5 -76.5 -76.6 -76.6 ...
## $ latitud : num [1:1116] 3.44 3.41 3.44 3.46 3.46 ...
## - attr(*, "na.action")= 'omit' Named int [1:1381] 16 17 18 19 20 21 22 23 24 25 ...
## ..- attr(*, "names")= chr [1:1381] "16" "17" "18" "19" ...
Se estima de nuevo el modelo con los datos de test:
modeloTest <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = trainingSet)
summary(modeloTest)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = trainingSet)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1662.03 -50.50 -4.93 41.61 1004.56
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -226.80056 18.06827 -12.552 < 2e-16 ***
## areaconst 1.94310 0.05682 34.199 < 2e-16 ***
## estrato 46.77728 3.76348 12.429 < 2e-16 ***
## habitaciones -25.86682 4.48752 -5.764 9.18e-09 ***
## parqueaderos 70.75755 4.49125 15.755 < 2e-16 ***
## banios 49.93977 4.16528 11.990 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 130.9 on 2597 degrees of freedom
## Multiple R-squared: 0.7728, Adjusted R-squared: 0.7724
## F-statistic: 1767 on 5 and 2597 DF, p-value: < 2.2e-16
Se realiza la predicción con el modelo y se agrega una nueva columna al final del dataset con el resultado:
testSet$prediccion <- predict(modeloTest, newdata=testSet, type='response'); print.data.frame(head(testSet))
## id zona piso estrato preciom areaconst parqueaderos banios
## 1 7497 Zona Norte 02 6 520 98 2 2
## 2 5424 Zona Norte 03 4 320 108 2 3
## 3 2323 Zona Norte 05 6 450 103 2 3
## 4 8109 Zona Oeste 01 4 150 55 0 1
## 5 8179 Zona Oeste 01 3 140 60 1 2
## 6 8105 Zona Oeste 02 4 120 60 0 1
## habitaciones tipo barrio longitud latitud prediccion
## 1 2 Apartamento acopi -76.54999 3.43505 433.94807
## 2 3 Apartamento acopi -76.53638 3.40770 383.89749
## 3 4 Apartamento acopi -76.51972 3.44000 441.86971
## 4 2 Apartamento aguacatal -76.55520 3.45970 65.38527
## 5 2 Apartamento aguacatal -76.55668 3.45832 149.02082
## 6 3 Apartamento aguacatal -76.55502 3.45972 49.23396
El error cuadratico medio es:
errorCuadraticoMedio<- mse(testSet$preciom, testSet$prediccion); errorCuadraticoMedio
## [1] 16023.22
Este valor es bastante alto y deberían probarse diferentes modelos para intentar disminuir este error.
El error absoluto medio es:
errorAbsolutoMedio<- mae(testSet$preciom, testSet$prediccion); errorAbsolutoMedio
## [1] 78.76266
Se puede interpretar como que en promedio el modelo da un valor de 78 millones diferente al resultado real, este valor es bastante grande teniendo en cuenta que en algunos apartamento puede llegar a ser un porcentaje importante con respecto al precio total y puede disminuir las ganancias del vendedor al tener tanto error.
El R2 es:
summary(modeloTest)$r.squared
## [1] 0.7728333
Es ligeramente inferior al resultado obtenido en el modelo original, pero sigue siendo un resultado aceptable aunque con mucho margen de mejora.