Con base en los datos de ofertas de vivienda descargadas del portal Fincaraiz para apartamento de estrato 4 con área construida menor a 200 m2 la inmobiliaria A&C requiere el apoyo en la construcción de un modelo que lo oriente sobre los precios de inmuebles. Con este propósito el equipo de asesores ha diseñado los siguientes pasos para obtener un modelo y así poder a futuro determinar los precios de los inmuebles a negociar
Se inicia reconociendo los campos presentes en la base de datos provista. En la siguiente tabla se observan los primeros 6 registros donde el campo Zona, Estrato y Tipo son tratados como Factores, dejando así 2 variables cuantitativas continuas, el Area Construida y el Precio del tipo Double.
formattable(head(vivienda4))
zona | estrato | preciom | areaconst | tipo |
---|---|---|---|---|
Zona Norte | 4 | 232.2643 | 52 | Apartamento |
Zona Norte | 4 | 272.3068 | 160 | Casa |
Zona Norte | 4 | 254.8213 | 108 | Apartamento |
Zona Sur | 4 | 257.7722 | 96 | Apartamento |
Zona Norte | 4 | 250.1956 | 82 | Apartamento |
Zona Norte | 4 | 261.1614 | 117 | Casa |
En la siguiente tabla se encuentra el resumen de los datos por campo, se observa que todos los datos recopilados son exclusivamente de estrato 4.
summary(vivienda4)
zona estrato preciom areaconst
Zona Centro : 8 3: 0 Min. :207.4 Min. : 40.00
Zona Norte : 288 4:1706 1st Qu.:230.7 1st Qu.: 60.00
Zona Oeste : 60 5: 0 Median :238.8 Median : 75.00
Zona Oriente: 6 6: 0 Mean :243.7 Mean : 87.63
Zona Sur :1344 3rd Qu.:251.5 3rd Qu.: 98.00
Max. :309.7 Max. :200.00
tipo
Apartamento:1363
Casa : 343
Finalmente, se encuentra el resumen estadístico de las variables cuantitativas.
formattable(as.data.frame(round(descr(vivienda4), 2)))
areaconst | preciom | |
---|---|---|
Mean | 87.63 | 243.70 |
Std.Dev | 36.35 | 19.56 |
Min | 40.00 | 207.41 |
Q1 | 60.00 | 230.73 |
Median | 75.00 | 238.77 |
Q3 | 98.00 | 251.51 |
Max | 200.00 | 309.70 |
MAD | 22.24 | 14.19 |
IQR | 38.00 | 20.77 |
CV | 0.41 | 0.08 |
Skewness | 1.53 | 1.26 |
SE.Skewness | 0.06 | 0.06 |
Kurtosis | 1.68 | 1.25 |
N.Valid | 1706.00 | 1706.00 |
Pct.Valid | 100.00 | 100.00 |
A priori, se puede comentar que el Area Construida presenta datos dispersos, pues el coeficiente de variacion es superior al 20%. Por otra parte, analizando los valores de los Cuartiles, se observa que los datos se encuentran algo sesgados a la derecha, es decir, con prepondernacia de valores menores, esto se corrobora con el Skewness > 0 y con los histogramas de estas variables mostrados en la siguiente figura.
par(mfrow = c(1,2))
hist(vivienda4$preciom, main = "Precio", xlab = "Millones COP")
hist(vivienda4$areaconst, main = "Area Construida", xlab = "m^2")
par(mfrow = c(1,1))
En la siguiente gráfica se observa que no hay datos faltantes en la base de datos.
gg_miss_var(vivienda4)
Para explorar cómo se comporta el precio de las viviendas, se segregan los datos por Zona y Tipo con el fin de conocer datos atípicos y encontrar comportamientos similares, cabe resaltar, que no se involucra el estrato ya que sólo se cuenta con datos de estrato 4.
# Lineas y labels Casas
zonasur <- subset(vivienda4, zona == "Zona Sur" & tipo == "Casa")
q <- quantile(zonasur$preciom, probs = c(0.25, 0.50, 0.75))
i <- iqr(zonasur$preciom)
infpreciocasassur <- q[1] - 1.5*i
if (infpreciocasassur <= min(zonasur$preciom)) infpreciocasassur <- min(zonasur$preciom)
suppreciocasassur <- q[3] + 1.5*i
if (suppreciocasassur >= max(zonasur$preciom)) suppreciocasassur <- max(zonasur$preciom)
# Lineas y labels Apartamentos
zonasuraptos <- subset(vivienda4, zona == "Zona Sur" & tipo == "Apartamento")
qsuraptos <- quantile(zonasuraptos$preciom, probs = 0.25)
isuraptos <- iqr(zonasuraptos$preciom)
infpreciosuraptos <- qsuraptos - 1.5*isuraptos
if (infpreciosuraptos <= min(zonasuraptos$preciom)) infpreciosuraptos <- min(zonasuraptos$preciom)
zonacenaptos <- subset(vivienda4, zona == "Zona Centro" & tipo == "Apartamento")
qcenaptos <- quantile(zonacenaptos$preciom, probs = 0.75)
icenaptos <- iqr(zonacenaptos$preciom)
suppreciocenaptos <- qcenaptos + 1.5*icenaptos
if (suppreciocenaptos >= max(zonacenaptos$preciom)) suppreciocenaptos <- max(zonacenaptos$preciom)
# Boxplot Casas
par(mfrow = c(1, 2))
boxplot(preciom ~ zona,
data = subset(vivienda4, tipo == "Casa"),
main = "Casas",
xlab = NA,
ylab = "Precio m^2",
notch = TRUE)
abline(h = infpreciocasassur, col = "blue", lty = "dashed")
text(infpreciocasassur, labels = round(infpreciocasassur, 2), pos = 3, col = "blue")
abline(h = suppreciocasassur, col = "blue", lty = "dashed")
text(suppreciocasassur, labels = round(suppreciocasassur, 2), pos = 1, col = "blue")
# Boxplot Apartamentos
boxplot(preciom ~ zona,
data = subset(vivienda4, tipo == "Apartamento"),
main = "Apartamentos",
xlab = NA,
ylab = "Precio m^2",
notch = TRUE)
abline(h = infpreciosuraptos, col = "blue", lty = "dashed")
text(infpreciosuraptos, labels = round(infpreciosuraptos, 2), pos = 3, col = "blue")
abline(h = suppreciocenaptos, col = "blue", lty = "dashed")
text(suppreciocenaptos, labels = round(suppreciocenaptos, 2), pos = 3, col = "blue")
par(mfrow = c(1, 1))
Se observa que para las casas, la mediana del precio es similar, pues las muescas de los diagramas de caja se traslapan para todas las zonas, por lo tanto, se tomarán como datos atipicos aquellos valores mostrados en la figura anterior. Para los apartamentos, se dará un trato similar.
Se realizo un tratamiento similar para el área construida la cual se presenta a continuación.
# Lineas y labels Casas
zonasur <- subset(vivienda4, zona == "Zona Sur" & tipo == "Casa")
q <- quantile(zonasur$areaconst, probs = 0.25)
i <- iqr(zonasur$areaconst)
infareacasasssur <- q - 1.5*i
if (infareacasasssur <= min(zonasur$areaconst)) infareacasasssur <- min(zonasur$areaconst)
zonanorte <- subset(vivienda4, zona == "Zona Norte" & tipo == "Casa")
qnorcasas <- quantile(zonanorte$areaconst, probs = 0.75)
inorcasas <- iqr(zonanorte$areaconst)
supareanorcasas <- qnorcasas + 1.5*inorcasas
if (supareanorcasas >= max(zonanorte$areaconst)) supareanorcasas <- max(zonanorte$areaconst)
# Lineas y labels Apartamentos
zonasuraptos <- subset(vivienda4, zona == "Zona Sur" & tipo == "Apartamento")
qsuraptos <- quantile(zonasuraptos$areaconst, probs = 0.25)
isuraptos <- iqr(zonasuraptos$areaconst)
infareasuraptos <- qsuraptos - 1.5*isuraptos
if (infareasuraptos <= min(zonasuraptos$areaconst)) infareasuraptos <- min(zonasuraptos$areaconst)
zonacenaptos <- subset(vivienda4, zona == "Zona Centro" & tipo == "Apartamento")
qcenaptos <- quantile(zonacenaptos$areaconst, probs = 0.75)
icenaptos <- iqr(zonacenaptos$areaconst)
supareacenaptos <- qcenaptos + 1.5*icenaptos
if (supareacenaptos >= max(zonacenaptos$areaconst)) supareacenaptos <- max(zonacenaptos$areaconst)
# Boxplot Casas
par(mfrow = c(1, 2))
boxplot(areaconst ~ zona,
data = subset(vivienda4, tipo == "Casa"),
main = "Casas",
xlab = NA,
ylab = "Area m^2",
notch = TRUE)
abline(h = infareacasasssur, col = "blue", lty = "dashed")
text(infareacasasssur, labels = round(infareacasasssur, 2), pos = 3, col = "blue")
abline(h = supareanorcasas, col = "blue", lty = "dashed")
text(supareanorcasas, labels = round(supareanorcasas, 2), pos = 1, col = "blue")
# Boxplot Apartamentos
boxplot(areaconst ~ zona,
data = subset(vivienda4, tipo == "Apartamento"),
main = "Apartamentos",
xlab = NA,
ylab = "Area m^2",
notch = TRUE)
abline(h = infareasuraptos, col = "blue", lty = "dashed")
text(infareasuraptos, labels = round(infareasuraptos, 2), pos = 3, col = "blue")
abline(h = supareacenaptos, col = "blue", lty = "dashed")
text(supareacenaptos, labels = round(supareacenaptos, 2), pos = 3, col = "blue")
par(mfrow = c(1, 1))
En la siguiente gráfica, se presenta la relación entre la variable Precio como variable de respuesta y la variable Area Construida como variable independiente.
ggpairs(vivienda4[3:4], title = "Relacion Precio y Area")
Se observa que hay una correlación positiva fuerte, con un coeficiente R de 0.931. La prueba de significancia sobre el coeficiente nos dice que es significativamente diferente de cero.
Para realizar el modelo, inicialmente se eliminaron datos atípicos teniendo en cuenta los gráficos de cajas mostrados anteriormente.
viviendalimpia <- subset(vivienda4,
ifelse (tipo == "Casa",
preciom >= infpreciocasassur & preciom <= suppreciocasassur &
areaconst >= infareacasasssur & areaconst <= supareanorcasas,
preciom >= infpreciosuraptos & preciom <= suppreciocenaptos &
areaconst >= infareasuraptos & areaconst <= supareacenaptos
))
Eliminados los datos atípicos, permanecen un 98.77% de los datos originales, es decir, sólo se removieron 21 registros.
De acuerdo con lo observado en el Análisis Exploratorio de Datos, se propone realizar un modelo para estimar el precio de las casas y otro modelo para estimar el precio de los apartamentos.
viviendalimpiacasas <- subset(viviendalimpia, tipo == "Casa")
preciocasas <- lm(viviendalimpiacasas$preciom ~ viviendalimpiacasas$areaconst)
summary(preciocasas)
Call:
lm(formula = viviendalimpiacasas$preciom ~ viviendalimpiacasas$areaconst)
Residuals:
Min 1Q Median 3Q Max
-20.1064 -4.7773 -0.3723 4.9441 21.2966
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.978e+02 1.399e+00 141.38 <2e-16 ***
viviendalimpiacasas$areaconst 5.138e-01 9.868e-03 52.06 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.371 on 341 degrees of freedom
Multiple R-squared: 0.8883, Adjusted R-squared: 0.8879
F-statistic: 2711 on 1 and 341 DF, p-value: < 2.2e-16
Se observa que tanto el valor obtenido para el intercepto como el valor de la pendiente son significativamente distintos de cero para una significancia del 5%, aparte de ello, se observa que el coeficiente de determinación es muy bueno, pues el modelo es capaz de explicar el comportamiento de la variable Precio en un 88.8%. Finalmente, la globalidad del modelo se encuentra significativa por medio del criterio de la prueba F
A continuacion, se verifican los supuestos del modelo.
shapiro.test(preciocasas$residuals)
Shapiro-Wilk normality test
data: preciocasas$residuals
W = 0.99705, p-value = 0.7918
bptest(preciocasas)
studentized Breusch-Pagan test
data: preciocasas
BP = 0.56669, df = 1, p-value = 0.4516
dwtest(preciocasas)
Durbin-Watson test
data: preciocasas
DW = 2.1222, p-value = 0.8693
alternative hypothesis: true autocorrelation is greater than 0
par(mar=c(5.1, 2, 2, 2.1))
par(mfrow = c(2, 2))
plot(preciocasas)
par(mfrow = c(1, 1))
En el gráfico QQ de residuales se observa que estos presentan una distribución normal, esta afirmación se corrobora con la prueba de Shapiro Wilks, con la cual no se rechaza la hipótesis nula de normalidad, pues p-value > 0.05.
En el gráfico de residuales vs valores ajustados se observa que los residuales presentan varianza constante, esta afirmación se corrobora con la prueba de Breusch-Pagan con la cual no se rechaza la hipótesis nula de varianza constante.
Finalmente se observa que los residuales presentan un comportamiento aleatorio y simétrico a cero en el gráfico de residuales vs valores ajustados, esta afirmación se corrobora con la prueba de Durbin-Watson con la cual no se rechaza la hipótesis nula de correlación de residuales igual a 0.
La gráfica de apalancamiento no muestra valores influyentes.
A continuación, se presenta un intervalo de confianza del 95% para los coeficientes del modelo.
confint(preciocasas)
2.5 % 97.5 %
(Intercept) 195.0422304 200.5460327
viviendalimpiacasas$areaconst 0.4943707 0.5331918
Como el intérvalo del coeficiente viviendalimpiacasas$areaconst no contiene el valor cero, se confirma por otro criterio (a parte de la significancia obtenida por el p-valor) que dicho valor es distinto de cero y que el cambio de un metro cuadrado en el área construida influye de 0.49 a 0.53 veces en el precio de las casas, mientras que, independientemente del área construida, el precio de las viviendas casas parten de 195 a 200 millones con una confianza del 95%.
viviendalimpiaapto <- subset(viviendalimpia, tipo == "Apartamento")
precioapto <- lm(preciom ~ areaconst, data = viviendalimpiaapto)
summary(precioapto)
Call:
lm(formula = preciom ~ areaconst, data = viviendalimpiaapto)
Residuals:
Min 1Q Median 3Q Max
-26.1634 -5.0663 -0.0043 4.6055 24.3535
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 200.42598 0.78688 254.7 <2e-16 ***
areaconst 0.49321 0.01032 47.8 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.097 on 1340 degrees of freedom
Multiple R-squared: 0.6303, Adjusted R-squared: 0.6301
F-statistic: 2285 on 1 and 1340 DF, p-value: < 2.2e-16
Se observa que tanto el valor obtenido para el intercepto como el valor de la pendiente son significativamente distintos de cero para una significancia del 5%, aparte de ello, se observa que el coeficiente de determinación no es muy alto ya que el modelo es capaz de explicar el comportamiento de la variable Precio en un 63%, probablemente haya más variables que se deban tener en cuenta para predecir el precio de un apartamento, por ejemplo el piso en el que está ubicado y las comodidades del edificio donde se encuentre. Finalmente, la globalidad del modelo se encuentra significativa por medio del criterio de la prueba F.
A continuacion, se verifican los supuestos del modelo.
shapiro.test(precioapto$residuals)
Shapiro-Wilk normality test
data: precioapto$residuals
W = 0.99876, p-value = 0.4789
bptest(precioapto)
studentized Breusch-Pagan test
data: precioapto
BP = 0.090144, df = 1, p-value = 0.764
gqtest(precioapto)
Goldfeld-Quandt test
data: precioapto
GQ = 1.0595, df1 = 669, df2 = 669, p-value = 0.2274
alternative hypothesis: variance increases from segment 1 to 2
dwtest(precioapto)
Durbin-Watson test
data: precioapto
DW = 2.0386, p-value = 0.7572
alternative hypothesis: true autocorrelation is greater than 0
par(mar=c(5.1, 2, 2, 2.1))
par(mfrow = c(2, 2))
plot(precioapto)
par(mfrow = c(1, 1))
En el gráfico QQ de residuales se observa que estos presentan una distribución normal, esta afirmación se corrobora con la prueba de Shapiro Wilks, con la cual no se rechaza la hipótesis nula de normalidad, pues p-value > 0.05.
En el gráfico de residuales vs valores ajustados se observa que aparentemente la varianza de los residuales disminuye para valores ajustados mayores, sin embargo, se ejecutaron 2 pruebas de hipótesis por sospecha (la de Breusch-Pagan y Goldfeld-Quant) con las cuales se corrobora el supuesto de varianza constante.
Finalmente se observa que los residuales presentan un comportamiento aleatorio y simétrico a cero en el gráfico de residuales vs valores ajustados, esta afirmación se corrobora con la prueba de Durbin-Watson con la cual no se rechaza la hipótesis nula de correlación de residuales igual a 0.
La gráfica de apalancamiento no muestra valores influyentes.
A continuación, se presenta un intervalo de confianza del 95% para los coeficientes del modelo.
confint(precioapto)
2.5 % 97.5 %
(Intercept) 198.8823335 201.969623
areaconst 0.4729702 0.513453
Como el intérvalo del coeficiente viviendalimpiaapto$areaconst no contiene el valor cero, se confirma por otro criterio (a parte de la significancia obtenida por el p-valor) que dicho valor es distinto de cero y que el cambio de un metro cuadrado en el área construida influye de 0.47 a 0.51 veces en el precio de los apartamentos, mientras que, independientemente del área construida, el precio de los apartamentos parten de 199 a 202 millones con una confianza del 95%.
Se realizó una exploración de modelos utilizando transformaciones logarítmicas para el modelo de predicción de precio de casas que se muestran a continuación.
y <- viviendalimpiacasas$preciom
logy <- log(y)
x <- viviendalimpiacasas$areaconst
logx <- log(x)
modelo1 <- lm(y ~ x) #lin-lin
modelo2 <- lm(logy ~ x) #log-lin
modelo3 <- lm(y ~ logx) #lin-log
modelo4 <- lm(logy ~ logx) #log-log
stargazer(modelo1, modelo2, modelo3, modelo4,
type = "text",
df = FALSE,
title = "Exploracaión Modelos Precio vs Area Casas")
Exploracaión Modelos Precio vs Area Casas
=======================================================================
Dependent variable:
---------------------------------------------------
y logy y logy
(1) (2) (3) (4)
-----------------------------------------------------------------------
x 0.514*** 0.002***
(0.010) (0.00004)
logx 64.607*** 0.244***
(1.358) (0.005)
Constant 197.794*** 5.324*** -46.639*** 4.401***
(1.399) (0.005) (6.619) (0.024)
-----------------------------------------------------------------------
Observations 343 343 343 343
R2 0.888 0.885 0.869 0.876
Adjusted R2 0.888 0.885 0.869 0.875
Residual Std. Error 7.371 0.028 7.978 0.029
F Statistic 2,710.607*** 2,621.839*** 2,264.156*** 2,403.096***
=======================================================================
Note: *p<0.1; **p<0.05; ***p<0.01
Se observa que el mejor modelo es el primero (lin-lin) descrito descrito en el apartado “Modelo para estimar precio de casas” ya que se obtiene tanto un R cuadrado y un valor F mayor que el resto de modelos.
De igual manera, se realizó una exploración de modelos para la predicción del precio de apartamentos, los resultados se presentan a continuación.
y <- viviendalimpiaapto$preciom
logy <- log(y)
x <- viviendalimpiaapto$areaconst
logx <- log(x)
modelo1 <- lm(y ~ x) #lin-lin
modelo2 <- lm(logy ~ x) #log-lin
modelo3 <- lm(y ~ logx) #lin-log
modelo4 <- lm(logy ~ logx) #log-log
stargazer(modelo1, modelo2, modelo3, modelo4,
type = "text",
df = FALSE,
title = "Exploracaión Modelos Precio vs Area Apartamentos")
Exploracaión Modelos Precio vs Area Apartamentos
=======================================================================
Dependent variable:
---------------------------------------------------
y logy y logy
(1) (2) (3) (4)
-----------------------------------------------------------------------
x 0.493*** 0.002***
(0.010) (0.00004)
logx 39.250*** 0.163***
(0.851) (0.004)
Constant 200.426*** 5.316*** 69.112*** 4.771***
(0.787) (0.003) (3.643) (0.015)
-----------------------------------------------------------------------
Observations 1,342 1,342 1,342 1,342
R2 0.630 0.618 0.613 0.606
Adjusted R2 0.630 0.618 0.613 0.606
Residual Std. Error 7.097 0.030 7.257 0.031
F Statistic 2,284.902*** 2,168.182*** 2,126.870*** 2,064.912***
=======================================================================
Note: *p<0.1; **p<0.05; ***p<0.01
También se observa que el modelo lin-lin descrito en el apartado “Modelo para estimar precio de apartamentos” es el mejor teniendo en cuenta los mismos criterios de la exploración anterior.
Si por ejemplo, se quisiera estimar el precio promedio de un apartamento de 110 metros cuadrados, utilizando el modelo desarrollado, se obtendría un valor entre 253.85 y 255.50 millones con una confianza del 95%
predict.lm(precioapto, data.frame(areaconst = 110),
interval = "confidence", level = 0.95)
fit lwr upr
1 254.6793 253.8559 255.5026
Si la inmobiliaria encontrara un apartamento con la misma área en un precio de 200 millones de pesos, sería una oferta muy atractiva ya que como se estimó, el precio es mayor, esto bajo las consideraciones de condición del apartamento, estado físico, estado legal, etc.