Problema
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 (vivienda4.RDS) la inmobiliaria A&C requiere el apoyo de un cientifico de datos en la construcción de un modelo que lo oriente sobre los precios de inmuebles.
Con este propósito el equipo de asesores a diseñado los siguientes pasos para obtener un modelo y así poder a futuro determinar los precios de los inmuebles a negociar
Rta./
#Importamos los datos
library(devtools)
## Loading required package: usethis
devtools::install_github("dgonxalex80/paqueteMETODOS")
## Skipping install of 'paqueteMETODOS' from a github remote, the SHA1 (9696ffdc) has not changed since last install.
## Use `force = TRUE` to force installation
library(paqueteMETODOS)
## Loading required package: cubature
## Loading required package: GGally
## Loading required package: ggplot2
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
## Loading required package: MASS
## Loading required package: summarytools
## Loading required package: psych
##
## Attaching package: 'psych'
## The following objects are masked from 'package:ggplot2':
##
## %+%, alpha
## Loading required package: tidyverse
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.3 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ lubridate 1.9.2 ✔ tibble 3.2.1
## ✔ purrr 1.0.1 ✔ tidyr 1.3.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ psych::%+%() masks ggplot2::%+%()
## ✖ psych::alpha() masks ggplot2::alpha()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ✖ dplyr::select() masks MASS::select()
## ✖ tibble::view() masks summarytools::view()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
data(vivienda4)
Analisis exploratorio
str(vivienda4)
## spc_tbl_ [1,706 × 5] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ zona : Factor w/ 5 levels "Zona Centro",..: 2 2 2 5 2 2 2 2 2 2 ...
## $ estrato : Factor w/ 4 levels "3","4","5","6": 2 2 2 2 2 2 2 2 2 2 ...
## $ preciom : num [1:1706] 220 600 320 290 220 305 220 162 225 370 ...
## $ areaconst: num [1:1706] 52 160 108 96 82 117 75 60 84 117 ...
## $ tipo : Factor w/ 2 levels "Apartamento",..: 1 2 1 1 1 2 1 1 1 1 ...
El dataset nos muestra 1706 registros con 5 variables a saber : zona, estrato, preciom, areaconst, y tipo
summary(vivienda4)
## zona estrato preciom areaconst
## Zona Centro : 8 3: 0 Min. : 78.0 Min. : 40.00
## Zona Norte : 288 4:1706 1st Qu.:160.0 1st Qu.: 60.00
## Zona Oeste : 60 5: 0 Median :210.0 Median : 75.00
## Zona Oriente: 6 6: 0 Mean :225.4 Mean : 87.63
## Zona Sur :1344 3rd Qu.:265.0 3rd Qu.: 98.00
## Max. :760.0 Max. :200.00
## tipo
## Apartamento:1363
## Casa : 343
##
##
##
##
La función nos ofrece resumen de resultados, indicando la siguiente información importante:
Precio en millones, mínimo de 78m y máximo 760m con una mediana de 210m.
Área construida:, mínimo de 40m, máximo de 200m, y una media de 87.63m
Ahora veamos algunos indicadores estadísticos:
vivienda4|> summarise(media = mean(preciom),
varianza = var(preciom),
desviación = sd(preciom),
Q1 = quantile(preciom, probs=0.25),
P90 = quantile(preciom, probs=0.90))
## # A tibble: 1 × 5
## media varianza desviación Q1 P90
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 225. 7376. 85.9 160 340
Podemos observar que el preciom medio es 225millones, con desviación estandar de 85.88 y un primer cuartil de 160m y un percentil 90 de 340m que nos indica que el 90% de las viviendas el precio será inferior a 340m.
vivienda4|> summarise(media = mean(areaconst),
varianza = var(areaconst),
desviación = sd(areaconst),
Q1 = quantile(areaconst, probs=0.25),
D4 = quantile(areaconst, probs=0.40),
P90 = quantile(areaconst, probs=0.90))
## # A tibble: 1 × 6
## media varianza desviación Q1 D4 P90
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 87.6 1321. 36.3 60 70 144.
Podemos observar que el área constrsuida media es de 87.62metros, con desviación estandar de 36.34. Un primer cuartil de 60metros, un cuantil 0.40 de 70 metros y un percentil 90 de 144.5m que nos indica que el 90% de las viviendas el área construida esta por debajo de 144.5metros.
Ahora veamoslo en histogramas una distribución similar que puede significar correlación:
#Definamos primero variables que usaremos en adelante:
area = vivienda4$areaconst
precio = vivienda4$preciom
#Graficamos precio
hist(precio, main = "Precio vivienda Finca Raiz", xlab = "Valor en Millones", col = "green")
#Graficamos área construida
hist(area, main = "Área construida vivienda Finca Raiz", xlab = "Medida en Metros Cuadrados", col = "green")
Rta./ Para esto usamos la librería Plot
plot(area,precio,xlab = "Área construida (en metros cuadrados)", ylab = "Precio (en millones)", main = "Análisis Exploratorio Bivariado")
Como podemos observar en este gráfico, la dispersión nos indica que hay una relación lineal positiva. Lo que podemos validar nuevamente utilizando la función de correlación:
cor(area,precio)
## [1] 0.7630166
Rta./
model=lm(precio ~ area)
summary(model)
##
## Call:
## lm(formula = precio ~ area)
##
## Residuals:
## Min 1Q Median 3Q Max
## -195.86 -31.95 -8.95 27.87 431.17
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 67.381 3.510 19.20 <2e-16 ***
## area 1.803 0.037 48.73 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 55.53 on 1704 degrees of freedom
## Multiple R-squared: 0.5822, Adjusted R-squared: 0.5819
## F-statistic: 2374 on 1 and 1704 DF, p-value: < 2.2e-16
Creemos un gráfico de dispersión y añadamos una línea de regresión lineal
plot(area, precio, xlab = "Área construida", ylab= "Precio", main = "Prueba de Regresión Lineal")
abline(model, col ="green")
Por el modelo creado, podemos establecer que el intercepto ó β0 es 67.3 y el β1 es 1.8. Lo anterior nos indica que el precio es de 67.3millones y que por cada metro construido, el precio aumentará 1.8 millones.
Rta./
par(mfrow=c(2,2))
plot(model)
confint(model, level = 0.95)
## 2.5 % 97.5 %
## (Intercept) 60.496208 74.265055
## area 1.730404 1.875547
Usando la función confint del paquete stats pudimos construir el intervalo de confianza de 95% observando que la pendiente β1 se situa entre 1.73 y 1.87, es decir que a cada metro el precio del mismo aumenta entre 1.73 y 1.87. De igual forma, como tanto β0 y β1 difieren de cero, se rechaza la hipotesis nula y acepta la alterna.
Rta./
model=lm(precio ~ area)
summary(model)
##
## Call:
## lm(formula = precio ~ area)
##
## Residuals:
## Min 1Q Median 3Q Max
## -195.86 -31.95 -8.95 27.87 431.17
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 67.381 3.510 19.20 <2e-16 ***
## area 1.803 0.037 48.73 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 55.53 on 1704 degrees of freedom
## Multiple R-squared: 0.5822, Adjusted R-squared: 0.5819
## F-statistic: 2374 on 1 and 1704 DF, p-value: < 2.2e-16
Como ya vimos cuando creamos el modelo, encontramos que el coeficiente de determinación multiple es:
Multiple R-squared: 0.5822
y el coeficiente de determinación ajustado es:
Adjusted R-squared: 0.5819
Esto nos indica que el precio de los apartamentos se explica en un 58.22% por el área de construcción de cada uno. Este número tambien nos indica que existen otros factores que influyen en el precio final de cada apartamento.
Rta./
metraje = 110 #Área deseada
datos_prediccion = data.frame(area = metraje)
precio = predict(model, newdata = datos_prediccion)
print(precio)
## 1
## 265.7079
El precio que arroja la predicción es de 265millones para un apartamento de 110 metros cuadrados.
Considero que es una buena oferta, ya que por 200millones la predicción nos dice que le alcanzaría para solo 73-74 metros cuadrados.
De igual forma recordemos que el Multiple R-squared explica en un 58.22% el precio. Existen otros factores que pueden intervenir.
Rta./
residuals = model$residuals
hist(residuals, main = "Histograma de residuos del modelo",col="green" )
qqnorm(residuals)
qqline(residuals,col="green")
Linealidad:
De acuerdo a estas gráficas, podemos presumir que hay una relación lineal entre los metros de área construida y el precio de la vivienda.
par(mfrow=c(2,2))
plot(model)
Normalidad:
Como no conocemos la media y la varianza del modelo, se usa el test de Lilliefors, que nos rechazan la hipotesis nula indicando que los datos no tienen una distribución normal.
install.packages("nortest") # Recordar instalar nortest
library(nortest)
lillie.test(residuals)
##
## Lilliefors (Kolmogorov-Smirnov) normality test
##
## data: residuals
## D = 0.077968, p-value < 2.2e-16
Autocorrelación:
Al realizar un test de Durbin-Watson podemos darnos cuenta que la correlación es positiva.
lmtest::dwtest(model)
##
## Durbin-Watson test
##
## data: model
## DW = 1.6713, p-value = 5.124e-12
## alternative hypothesis: true autocorrelation is greater than 0
Homocedasticidad:
res.estudentizados <- studres(model) #cálculo de residuos estudentizados
plot(model$fitted.values, res.estudentizados, ylab = "Residuos Estudentizados", xlab = "Valores Ajustados")
abline(h = 0, lty = 2)
Ahora ejecutemos la prueba de Breusch-Pagan
library(zoo)
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(lmtest)
bptest(model)
##
## studentized Breusch-Pagan test
##
## data: model
## BP = 152.8, df = 1, p-value < 2.2e-16
Siendo 152.8 nos indica que hay diferencia entre el modelo que asume homocedasticidad y el modelo que permite heterocedasticidad, y siendo p un valor muy bajo casi cero, podemos decir que no satisface la suposición de Homocedasticidad lo que puede significar que las varianzas de los errores no es constante y que toque aplicar transformaciones.
Rta./
Cómo vimos en el punto 7, si es necesario aplicar transformaciones para tratar la heterocedasticidad en los datos.
Lo haremos usando la librería MASS
model=lm(vivienda4$preciom ~ vivienda4$areaconst) # necesario aplicarse a la variable de respuesta original, sino fallara boxcox
library(MASS)
bc= boxcox(model)
plot(bc)
Ahora encontremos el valor óptimo de lambda
lambda=bc $x [which.max(bc$y)]
lambda
## [1] -0.1010101
Este valor bajo nos sugiere que no es una transformación simple. Podemos usarlo para aplicar la transformación de boxcox
model2 <- lm (((bc$ x ^ lambda-1) / lambda) ~ bc$y)
model2
##
## Call:
## lm(formula = ((bc$x^lambda - 1)/lambda) ~ bc$y)
##
## Coefficients:
## (Intercept) bc$y
## -11.253062 -0.002625
Ahora veamos el resumen de nuestro nuevo modelo (model2)
summary(model2)
##
## Call:
## lm(formula = ((bc$x^lambda - 1)/lambda) ~ bc$y)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.5535 -0.2499 0.2295 0.5074 0.5976
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.125e+01 1.503e+00 -7.485 1.33e-09 ***
## bc$y -2.625e-03 3.609e-04 -7.274 2.80e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.7634 on 48 degrees of freedom
## (50 observations deleted due to missingness)
## Multiple R-squared: 0.5243, Adjusted R-squared: 0.5144
## F-statistic: 52.91 on 1 and 48 DF, p-value: 2.8e-09
R2 disminuye de 58.2% a 52% pero p-value sigue siendo signficativo con un p-value <0.05
De ser necesario compare el ajuste y supuestos del modelo inicial y el transformado.
Rta./
Estime varios modelos y compare los resultados obtenidos. En el mejor de los modelos, ¿se cumplen los supuestos sobre los errores?
Rta./
Con los resultados obtenidos construya un informe para los directivos de la inmobiliaria, indicando el modelo apropiado y sus principales características. A este informe se deben añadir los anexos como evidencia de la realización de los pasos anteriores.
Rta./