Elaborado por: Angélica Forero
Actualmente las ventas de bienes raíces en Cali se han visto disminuidas de manera significativa en lo corrido del año. Durante este periodo muchas instituciones bancarias de ahorro y vivienda están prestando grandes sumas de dinero para la industria y la construcción comercial y residencial. Cuando el efecto producto de las tensiones políticas y sociales disminuya, se espera que la actividad económica de este sector se reactive.
Hace dos días, María recibió una carta solicitando asesoría para la compra de dos viviendas por parte de una compañía internacional que desea ubicar a dos de sus empleados con sus familias en la ciudad. Las solicitudes incluyen las siguientes condiciones:
Ayude a María a responder la
solicitud, mediante técnicas modelación que usted conoce. Ella requiere
le envíe un informe ejecutivo donde analice los dos casos y sus
recomendaciones (Informe). Como soporte del informe debe anexar las
estimaciones, validaciones y comparación de modelos requeridos
(Anexos)
Pasos requeridos para la obtención de los resultados:
Filtro de datos y mapear zonas
Análisis Exploratorio
Modelo de regresión lineal múltiple
Validación de supuestos
Predicción precio vivienda
Solicitud vivienda 1
Solicitud vivienda 2
Cargar Librerías
En primer lugar, se cargan las librerías que utilizaremos durante toda la actividad. Adicionalmente establecemos desde el principio la configuración de las opciones de formato número. En este caso que evite la notación científica y que muestre números en notación decimal estándar.
library(paqueteMODELOS)
library(tidyverse)
library(dplyr)
library(psych)
library(mice)
library(factoextra)
library(plotly)
library(ggplot2)
library(FactoMineR)
library(leaflet)
library(corrplot)
library(boot)
library(lmtest)
library(car)
options(scipen = 100, digits = 2)
Creación de funciones
Se crean funciones que nos ayudarán a limpiar la información.La primera función tiene como finalidad dejar los campos tipos caracter en mayúscula y eliminar los espacios.
LimpiarNombres <- function(s){
x<-trimws(str_to_upper(gsub("([\\s])\\1+","\\1",s, perl=T)))
return(x)
}
Cargar conjunto de datos
data(vivienda)
Se utiliza la función ‘glimpse’ que nos proporcionará una vista general de los datos. El número de registros, el número de campos y la clase a la que pertenecen esos campos.
glimpse(vivienda)
## Rows: 8,322
## Columns: 13
## $ id <dbl> 1147, 1169, 1350, 5992, 1212, 1724, 2326, 4386, 1209, 159…
## $ zona <chr> "Zona Oriente", "Zona Oriente", "Zona Oriente", "Zona Sur…
## $ piso <chr> NA, NA, NA, "02", "01", "01", "01", "01", "02", "02", "02…
## $ estrato <dbl> 3, 3, 3, 4, 5, 5, 4, 5, 5, 5, 6, 4, 5, 6, 4, 5, 5, 4, 5, …
## $ preciom <dbl> 250, 320, 350, 400, 260, 240, 220, 310, 320, 780, 750, 62…
## $ areaconst <dbl> 70, 120, 220, 280, 90, 87, 52, 137, 150, 380, 445, 355, 2…
## $ parqueaderos <dbl> 1, 1, 2, 3, 1, 1, 2, 2, 2, 2, NA, 3, 2, 2, 1, 4, 2, 2, 2,…
## $ banios <dbl> 3, 2, 2, 5, 2, 3, 2, 3, 4, 3, 7, 5, 6, 2, 4, 4, 4, 3, 2, …
## $ habitaciones <dbl> 6, 3, 4, 3, 3, 3, 3, 4, 6, 3, 6, 5, 6, 2, 5, 5, 4, 3, 3, …
## $ tipo <chr> "Casa", "Casa", "Casa", "Casa", "Apartamento", "Apartamen…
## $ barrio <chr> "20 de julio", "20 de julio", "20 de julio", "3 de julio"…
## $ longitud <dbl> -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, -7…
## $ latitud <dbl> 3.4, 3.4, 3.4, 3.4, 3.5, 3.4, 3.4, 3.4, 3.5, 3.5, 3.4, 3.…
El conjunto de datos cuenta con 13 atributos y 8322 registros.
id: este dato es la identificación del registro por lo que tendremos en cuenta para saber si hay datos duplicados.
Vacíos
colSums(is.na(vivienda))
## id zona piso estrato preciom areaconst
## 3 3 2638 3 2 3
## parqueaderos banios habitaciones tipo barrio longitud
## 1605 3 3 3 3 3
## latitud
## 3
Duplicados
Con base en el id se identifican los duplicados
vivienda %>%
group_by(id) %>%
summarise(contar=n()) %>%
filter(contar>1)
## # A tibble: 1 × 2
## id contar
## <dbl> <int>
## 1 NA 3
Únicos
Algunos atributos categóricos y cuantitativos deberían tener muy pocas clases.Por lo tanto, seleccionamos los datos e identificamos los valores únicos que tienen.
var <- c("zona","piso", "estrato","parqueaderos","banios","habitaciones","tipo")
for(variable in var){
unicos<- vivienda %>%
group_by(!!sym(variable)) %>%
summarise(registros = n())
print(unicos)
}
## # A tibble: 6 × 2
## zona registros
## <chr> <int>
## 1 Zona Centro 124
## 2 Zona Norte 1920
## 3 Zona Oeste 1198
## 4 Zona Oriente 351
## 5 Zona Sur 4726
## 6 <NA> 3
## # A tibble: 13 × 2
## piso registros
## <chr> <int>
## 1 01 860
## 2 02 1450
## 3 03 1097
## 4 04 607
## 5 05 567
## 6 06 245
## 7 07 204
## 8 08 211
## 9 09 146
## 10 10 130
## 11 11 84
## 12 12 83
## 13 <NA> 2638
## # A tibble: 5 × 2
## estrato registros
## <dbl> <int>
## 1 3 1453
## 2 4 2129
## 3 5 2750
## 4 6 1987
## 5 NA 3
## # A tibble: 11 × 2
## parqueaderos registros
## <dbl> <int>
## 1 1 3155
## 2 2 2475
## 3 3 520
## 4 4 384
## 5 5 68
## 6 6 68
## 7 7 18
## 8 8 17
## 9 9 4
## 10 10 8
## 11 NA 1605
## # A tibble: 12 × 2
## banios registros
## <dbl> <int>
## 1 0 45
## 2 1 496
## 3 2 2946
## 4 3 1993
## 5 4 1456
## 6 5 890
## 7 6 314
## 8 7 107
## 9 8 48
## 10 9 15
## 11 10 9
## 12 NA 3
## # A tibble: 12 × 2
## habitaciones registros
## <dbl> <int>
## 1 0 66
## 2 1 59
## 3 2 926
## 4 3 4097
## 5 4 1729
## 6 5 679
## 7 6 318
## 8 7 173
## 9 8 138
## 10 9 83
## 11 10 51
## 12 NA 3
## # A tibble: 3 × 2
## tipo registros
## <chr> <int>
## 1 Apartamento 5100
## 2 Casa 3219
## 3 <NA> 3
De esta primera parte podemos evidenciar que hay 1 valor que se repite 3 veces y es el id NA. El atributo piso está en tipo caracter y tiene 2638 registros NA. El atributo parqueadero tiene 1605 registros NA. Los demás atributos tienen 3 valores NA que corresponden a los valores que se están repitiendo.
Eliminación de datos
Eliminamos los datos NA
vivienda <-vivienda[!is.na(vivienda$id),]
Estandarización de los datos tipo caracter
vivienda <- vivienda %>%
mutate_if(is.character, LimpiarNombres)
Cambiar el tipo de atributo piso
Se cambia el tipo de atributo del piso puesto que está como caracter
vivienda$piso <-as.numeric(vivienda$piso)
Corregir datos de Barrio
Los caracteres “É” y “Ú” los está tomando con los caracteres “√©” y “√∫”, respectivamente. Por lo tanto, hacemos los cambios. También algunos están tomando las tílde entonces dejamos todos los datos sin tíldes.
vivienda$barrio <- gsub("é", "E", vivienda$barrio)
vivienda$barrio <- gsub("√∫", "U", vivienda$barrio)
vivienda$barrio <- gsub("Á", "A", vivienda$barrio)
vivienda$barrio <- gsub("É", "E", vivienda$barrio)
vivienda$barrio <- gsub("Í", "I", vivienda$barrio)
vivienda$barrio <- gsub("Ó", "O", vivienda$barrio)
vivienda$barrio <- gsub("Ú", "U", vivienda$barrio)
Reemplezar NA parqueaderos
vivienda$parqueaderos[is.na(vivienda$parqueaderos)]<-0
Realice un filtro a la base de datos e incluya solo las ofertas de: base1: casas, de la zona norte de la ciudad. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta. (Adicional un mapa con los puntos de las bases. Discutir si todos los puntos se ubican en la zona correspondiente o se presentan valores en otras zonas, por que?).
casas <- vivienda %>%
filter(tipo =="CASA", zona=="ZONA NORTE") %>%
select(-id)
head(casas,3)
## # A tibble: 3 × 12
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 ZONA N… 2 5 320 150 2 4 6 CASA
## 2 ZONA N… 2 5 780 380 2 3 3 CASA
## 3 ZONA N… 2 6 750 445 0 7 6 CASA
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
Verificación filtro
Para verificar el filtro extraemos los datos únicos de algunas variables
var <- c("zona","piso", "estrato","parqueaderos","banios","habitaciones","tipo")
for(variable in var){
unicos<- casas %>%
group_by(!!sym(variable)) %>%
summarise(registros = n())
print(unicos)
}
## # A tibble: 1 × 2
## zona registros
## <chr> <int>
## 1 ZONA NORTE 722
## # A tibble: 6 × 2
## piso registros
## <dbl> <int>
## 1 1 84
## 2 2 194
## 3 3 65
## 4 4 6
## 5 7 1
## 6 NA 372
## # A tibble: 4 × 2
## estrato registros
## <dbl> <int>
## 1 3 235
## 2 4 161
## 3 5 271
## 4 6 55
## # A tibble: 11 × 2
## parqueaderos registros
## <dbl> <int>
## 1 0 287
## 2 1 161
## 3 2 158
## 4 3 49
## 5 4 40
## 6 5 11
## 7 6 8
## 8 7 5
## 9 8 1
## 10 9 1
## 11 10 1
## # A tibble: 11 × 2
## banios registros
## <dbl> <int>
## 1 0 10
## 2 1 17
## 3 2 165
## 4 3 187
## 5 4 171
## 6 5 101
## 7 6 46
## 8 7 11
## 9 8 11
## 10 9 1
## 11 10 2
## # A tibble: 11 × 2
## habitaciones registros
## <dbl> <int>
## 1 0 20
## 2 1 2
## 3 2 12
## 4 3 171
## 5 4 222
## 6 5 137
## 7 6 60
## 8 7 42
## 9 8 29
## 10 9 14
## 11 10 13
## # A tibble: 1 × 2
## tipo registros
## <chr> <int>
## 1 CASA 722
Mapa
mapa_casa <- leaflet(casas) %>%
addTiles() %>%
addMarkers(lng = ~longitud,
lat = ~latitud)
mapa_casa
Se puede observar que no todos los puntos están en la zona norte. No obstante, la mayoría de ellos sí se encuentran ubicados en esa área.
Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio de la casa) en función del área construida, estrato, numero de baños, número de habitaciones y zona donde se ubica la vivienda. Use gráficos interactivos con el paquete plotly e interprete los resultados.
Datos
Para entender la data de casas realizamos un summary
summary(casas)
## zona piso estrato preciom areaconst
## Length:722 Min. :1 Min. :3.0 Min. : 89 Min. : 30
## Class :character 1st Qu.:2 1st Qu.:3.0 1st Qu.: 261 1st Qu.: 140
## Mode :character Median :2 Median :4.0 Median : 390 Median : 240
## Mean :2 Mean :4.2 Mean : 446 Mean : 265
## 3rd Qu.:2 3rd Qu.:5.0 3rd Qu.: 550 3rd Qu.: 337
## Max. :7 Max. :6.0 Max. :1940 Max. :1440
## NA's :372
## parqueaderos banios habitaciones tipo
## Min. : 0.0 Min. : 0.0 Min. : 0.0 Length:722
## 1st Qu.: 0.0 1st Qu.: 2.0 1st Qu.: 3.0 Class :character
## Median : 1.0 Median : 3.0 Median : 4.0 Mode :character
## Mean : 1.3 Mean : 3.6 Mean : 4.5
## 3rd Qu.: 2.0 3rd Qu.: 4.0 3rd Qu.: 5.0
## Max. :10.0 Max. :10.0 Max. :10.0
##
## barrio longitud latitud
## Length:722 Min. :-77 Min. :3.3
## Class :character 1st Qu.:-77 1st Qu.:3.5
## Mode :character Median :-77 Median :3.5
## Mean :-77 Mean :3.5
## 3rd Qu.:-77 3rd Qu.:3.5
## Max. :-76 Max. :3.5
##
Análisis atributos
boxplot(casas$preciom, casas$areaconst,
names = c("Precio", "Área"),
main = "Diagrama de Caja",
ylab = "Valores")
barplot(prop.table(table(casas$estrato)),
ylab = "Proportion",
xlab = "Estrato")
barplot(prop.table(table(casas$banios)),
ylab = "Proportion",
xlab = "Baños")
barplot(prop.table(table(casas$habitaciones)),
ylab = "Proportion",
xlab = "Habitaciones")
barplot(prop.table(table(casas$parqueaderos)),
ylab = "Proportion",
xlab = "Parqueaderos")
casa_ea <- casas %>%
select(preciom, areaconst, parqueaderos, estrato, banios, habitaciones)
matriz_cor_casa <- cor(casa_ea)
corrplot(matriz_cor_casa, method = "color", addCoef.col = "black")
ggpairs(casa_ea)
De acuerdo con la información previa, se observa que la mayoría de las casas se encuentran en el rango de estratos 3 a 5, con 2 a 4 baños, 3 a 5 habitaciones y 0 a 2 parqueaderos. Además, el promedio del precio de las casas es de 446 millones con un área promedio de 265. Al analizar las correlaciones, se destaca una relación lineal muy significativa entre el precio y el área (0.76), así como entre el precio y el estrato (0.62). En contraste, no se evidencia una correlación tan marcada entre el precio y el número de baños, habitaciones y paqueaderos. Por lo tanto, se puede inferir que el área y el estrato influyen considerablemente en el precio, indicando que a mayor área o estrato, mayor será el valor de la vivienda.
Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños ) ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deben estár contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).
set.seed(42)
modelo_casa <- lm(formula = preciom~areaconst+estrato+habitaciones+parqueaderos+banios, data = casa_ea)
summary(modelo_casa)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = casa_ea)
##
## Residuals:
## Min 1Q Median 3Q Max
## -964.0 -80.1 -17.1 50.1 1069.4
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -236.4755 30.3658 -7.79 0.000000000000024 ***
## areaconst 0.8268 0.0437 18.93 < 0.0000000000000002 ***
## estrato 86.4258 7.3975 11.68 < 0.0000000000000002 ***
## habitaciones 1.4444 4.1641 0.35 0.73
## parqueaderos -1.6767 4.3150 -0.39 0.70
## banios 26.9798 5.3438 5.05 0.000000564653292 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 159 on 716 degrees of freedom
## Multiple R-squared: 0.651, Adjusted R-squared: 0.648
## F-statistic: 267 on 5 and 716 DF, p-value: <0.0000000000000002
El modelo muestra que las variables área, estrato y número de baños tienen un impacto significativo sobre el precio de la casa, mientras que el número de habitaciones y paqueaderos no parecen ser tan relevantes.
Los coeficientes proporcionan información adicional: por cada metro cuadrado adicional en una casa, el precio aumenta en 0.8268 unidades, lo que equivale aproximadamente a $826,000. Un nivel de estrato más alto se traduce en un incremento de aproximadamente $86 millones en el precio de la casa, y cada baño adicional contribuye a un aumento de $26 millones en el precio, manteniendo constantes las otras variables en cada caso.
Estos resultados tienen sentido: se esperaría que un estrato más elevado correspondiera a una zona más exclusiva, aumentando así el precio. Además, es lógico que una casa con mayor área tenga un precio más alto. Sin embargo, llama la atención que el número de baños tenga un impacto mayor que el área en el precio de la casa.
El valor R^2 nos indica que el modelo explica aproximadamente el 65.1% de la variabilidad observada en el precio de las casas.
Se pueden realizar técnicas de validación cruzada con el fin de evaluar la capacidad predictiva del modelo y seleccionar las mejores variables presictoras. Evitando el sobreajuste y mejorando la generalización del modelo.
Validación Cruzada
# Se define la función que devuelve el estadístico de interés, los coeficientes
# de regresión
set.seed(42)
fun_coeficientes <- function(data, index){
return(coef(lm(formula = preciom~areaconst+estrato+habitaciones+parqueaderos+banios,
data = casa_ea, subset = index)
)
)
}
boot(data = casa_ea, statistic = fun_coeficientes, R = 9999)
##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = casa_ea, statistic = fun_coeficientes, R = 9999)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* -236.48 2.120 32.21
## t2* 0.83 0.008 0.11
## t3* 86.43 -0.793 9.54
## t4* 1.44 -0.065 5.23
## t5* -1.68 -0.136 5.46
## t6* 26.98 -0.166 7.55
La validación cruzada revela que, de las tres variables que influyen en el precio, el área es la variable que presenta menor sesgo (0.0087) y mayor precisión (0.11). En cuanto al estrato, la estimación del coeficiente tiende, en promedio, a ser aproximadamente 0.793 unidades más baja de lo que sería sin sesgo, mientras que para los baños este valor es de 0.166. Además, el error estándar indica que las estimaciones del coeficiente del estrato (86.43) pueden variar, en promedio, alrededor de 9.54 unidades de su valor estimado, mientras que para los baños este valor es de 7.55.
Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).
Se realiza la prueba de Shapiro-Wilk para evaluar formalmente si los residuos siguen una distribución normal.
print(shapiro.test(resid(modelo_casa)))
##
## Shapiro-Wilk normality test
##
## data: resid(modelo_casa)
## W = 0.8, p-value <0.0000000000000002
La prueba de Shapiro sugiere que los residuos en el modelo no siguen una distribución normal. Esto nos indica que el modelo posiblemente no está capturando completamente la estructura de los datos. El impacto de esto es que al final puede afectar la precisión de las predicciones. Existen varias técnicas que se pueden utilizar cuando los residuos del modelo no siguen una distribución normal:
Se podrían transformar las variables para que se ajusten mejor a una distribución normal, por ejmplo, utilizar una transformación logarítmica o Box-Cox.
Utilizar modelos de regresión que son menos sensibles a las violaciones de los supuestos de normalidad y homocedasticidad, por ejemplo, regresión robusta de mínimos cuadrados ordinarios (MCO) o la regresión robusta de mínimos cuadrados no paramétricos (MNCP)
plot(fitted(modelo_casa), resid(modelo_casa),
xlab = "Valores Ajustados", ylab = "Residuos",
main = "Gráfico de Residuos vs. Valores Ajustados")
abline(h = 0, col = "red", lty = 2) # Agregar línea horizontal en y = 0
print(gqtest(modelo_casa))
##
## Goldfeld-Quandt test
##
## data: modelo_casa
## GQ = 1, df1 = 355, df2 = 355, p-value = 0.1
## alternative hypothesis: variance increases from segment 1 to 2
De acuerdo al gráfico y a la prueba de Goldfeld-Quandt, el supuesto de varianza constante no se viola en el modelo de regresión, es decir que los efectos de las variables predictoras (área, estrato, parqueadero, habitaciones, baños) en la varianza de los errores son consistentes en todo el rango de los datos. Esto proporciona una mayor confianza en las estimaciones y predicciones del modelo.
print(dwtest(modelo_casa))
##
## Durbin-Watson test
##
## data: modelo_casa
## DW = 2, p-value = 0.0000003
## alternative hypothesis: true autocorrelation is greater than 0
De acuerdo con los resultados de la prueba de Durbin-Watson, el modelo no cumple con el supuesto de independencia de los errores. Esto indica que el modelo puede estar subestimando o sobreestimando consistentemente los precios de las propiedades en función de las características del modelo. Se puede abordar este problema a través de:
Transformación de las variables, por ejmplo, utilizar una transformación logarítmica o Box-Cox.
Corrección de errores autocorrelacionados, por ejemplo, los modelos de autorregresión con errores ARIMA (ARIMA errors), los modelos de series temporales con términos autorregresivos de error o la inclusión de retardos adicionales de la variable dependiente en el modelo.
A través del análisis de la varianza inflada (VIF), se puede calcular un factor para cada variable independiente. VIF mayor que 10 indica alta multicolinealidad.
print(vif(modelo_casa))
## areaconst estrato habitaciones parqueaderos banios
## 1.5 1.5 1.6 1.2 1.9
Los resultados del Factor de Inflación de la Varianza (VIF) para las variables en el modeloson bastante bajos, lo que indica que no hay evidencia de multicolinealidad significativa entre las variables independientes.
Según los requisitos de la casa, estas son las características:
# Estrato 4
datos_casa4 <- data.frame(areaconst=200,
estrato=4,
habitaciones=4,
parqueaderos=1,
banios=2)
prediccion_precioc4 <- predict(modelo_casa, datos_casa4)
print(prediccion_precioc4)
## 1
## 333
De acuerdo al modelo, el precio con las características para la casa y en estrato 4 es de 333 millones
# Estrato 5
datos_casa5 <- data.frame(areaconst=200,
estrato=5,
habitaciones=4,
parqueaderos=1,
banios=2)
prediccion_precioc5 <- predict(modelo_casa, datos_casa5)
print(prediccion_precioc5)
## 1
## 419
De acuerdo al modelo, el precio con las características para la casa y en estrato 5 es de 419 millones.
Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 1. Tenga encuenta que la empresa tiene crédito pre-aprobado de máximo 350 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.
# Ofertas
ofertas_casas<- casas %>%
filter(preciom<=350,
areaconst>=200,
parqueaderos==1,
banios>=2,
habitaciones>=4,
estrato%in%c(4,5)) %>%
arrange(preciom)
head(ofertas_casas, 7)
## # A tibble: 7 × 12
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 ZONA N… NA 5 250 243 1 4 5 CASA
## 2 ZONA N… NA 5 321 249 1 5 5 CASA
## 3 ZONA N… 2 4 330 260 1 3 4 CASA
## 4 ZONA N… 1 5 335 202 1 4 5 CASA
## 5 ZONA N… 2 5 342 250 1 4 6 CASA
## 6 ZONA N… 3 4 350 350 1 4 5 CASA
## 7 ZONA N… NA 5 350 346 1 2 4 CASA
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
Mapa Ofertas
mapa_Ofertacasa <- leaflet(ofertas_casas) %>%
addTiles() %>%
addMarkers(lng = ~longitud,
lat = ~latitud)
mapa_Ofertacasa
De acuerdo con la información se cuenta con 7 ofertas que se encuentran en la zona norte, con precios entre los 250 millones a los 350 millones, en estratos entre 4 y 5, área construida de 243 a 346, 1 parqueadero, entre 2 a 5 baños y entre 4 a 6 habitaciones. Así mismo, la oferta que se ajusta totalmente a las necesidades se encuentra en el barrio Vipasa y tiene un precio de 350 millones.
Realice un filtro a la base de datos e incluya solo las ofertas de base2: apartamentos, de la zona sur de la ciudad. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta. (Adicional un mapa con los puntos de las bases. Discutir si todos los puntos se ubican en la zona correspondiente o se presentan valores en otras zonas, por que?).
apartamentos <- vivienda %>%
filter(tipo =="APARTAMENTO", zona=="ZONA SUR") %>%
select(-id)
head(apartamentos,3)
## # A tibble: 3 × 12
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 ZONA S… 5 4 290 96 1 2 3 APAR…
## 2 ZONA S… 2 3 78 40 1 1 2 APAR…
## 3 ZONA S… NA 6 875 194 2 5 3 APAR…
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
Verificación filtro
Para verificar el filtro extraemos los datos únicos de algunas variables
var <- c("zona","piso", "estrato","parqueaderos","banios","habitaciones","tipo")
for(variable in var){
unicos<- apartamentos %>%
group_by(!!sym(variable)) %>%
summarise(registros = n())
print(unicos)
}
## # A tibble: 1 × 2
## zona registros
## <chr> <int>
## 1 ZONA SUR 2787
## # A tibble: 13 × 2
## piso registros
## <dbl> <int>
## 1 1 255
## 2 2 319
## 3 3 329
## 4 4 327
## 5 5 353
## 6 6 131
## 7 7 113
## 8 8 129
## 9 9 73
## 10 10 73
## 11 11 29
## 12 12 34
## 13 NA 622
## # A tibble: 4 × 2
## estrato registros
## <dbl> <int>
## 1 3 201
## 2 4 1091
## 3 5 1033
## 4 6 462
## # A tibble: 6 × 2
## parqueaderos registros
## <dbl> <int>
## 1 0 406
## 2 1 1551
## 3 2 718
## 4 3 79
## 5 4 31
## 6 10 2
## # A tibble: 9 × 2
## banios registros
## <dbl> <int>
## 1 0 6
## 2 1 167
## 3 2 1588
## 4 3 662
## 5 4 229
## 6 5 123
## 7 6 10
## 8 7 1
## 9 8 1
## # A tibble: 7 × 2
## habitaciones registros
## <dbl> <int>
## 1 0 8
## 2 1 19
## 3 2 463
## 4 3 1902
## 5 4 366
## 6 5 24
## 7 6 5
## # A tibble: 1 × 2
## tipo registros
## <chr> <int>
## 1 APARTAMENTO 2787
Mapa
mapa_apartamento <- leaflet(apartamentos) %>%
addTiles() %>%
addMarkers(lng = ~longitud,
lat = ~latitud)
mapa_apartamento
Se puede observar que no todos los puntos están en la zona sur. No obstante, la mayoría de ellos sí se encuentran ubicados en esa área.
Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio del apartamento) en función del área construida, estrato, numero de baños, número de habitaciones y zona donde se ubica la vivienda. Use gráficos interactivos con el paquete plotly e interprete los resultados.
Datos
Para entender la data de apartamentos realizamos un summary
summary(apartamentos)
## zona piso estrato preciom areaconst
## Length:2787 Min. : 1 Min. :3.0 Min. : 75 Min. : 40
## Class :character 1st Qu.: 2 1st Qu.:4.0 1st Qu.: 175 1st Qu.: 65
## Mode :character Median : 4 Median :5.0 Median : 245 Median : 85
## Mean : 4 Mean :4.6 Mean : 297 Mean : 97
## 3rd Qu.: 6 3rd Qu.:5.0 3rd Qu.: 335 3rd Qu.:110
## Max. :12 Max. :6.0 Max. :1750 Max. :932
## NA's :622
## parqueaderos banios habitaciones tipo
## Min. : 0.0 Min. :0.0 Min. :0 Length:2787
## 1st Qu.: 1.0 1st Qu.:2.0 1st Qu.:3 Class :character
## Median : 1.0 Median :2.0 Median :3 Mode :character
## Mean : 1.2 Mean :2.5 Mean :3
## 3rd Qu.: 2.0 3rd Qu.:3.0 3rd Qu.:3
## Max. :10.0 Max. :8.0 Max. :6
##
## barrio longitud latitud
## Length:2787 Min. :-77 Min. :3.3
## Class :character 1st Qu.:-77 1st Qu.:3.4
## Mode :character Median :-77 Median :3.4
## Mean :-77 Mean :3.4
## 3rd Qu.:-77 3rd Qu.:3.4
## Max. :-76 Max. :3.5
##
Análisis atributos
boxplot(apartamentos$preciom, apartamentos$areaconst,
names = c("Precio", "Área"),
main = "Diagrama de Caja",
ylab = "Valores")
barplot(prop.table(table(apartamentos$estrato)),
ylab = "Proportion",
xlab = "Estrato")
barplot(prop.table(table(apartamentos$banios)),
ylab = "Proportion",
xlab = "Baños")
barplot(prop.table(table(apartamentos$habitaciones)),
ylab = "Proportion",
xlab = "Habitaciones")
barplot(prop.table(table(casas$parqueaderos)),
ylab = "Proportion",
xlab = "Parqueaderos")
apartamento_ea <- apartamentos %>%
select(preciom, areaconst, parqueaderos, estrato, banios, habitaciones)
matriz_cor_apartamento <- cor(apartamento_ea)
corrplot(matriz_cor_apartamento, method = "color", addCoef.col = "black")
ggpairs(apartamento_ea)
Según los datos previos, la mayoría de los apartamentos se ubican en el rango de estratos 4 a 5, con 2 a 3 baños, 3 habitaciones y de 0 a 2 parqueaderos. Además, el precio promedio de estos apartamentos es de 297 millones, con un área promedio de 97 metros cuadrados. Al examinar las correlaciones, se destaca una relación lineal muy significativa entre el precio y el área (0.76), así como entre el precio y el número de baños (0.72), el precio y el estrato (0.67), y el precio y el número de parqueaderos (0.67). En contraste, no se observa una correlación tan pronunciada entre el precio y el número de habitaciones (0.33). Por lo tanto, se puede inferir que el área, el estrato, el número de baños y los parqueaderos influyen considerablemente en el precio de los apartamentos.
Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños ) ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deben estár contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).
set.seed(42)
modelo_apartamento <- lm(formula = preciom~areaconst+estrato+habitaciones+parqueaderos+banios, data = apartamento_ea)
summary(modelo_apartamento)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = apartamento_ea)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1252.3 -42.1 -2.1 36.3 934.1
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -221.0461 13.4777 -16.40 < 0.0000000000000002 ***
## areaconst 1.4606 0.0488 29.96 < 0.0000000000000002 ***
## estrato 57.0061 2.7965 20.38 < 0.0000000000000002 ***
## habitaciones -22.7179 3.3955 -6.69 0.000000000027 ***
## parqueaderos 48.3635 3.0234 16.00 < 0.0000000000000002 ***
## banios 48.6087 3.0405 15.99 < 0.0000000000000002 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 95 on 2781 degrees of freedom
## Multiple R-squared: 0.754, Adjusted R-squared: 0.753
## F-statistic: 1.7e+03 on 5 and 2781 DF, p-value: <0.0000000000000002
El análisis revela la significancia de todas las variables consideradas (área, estrato, número de habitaciones, parqueaderos y baños).
Los coeficientes arrojan detalles adicionales: por cada metro cuadrado extra en un apartamento, el precio aumenta en 1.4606 unidades, aproximadamente $1’460.600. Un estrato más alto implica un incremento de alrededor de $57 millones en el precio del apartamento, mientras que cada habitación adicional reduce el precio en $22 millones. Por otro lado, cada parqueadero o baño adicional incrementa el precio en $48 millones, manteniendo las otras variables constantes.
Estos hallazgos son coherentes: se esperaría que un estrato más elevado estuviera asociado con una ubicación más exclusiva, lo que se traduce en un aumento en el precio. Además, resulta lógico que un apartamento más amplio tenga un precio más alto. Sin embargo, es notable que el número de baños y parqueaderos tenga un impacto más significativo en el precio que el área del apartamento, y que el número de habitaciones reduzca el precio del mismo.
El valor de R cuadrado (R^2) indica que el modelo explica aproximadamente el 75.4% de la variabilidad observada en el precio de los apartamentos.
Se pueden realizar técnicas de validación cruzada con el fin de evaluar la capacidad predictiva del modelo y seleccionar las mejores variables presictoras. Evitando el sobreajuste y mejorando la generalización del modelo.
Validación Cruzada
# Se define la función que devuelve el estadístico de interés, los coeficientes
# de regresión
set.seed(42)
fun_coeficientes <- function(data, index){
return(coef(lm(formula = preciom~areaconst+estrato+habitaciones+parqueaderos+banios,
data = apartamento_ea, subset = index)
)
)
}
boot(data = apartamento_ea, statistic = fun_coeficientes, R = 9999)
##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = apartamento_ea, statistic = fun_coeficientes, R = 9999)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* -221.0 2.25 17.78
## t2* 1.5 0.05 0.32
## t3* 57.0 -0.37 3.54
## t4* -22.7 -0.58 5.88
## t5* 48.4 -0.76 7.16
## t6* 48.6 -1.09 7.47
La validación cruzada revela que, entre las cinco variables que influyen en el precio, el área presenta el menor sesgo (0.05) y la mayor precisión (0.32). En cuanto al estrato, habitaciones, parqueaderos y baños, la estimación de cada coeficiente tiende, en promedio, a ser aproximadamente 0.37, 0.58, 0.76 y 1.09 unidades respectivamente más baja de lo que sería sin sesgo. Además, el error estándar indica que las estimaciones de los coeficientes del estrato, habitaciones, parqueaderos y baños pueden variar, en promedio, alrededor de 3.54, 5.88, 7.16 y 7.47 unidades respectivamente de su valor estimado.
Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).
Se realiza la prueba de Shapiro-Wilk para evaluar formalmente si los residuos siguen una distribución normal.
print(shapiro.test(resid(modelo_apartamento)))
##
## Shapiro-Wilk normality test
##
## data: resid(modelo_apartamento)
## W = 0.8, p-value <0.0000000000000002
La prueba de Shapiro sugiere que los residuos en el modelo no siguen una distribución normal. Esto nos indica que el modelo posiblemente no está capturando completamente la estructura de los datos. El impacto de esto es que al final puede afectar la precisión de la predicción del precio. Existen varias técnicas que se pueden utilizar cuando los residuos del modelo no siguen una distribución normal:
Se podrían transformar las variables para que se ajusten mejor a una distribución normal, por ejmplo, utilizar una transformación logarítmica o Box-Cox.
Utilizar modelos dde regresión que son menos sensibles a las violaciones de los supuestos de normalidad y homocedasticidad, por ejemplo, regresión robusta de mínimos cuadrados ordinarios (MCO) o la regresión robusta de mínimos cuadrados no paramétricos (MNCP)
plot(fitted(modelo_apartamento), resid(modelo_apartamento),
xlab = "Valores Ajustados", ylab = "Residuos",
main = "Gráfico de Residuos vs. Valores Ajustados")
abline(h = 0, col = "red", lty = 2) # Agregar línea horizontal en y = 0
print(gqtest(modelo_apartamento))
##
## Goldfeld-Quandt test
##
## data: modelo_apartamento
## GQ = 0.9, df1 = 1388, df2 = 1387, p-value = 0.9
## alternative hypothesis: variance increases from segment 1 to 2
De acuerdo al gráfico y a la prueba de Goldfeld-Quandt, el supuesto de varianza constante no se viola en el modelo de regresión, es decir que los efectos de las variables predictoras (área, estrato, parqueadero, habitaciones, baños) en la varianza de los errores son consistentes en todo el rango de los datos. Esto proporciona una mayor confianza en las estimaciones y predicciones del modelo.
print(dwtest(modelo_apartamento))
##
## Durbin-Watson test
##
## data: modelo_apartamento
## DW = 2, p-value <0.0000000000000002
## alternative hypothesis: true autocorrelation is greater than 0
De acuerdo con los resultados de la prueba de Durbin-Watson, el modelo no cumple con el supuesto de independencia de los errores. Esto indica que el modelo puede estar subestimando o sobreestimando consistentemente los precios de las propiedades en función de las características del modelo. Se puede abordar este problema a través de:
Transformación de las variables, por ejmplo, utilizar una transformación logarítmica o Box-Cox.
Corrección de errores autocorrelacionados, por ejemplo, los modelos de autorregresión con errores ARIMA (ARIMA errors), los modelos de series temporales con términos autorregresivos de error o la inclusión de retardos adicionales de la variable dependiente en el modelo.
A través del análisis de la varianza inflada (VIF), se puede calcular un factor para cada variable independiente. VIF mayor que 10 indica alta multicolinealidad.
print(vif(modelo_apartamento))
## areaconst estrato habitaciones parqueaderos banios
## 2.0 1.7 1.4 1.8 2.5
Los resultados del Factor de Inflación de la Varianza (VIF) para las variables en el modelo son bastante bajos, lo que indica que no hay evidencia de multicolinealidad significativa entre las variables independientes.
Según los requisitos del apartamento, estas son las características:
# Estrato 5
datos_apto5 <- data.frame(areaconst=300,
estrato=5,
habitaciones=5,
parqueaderos=3,
banios=3)
prediccion_precioa5 <- predict(modelo_apartamento, datos_apto5)
print(prediccion_precioa5)
## 1
## 679
De acuerdo al modelo, el precio con las características para el apartamento y en estrato 5 es de 679 millones.
# Estrato 6
datos_apto6 <- data.frame(areaconst=300,
estrato=6,
habitaciones=5,
parqueaderos=3,
banios=3)
prediccion_precioa6 <- predict(modelo_apartamento, datos_apto6)
print(prediccion_precioa6)
## 1
## 737
De acuerdo al modelo, el precio con las características para el apartamento y en estrato 5 es de 737 millones.
Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 2. Tenga encuenta que la empresa tiene crédito pre-aprobado de máximo 850 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.
# Ofertas
ofertas_aptos<- apartamentos %>%
filter(preciom<=850,
parqueaderos>=3,
habitaciones>=5,
estrato%in%c(5,6)) %>%
arrange(preciom)
head(ofertas_aptos, 3)
## # A tibble: 3 × 12
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 ZONA S… NA 5 530 256 3 5 5 APAR…
## 2 ZONA S… NA 5 670 300 3 5 6 APAR…
## 3 ZONA S… NA 5 730 573 3 8 5 APAR…
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
Mapa Ofertas
mapa_Ofertaapto <- leaflet(ofertas_aptos) %>%
addTiles() %>%
addMarkers(lng = ~longitud,
lat = ~latitud)
mapa_Ofertaapto
De acuerdo con la información se cuenta con 3 ofertas que se encuentran en la zona sur, con precios entre los 530 a 730 millones, en estratos 5, área construida de 256 a 573, 3 parqueadero, entre 5 a 8 baños y entre 5 a 6 habitaciones.