Maria comenzó como agente de bienes raíces en Cali hace 10 años. Después de laborar dos años para una empresa nacional, se traslado a Bogotá y trabajó para otra agencia de bienes raíces. Sus amigos y familiares la convencieron de que con su experiencia y conocimientos del negocio debía abrir su propia agencia. Terminó por adquirir la licencia de intermediario y al poco tiempo fundó su propia compañía, C&A (Casas y Apartamentos) en Cali. Santiago y Lina, dos vendedores de la empresa anterior aceptaron trabajar en la nueva compaña. En la actualidad ocho agentes de bienes raíces colaboran con ella en C&A.
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.
Se importa del paquete MODELOS la base de datos vivienda, realizando primero la instalación de librerías:
Cargue de la base de datos:
data("vivienda")
vivienda
## # A tibble: 8,322 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona … <NA> 3 250 70 1 3 6
## 2 1169 Zona … <NA> 3 320 120 1 2 3
## 3 1350 Zona … <NA> 3 350 220 2 2 4
## 4 5992 Zona … 02 4 400 280 3 5 3
## 5 1212 Zona … 01 5 260 90 1 2 3
## 6 1724 Zona … 01 5 240 87 1 3 3
## 7 2326 Zona … 01 4 220 52 2 2 3
## 8 4386 Zona … 01 5 310 137 2 3 4
## 9 1209 Zona … 02 5 320 150 2 4 6
## 10 1592 Zona … 02 5 780 380 2 3 3
## # ℹ 8,312 more rows
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
Se filtran en una base aparte los inmuebles de tipo Casa, que pertenecen a la Zona Norte de la ciudad y se muestran gráficamente.
conflicts_prefer(mice::filter)
## [conflicted] Will prefer mice::filter over any other package.
base1 <- filter(vivienda, tipo == "Casa", zona == "Zona Norte")
head(base1,3)
## # A tibble: 3 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1209 Zona N… 02 5 320 150 2 4 6
## 2 1592 Zona N… 02 5 780 380 2 3 3
## 3 4057 Zona N… 02 6 750 445 NA 7 6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
print(paste("El numero casas en la zona norte de la ciudad de Cali es de:", nrow(base1)))
## [1] "El numero casas en la zona norte de la ciudad de Cali es de: 722"
base2 <- na.omit(base1)
mapa_casas = leaflet() %>% addCircleMarkers(lng = base2$longitud,
lat = base2$latitud,
radius = 0.1,
color = "purple",
label = base1$id) %>% addTiles()
mapa_casas
Sobre la base anterior utilizada para extraer la información de Casas de la Zona Norte, se realiza un análisis exploratorio sobre la variable respuesta PRECIO, en función de las variables área construida, estrato, numero de baños, numero de habitaciones y zona donde se ubica la vivienda.
Sobre esta variable se evidencia que la mayoría de las casas de la Zona Norte tienen un precio menor a 1000 millones y no cuenta con una distribución normal.
Según el histograma, se evidencian inmuebles con habitaciones = 0, lo cual en el mundo real y práctico es un error, por tanto se toma la decisión de eliminar estos registros de la base al no representar un gran volumen.
base1=base1[base1$habitaciones!=0,]
summary(base1$habitaciones)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 3.000 4.000 4.635 5.000 10.000
Según el histograma, se evidencian inmuebles con baños = 0, lo cual en el mundo real y práctico es un error, por tanto se toma la decisión de eliminar estos registros de la base al no representar un gran volumen.
base1=base1[base1$banios!=0,]
summary(base1$banios)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.0 2.0 3.0 3.6 4.0 10.0
Para la Zona Norte y el inmueble Casa, la mayoría de inmuebles se encuentran concentrados en el estrato 5, siendo este el que tiene a su vez los mayores precios.
hist(base1$estrato)
Para esta varaible se encuentra que el valor mínimo de área es de 30 y el máximo de 1440 metros cuadrados. Adicional, la mayoría de los registros se encuentran desplazados hacia la izquierda con valores menores a los 600 metros cuadrados.
hist(base1$areaconst)
summary(base1$areaconst)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 30.0 140.0 240.0 262.1 336.0 1440.0
Adicional a las variables solicitadas para analizar, se identifica que se tienen registros vacíos en la variable parqueadero, por tanto se utiliza el método de imputación por 0, asumiendo que los inmuebles que tienen este campo vacío es porque no cuentan con esta característica.
base1$parqueaderos <- ifelse(is.na(base1$parqueaderos), 0, base1$parqueaderos)
Sobre la correlacción de las variables en función del precio, podemos concluir lo siguiente:
Precio vs. Área construida: Existe una fuerte correlación positiva entre el precio y el área construida. Esto significa que, a medida que aumenta el área construida, el precio también tiende a aumentar. Por cada unidad que aumenta el área construida, el precio se incrementa en un 73%.
Precio vs. Baños: Hay una correlación positiva moderada entre el precio y la cantidad de baños. Al aumentar la cantidad de baños, el precio también suele aumentar, pero en menor medida que con el área construida. Por cada baño adicional, el precio aumenta en un 56.8%.
Preciom vs. Habitaciones: Existe una correlación positiva débil entre el precio por metro cuadrado y la cantidad de habitaciones. A medida que aumenta la cantidad de habitaciones, el precio por metro cuadrado también tiende a aumentar, pero la relación es menos evidente que en los casos anteriores. Por cada habitación adicional, el precio por metro cuadrado aumenta en un 37.5%.
#install.packages("plotly")
library(plotly)
cor_1=base1[,c("preciom","areaconst","banios","habitaciones")]
gcor<-ggplotly(ggpairs(cor_1))
## Warning: Can only have one: highlight
## Warning: Can only have one: highlight
## Warning: Can only have one: highlight
gcor
Teniendo en cuenta el análisis anterior, se realiza la estimación de un modelo de Regresión Lineal Múltiple (MRLM), es decir, un modelo para predecir el preciom en función de:
precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños )
# se define el modelo ingenuo y= b0
modelo_b0<- lm(preciom ~ 1, data=base1)
#define model with all predictors
modelo_all <- lm(preciom ~ habitaciones + banios + areaconst + estrato + parqueaderos, data = base1)
# Se aplica el proceso forward stepwise regression
forward <- step(modelo_b0, direction='forward', scope=formula(modelo_all), trace=0)
# Visualización de los resultados
forward$anova
## Step Df Deviance Resid. Df Resid. Dev AIC
## 1 NA NA 699 50116309 7827.144
## 2 + areaconst -1 26740934 698 23375376 7295.279
## 3 + estrato -1 4897283 697 18478093 7132.711
## 4 + banios -1 1117457 696 17360636 7091.045
summary(forward)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios, data = base1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -920.79 -77.09 -17.72 50.67 1087.00
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -235.96994 26.91083 -8.769 < 2e-16 ***
## areaconst 0.79428 0.04404 18.034 < 2e-16 ***
## estrato 83.83950 7.08694 11.830 < 2e-16 ***
## banios 32.87174 4.91118 6.693 4.49e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 157.9 on 696 degrees of freedom
## Multiple R-squared: 0.6536, Adjusted R-squared: 0.6521
## F-statistic: 437.7 on 3 and 696 DF, p-value: < 2.2e-16
La fórmula final del modelo es la siguiente:
Preciom=-235.96994 + 0.79428 * areaconst + 83.83950 * estrato + 32.87174 * banios + 157.9.
Adicionalmente, el R^2 de este modelo es 0.6536 y el R^2 ajustado es 0.6521, siendo el preciom explicado en un 65,21% aproximadamente por el modelo calculado anteriormente.
par(mfrow = c(2, 2))
plot(forward)
El valor p es menor que 0.05 por lo que no podemos aceptar Ho y nos sugiere que los residuos no se comportan de forma normal. En este caso sería necesario realizar transformación de las variables que pueden estar causando el problema de normalidad en los residuos, también se podría optar por usar otras variables que no generen este problema.
e= forward$residuals
shapiro.test(e)
##
## Shapiro-Wilk normality test
##
## data: e
## W = 0.8358, p-value < 2.2e-16
los valores de FIV son relativamente bajos, lo que sugiere que no hay una multicolinealidad preocupante en el modelo. Además, el valor de FIV para “estrato” es ligeramente superior al de las otras variables, pero sigue estando por debajo del umbral de preocupación. Por lo tanto, podemos decir que el modelo no tiene problemas significativos de multicolinealidad.
library(car)
## Loading required package: carData
vif(forward)
## areaconst estrato banios
## 1.508688 1.365943 1.456262
A continuación, con el modelo identificado se va a predecir el precio de la vivienda con las características de la primera solicitud.
print("Tipo: Casa")
## [1] "Tipo: Casa"
print("Área construida: 200")
## [1] "Área construida: 200"
print("Parqueaderos: 1")
## [1] "Parqueaderos: 1"
print("Baños: 2")
## [1] "Baños: 2"
print("Habitaciones: 4")
## [1] "Habitaciones: 4"
print("Estrato: 4 o 5")
## [1] "Estrato: 4 o 5"
print("Zona: Norte")
## [1] "Zona: Norte"
print("Crédito preaprobado: 350MM")
## [1] "Crédito preaprobado: 350MM"
casa_1<-data.frame(areaconst=200,estrato=4,banios=2,habitaciones=4)
casa_2<-data.frame(areaconst=200,estrato=5,banios=2,habitaciones=4)
Precio_1<-predict(forward,data.frame(casa_1),type="response")
Precio_2<-predict(forward,data.frame(casa_2),type="response")
print(paste("Precio de la casa de estrato 4: ", as.character(Precio_1),"MM"))
## [1] "Precio de la casa de estrato 4: 323.986891601572 MM"
print(paste("Precio de la casa de estrato 5: ", as.character(Precio_2),"MM"))
## [1] "Precio de la casa de estrato 5: 407.826394036139 MM"
De acuerdo con el resultado anterior, la mejor opción para este escenario es un inmueble estrato 4, ya que al cambiar de estrato es mayor el precio.
Se determinan las ofertas ideales de acuerdo con la información del punto anterior.
oferta1<-filter(base1, areaconst>="200" & areaconst<="280" & estrato==4 & habitaciones=="4" & banios=="2")
oferta2<-filter(base1, areaconst>="200" & areaconst<="280" & estrato==5 & habitaciones=="4" & banios=="2")
ofertas<-rbind(oferta1,oferta2)
ofertas
## # A tibble: 7 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1222 Zona N… 02 4 360 216 2 2 4
## 2 1821 Zona N… <NA> 4 550 265 0 2 4
## 3 1191 Zona N… <NA> 5 405 280 0 2 4
## 4 3121 Zona N… 02 5 580 247 3 2 4
## 5 1163 Zona N… <NA> 5 350 216 2 2 4
## 6 58 Zona N… <NA> 5 400 212 0 2 4
## 7 4555 Zona N… <NA> 5 550 200 3 2 4
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
En este caso en el mapa podemos visualizar de color rojo la ubicación de la casa que mejor se adapta a las condiciones requeridas por el cliente.
# Convertir la variable "base" en una variable de tipo carácter
ofertas$id <- as.character(ofertas$id)
# Asignar colores a cada nivel de la variable categórica, incluyendo un color para cuando "preciom" = 350
colores <- ifelse(ofertas$preciom == 350, "red",
colorFactor(palette = c("purple", "blue", "green"), domain = ofertas$id)(ofertas$id))
# Crear un mapa con las viviendas marcadas por su latitud y longitud y con el color dictado por la variable "base"
mapa <- leaflet(ofertas) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitud, lat = ~latitud, color = ~colores, radius = 4)
# Mostrar el mapa
mapa
Se realiza el mismo ejercicio anterior para un inmueble con las siguientes condiciones:
print("Tipo: Apartamento")
## [1] "Tipo: Apartamento"
print("Área construida: 300")
## [1] "Área construida: 300"
print("Parqueaderos: 3")
## [1] "Parqueaderos: 3"
print("Baños: 3")
## [1] "Baños: 3"
print("Habitaciones: 5")
## [1] "Habitaciones: 5"
print("Estrato: 5 o 6")
## [1] "Estrato: 5 o 6"
print("Zona: Sur")
## [1] "Zona: Sur"
print("Crédito preaprobado: 850MM")
## [1] "Crédito preaprobado: 850MM"
conflicts_prefer(mice::filter)
## [conflicted] Removing existing preference.
## [conflicted] Will prefer mice::filter over any other package.
baseAptos <- filter(vivienda, tipo == "Apartamento", zona == "Zona Sur")
head(baseAptos,3)
## # A tibble: 3 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 5098 Zona S… 05 4 290 96 1 2 3
## 2 698 Zona S… 02 3 78 40 1 1 2
## 3 8199 Zona S… <NA> 6 875 194 2 5 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
base4 <- na.omit(baseAptos)
mapa_aptos = leaflet() %>% addCircleMarkers(lng = base4$longitud,
lat = base4$latitud,
radius = 0.1,
color = "purple",
label = base4$id) %>% addTiles()
mapa_aptos
#install.packages("plotly")
#library(plotly)
baseAptos=baseAptos[baseAptos$habitaciones!=0,]
summary(baseAptos$habitaciones)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 3.000 3.000 2.974 3.000 6.000
baseAptos$parqueaderos <- ifelse(is.na(baseAptos$parqueaderos), 0, baseAptos$parqueaderos)
cor_1=baseAptos[,c("preciom","areaconst","banios","habitaciones")]
gcoraptos<-ggplotly(ggpairs(cor_1))
## Warning: Can only have one: highlight
## Warning: Can only have one: highlight
## Warning: Can only have one: highlight
gcoraptos
# se define el modelo ingenuo y= b0
modeloApto_b0<- lm(preciom ~ 1, data=baseAptos)
#define model with all predictors
modeloAptos_all <- lm(preciom ~ habitaciones + banios + areaconst + estrato + parqueaderos, data = baseAptos)
# Se aplica el proceso forward stepwise regression
forwardAptos <- step(modeloApto_b0, direction='forward', scope=formula(modeloAptos_all), trace=0)
# Visualización de los resultados
forwardAptos$anova
## Step Df Deviance Resid. Df Resid. Dev AIC
## 1 NA NA 2778 101632009 29201.02
## 2 + areaconst -1 58226232.6 2777 43405777 26838.74
## 3 + estrato -1 12588704.0 2776 30817073 25888.86
## 4 + parqueaderos -1 3355315.9 2775 27461757 25570.52
## 5 + banios -1 1898289.5 2774 25563467 25373.46
## 6 + habitaciones -1 394130.2 2773 25169337 25332.28
apto_1<-data.frame(areaconst=300,estrato=5,banios=3,habitaciones=5,parqueaderos=3)
apto_2<-data.frame(areaconst=300,estrato=6,banios=3,habitaciones=5,parqueaderos=3)
PrecioApto_1<-predict(forwardAptos,data.frame(apto_1),type="response")
PrecioApto_2<-predict(forwardAptos,data.frame(apto_2),type="response")
print(paste("Precio del apartamento de estrato 5: ", as.character(PrecioApto_1),"MM"))
## [1] "Precio del apartamento de estrato 5: 678.690762952779 MM"
print(paste("Precio del apartamento de estrato 6: ", as.character(PrecioApto_2),"MM"))
## [1] "Precio del apartamento de estrato 6: 735.572729942884 MM"