1. Carga y depuración de base de datos

La información suministrada abarca detalles sobre los inmuebles en una zona específica de Cali, incluyendo el nivel en el que están ubicados, su estrato socio económico, el valor en millones de pesos, el área total construida, la cantidad de parqueaderos, baños y habitaciones, el tipo de inmueble, el barrio donde se localiza y sus coordenadas geográficas de longitud y latitud.

data("vivienda")

vivienda<-as.data.frame(vivienda[,-1])
vivienda$zona<-as.factor(vivienda$zona)
vivienda$piso<-as.factor(vivienda$piso)
vivienda$tipo<-as.factor(vivienda$tipo)
vivienda$barrio<-as.factor(vivienda$barrio)
kable(head(vivienda,3), format = "html") %>%
  kable_styling(position = "center")
zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
Zona Oriente NA 3 250 70 1 3 6 Casa 20 de julio -76.51168 3.43382
Zona Oriente NA 3 320 120 1 2 3 Casa 20 de julio -76.51237 3.43369
Zona Oriente NA 3 350 220 2 2 4 Casa 20 de julio -76.51537 3.43566
tabla<-round(as.data.frame(apply(vivienda[,-c(1,2,8,9,10,11)],2,summary)),2)

kable(tabla, format = "html") %>%
  kable_styling(position = "center")
estrato preciom areaconst parqueaderos banios latitud
Min. 3.00 58.00 30.00 1.00 0.00 3.33
1st Qu. 4.00 220.00 80.00 1.00 2.00 3.38
Median 5.00 330.00 123.00 2.00 3.00 3.42
Mean 4.63 433.89 174.93 1.84 3.11 3.42
3rd Qu. 5.00 540.00 229.00 2.00 4.00 3.45
Max. 6.00 1999.00 1745.00 10.00 10.00 3.50
NA’s 3.00 2.00 3.00 1605.00 3.00 3.00
summary(vivienda[,c(1,2,8,9)])
##            zona           piso       habitaciones             tipo     
##  Zona Centro : 124   02     :1450   Min.   : 0.000   Apartamento:5100  
##  Zona Norte  :1920   03     :1097   1st Qu.: 3.000   Casa       :3219  
##  Zona Oeste  :1198   01     : 860   Median : 3.000   NA's       :   3  
##  Zona Oriente: 351   04     : 607   Mean   : 3.605                     
##  Zona Sur    :4726   05     : 567   3rd Qu.: 4.000                     
##  NA's        :   3   (Other):1103   Max.   :10.000                     
##                      NA's   :2638   NA's   :3

La base de datos contiene información de 8,322 viviendas, pero algunas variables tienen datos faltantes. La información sobre el “piso” no está disponible en 2,638 filas, y la de “parqueaderos” en 1,605. En el analisis no se contempla usar la variable piso, entonces no es necesario imputar. En cambio, los valores faltantes en “parqueaderos” se rellenan con 0, asumiendo que la vivienda no tiene parqueadero propio. Adicional a esto hay 3 filas que no contienen datos casi en todas las variables, por lo cual estas se eliminan.

## se elimina variable piso
vivienda<-vivienda[,-c(2)]

## Imputar parqueaderos NA=0

vivienda$parqueaderos[is.na(vivienda$parqueaderos)]=0

## quitar na
vivienda2<-na.omit(vivienda)

2. Casas Zona Norte

Para visualizar las ubicaciones de las viviendas en un mapa, se utiliza un archivo shapefile con los límites de las comunas de Cali. Primero, se carga este archivo y luego se filtran las viviendas ubicadas en la zona norte de la ciudad. Las coordeneadas de la zona norte son traficadas.

## casas zona norte

casas_norte<-vivienda2[vivienda2$zona=="Zona Norte" & vivienda2$tipo=="Casa",]


kable(head(casas_norte,3), format = "html") %>%
  kable_styling(position = "center")
zona estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
9 Zona Norte 5 320 150 2 4 6 Casa acopi -76.51341 3.47968
10 Zona Norte 5 780 380 2 3 3 Casa acopi -76.51674 3.48721
11 Zona Norte 6 750 445 0 7 6 Casa acopi -76.52950 3.38527
## Mapa de Cali con comunas

comunas <- readOGR("Comunas/comunas.shp")
## OGR data source with driver: ESRI Shapefile 
## Source: "C:\Users\ALEJI\Desktop\Comunas\comunas.shp", layer: "comunas"
## with 22 features
## It has 5 fields
## Integer64 fields read as strings:  OBJECTID
leaflet() %>%
  addProviderTiles("CartoDB.Positron") %>%  # Fondo del mapa
  addPolygons(data = comunas, color = "black", weight = 1, fillOpacity = 0) %>% 
  addCircleMarkers(
    lng = casas_norte$longitud, lat = casas_norte$latitud, 
    radius = 3, color = "blue", fillOpacity = 1
  )

Al analizar los datos, se identificó que algunas viviendas estaban localizadas fuera de la zona norte. Para corregir esto, se compararon las coordenadas de las viviendas con el mapa de comunas, considerando como parte de la zona norte las comunas 2, 4, 5 y 6. Luego, se verificó esta clasificación cruzándola con la variable barrio mediante una tabla de contingencia, lo que permitió detectar posibles inconsistencias en la ubicación.

points <- SpatialPointsDataFrame(coords = casas_norte[,c("longitud","latitud")],
                                 data = casas_norte,
                                 proj4string = CRS(proj4string(comunas)))
cruce <- over(points, comunas)

casas_norte$comuna<- cruce$COMUNA

casas_norte$clasif<- ifelse(casas_norte$comuna%in%c(2,4,5,6),"Bien","Mal")

t<-head(casas_norte %>% group_by(barrio) %>% summarise(Bien=sum(clasif=="Bien"),Mal=sum(clasif=="Mal"))%>%
        arrange(desc(Mal)))


kable(t, format = "html") %>%
  kable_styling(position = "center")
barrio Bien Mal
acopi 11 59
la flora 82 17
Cali 0 13
prados del norte 23 8
san vicente 23 8
villa del prado 33 7

El barrio Acopi presentó la mayor cantidad de viviendas con ubicaciones incorrectas. Esto podría deberse a que algunas direcciones pertenecen al municipio de Yumbo, pero durante el proceso de geocodificación se interpretaron como si estuvieran en Cali, generando errores en su localización. En general se puede decir que el error de ubicaciones con respecto a latitud, longitud es debido a la geocodificación de direcciones, esto no necesariamente indica que la vivienda no pertenezca a la zona norte, por lo tanto los datos con ubicación errónea no se excluyen del análisis.

3. Relación entre variables

# Matriz de correlación


matriz_correlacion <- cor(casas_norte[,c("preciom", "areaconst", "parqueaderos","estrato", "banios", "habitaciones")])

plot_ly(
  z = matriz_correlacion, 
  x = colnames(matriz_correlacion), 
  y = colnames(matriz_correlacion),
  type = "heatmap", 
  colorscale = "Plasma",
  zmin = -1, 
  zmax = 1, 
  reversescale = TRUE,
  text = round(matriz_correlacion, 2),  
  hoverinfo = "text",        
  texttemplate = "%{text}",  
  textfont = list(color = "white")
) %>% layout(
    title = "Matriz de correlacion",
    xaxis = list(title = ""),  
    yaxis = list(title = "")  
  ) 

Se observa que el precio de la vivienda tiene una correlación positiva moderada a fuerte con el área construida, la cantidad de parqueaderos, el número de baños y el estrato socioeconómico. En contraste, la relación entre el precio y la cantidad de habitaciones es débil. Además, el estrato muestra una correlación moderada y positiva con los parqueaderos, mientras que su relación con el número de habitaciones es negativa pero débil.

4. Ajuste de modelo de regresión multiple

En esta parte, se construye un modelo de regresión lineal múltiple para estimar el precio de las viviendas en la zona norte de Cali, considerando como variables predictoras el área construida, la cantidad de parqueaderos, el estrato, el número de baños y de habitaciones.

mod=lm(preciom~ areaconst + parqueaderos + estrato + banios + habitaciones, casas_norte)


summary(mod)
## 
## Call:
## lm(formula = preciom ~ areaconst + parqueaderos + estrato + banios + 
##     habitaciones, data = casas_norte)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -964.04  -80.10  -17.08   50.06 1069.45 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -236.47551   30.36582  -7.788 2.40e-14 ***
## areaconst       0.82677    0.04368  18.926  < 2e-16 ***
## parqueaderos   -1.67672    4.31505  -0.389    0.698    
## estrato        86.42579    7.39747  11.683  < 2e-16 ***
## banios         26.97978    5.34384   5.049 5.65e-07 ***
## habitaciones    1.44443    4.16411   0.347    0.729    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 159.1 on 716 degrees of freedom
## Multiple R-squared:  0.6508, Adjusted R-squared:  0.6484 
## F-statistic: 266.9 on 5 and 716 DF,  p-value: < 2.2e-16

Estrategias para mejorar el modelo:
- Agregar nuevas variables: Incluir factores como la ubicación exacta, la antigüedad de la construcción o la calidad de los materiales podría mejorar la precisión del modelo.
- Eliminar variables no significativas: Algunas variables pueden no aportar información relevante y afectar la calidad del modelo, por lo que podrían ser descartadas.
- Transformaciones de variables: Aplicar funciones como logaritmos o raíces cuadradas puede mejorar la relación entre las variables y la variable dependiente, optimizando el ajuste del modelo.

5. Validacion de supuestos

En esta sección se verifican los supuestos del modelo para evaluar su validez.

5.1. Normalidad

Se emplea la prueba de Shapiro-Wilk para analizar si los residuos siguen una distribución normal.

\[ H_0: \text{Los residuos siguen una distribución normal} \]

\[ H_1: \text{Los residuos no siguen una distribución normal} \]

Los resultados arrojan un valor de W = 0.83 y un p-value ≈ 0, lo que indica que los residuos no presentan una distribución normal.

## Validacion de supuestos

res<-mod$residuals
## Normalidad de residuales
shapiro.test(res)
## 
##  Shapiro-Wilk normality test
## 
## data:  res
## W = 0.83823, p-value < 2.2e-16

5.2. Homocedasticidad

Para evaluar si los residuos tienen varianza constante, se aplica la prueba de Breusch-Pagan.

\[ H_0: \text{Los residuos presentan varianza constante (homocedasticidad)} \]

\[ H_1: \text{Los residuos no presentan varianza constante (heterocedasticidad)} \]

Se obtiene un valor de BP = 139 y un p-value ≈ 0, lo que sugiere que los residuos no son homocedásticos.

## Homocedasticidad
bptest(mod)
## 
##  studentized Breusch-Pagan test
## 
## data:  mod
## BP = 139, df = 5, p-value < 2.2e-16

5.3. Indenpendencia

Se utiliza la prueba de Durbin-Watson para examinar si los residuos son independientes. \[ H_0: \text{Los residuos no presentan autocorrelación (independencia)} \]

\[ H_1: \text{Los residuos presentan autocorrelación} \]

En este caso, el resultado muestra un valor de DW = 1.6 y un p-value = 0, lo que indica que los residuos no presentan autocorrelación y, por lo tanto, son independientes entre sí.

## Independecia
dwtest(mod)
## 
##  Durbin-Watson test
## 
## data:  mod
## DW = 1.633, p-value = 3.068e-07
## alternative hypothesis: true autocorrelation is greater than 0

Conclusión: No se cumple ninguno de los supuestos del modelo, una opción en este caso es realizar una transformación de la variable respuesta y evaluar nuevamente el modelo.

6. Predicción valor de la vivienda 1

Se busca estimar el precio de una vivienda con las siguientes características:

Características Vivienda 1
Tipo Casa
Área construida 200
Parqueaderos 1
Baños 2
Habitaciones 4
Estrato 4 o 5
Zona Norte
Crédito preaprobado 350 millones

Para realizar la predicción, se emplea la función predict(). Primero, se construye un dataframe con la información de la vivienda de interés, y luego se usa el modelo ajustado para obtener la estimación del precio.

## Prediccion

new_dat <- data.frame(
  areaconst = 200,
  parqueaderos = 1,
  estrato = c(4, 5),
  banios = 2,
  habitaciones = 4
)


predict(mod,new_dat)
##        1        2 
## 332.6430 419.0688

El modelo ajustado arroja los siguientes valores estimados para una vivienda con las características dadas:

Estos valores permiten evaluar si el precio de venta de la vivienda está dentro del rango esperado según el modelo.

7. Potenciales ofertas

Se identifican las mejores oportunidades analizando las casas con un precio inferior a 350 millones y un residual negativo en la predicción. Esto indica que, según el modelo, estas viviendas tienen un valor estimado superior al precio registrado en la base de datos.

casas_norte$res<-res
casas_norte$pred<-mod$fitted.values

df2=head(casas_norte[casas_norte$preciom<350 & casas_norte$res<=0,]%>% arrange(desc(preciom)),5)



kable(df2[,-c(8,9,10,11,13)], format = "html") %>%
  kable_styling(position = "center")
zona estrato preciom areaconst parqueaderos banios habitaciones comuna res pred
Zona Norte 5 343 170 3 4 4 2 -101.87171 444.8717
Zona Norte 5 342 250 1 4 6 2 -175.25593 517.2559
Zona Norte 5 340 250 2 4 4 2 -172.69035 512.6903
Zona Norte 4 340 162 1 4 4 2 -15.18517 355.1852
Zona Norte 5 340 208 0 6 4 4 -195.27885 535.2788

Las ofertas potenciales son las de las filas 2 y 3. Ubicación espacial de las 5 casas:

leaflet() %>%
  addProviderTiles("CartoDB.Positron") %>%  # Fondo del mapa
  addPolygons(data = comunas, color = "black", weight = 1, fillOpacity = 0) %>%  
  addCircleMarkers(
    lng = df2$longitud, lat = df2$latitud, 
    radius = 3, color = "blue", fillOpacity = 1
  )

8. Mdelo Zona sur para apartamentos

Se realiza la misma metodologia para el caso de apartamentos en zona sur.

## Filtro de apartamentos en Zona sur

apartamentos_sur <- vivienda2[(vivienda2$zona=="Zona Sur" & vivienda2$tipo=="Apartamento"),]

kable(head(apartamentos_sur,3), format = "html") %>%
  kable_styling(position = "center")
zona estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
24 Zona Sur 4 290 96 1 2 3 Apartamento acopi -76.53464 3.44987
164 Zona Sur 3 78 40 1 1 2 Apartamento aguablanca -76.50100 3.40000
264 Zona Sur 6 875 194 2 5 3 Apartamento aguacatal -76.55700 3.45900
leaflet() %>%
  addProviderTiles("CartoDB.Positron") %>%  
  addPolygons(data = comunas, color = "black", weight = 1, fillOpacity = 0) %>% 
  addCircleMarkers(
    lng = apartamentos_sur$longitud, lat = apartamentos_sur$latitud, 
    radius = 3, color = "blue", fillOpacity = 1
  )

Al igual que en el caso anterior, se identificaron puntos mal ubicados. Para validar la ubicación correcta de las viviendas, se realizó una verificación por comunas. Se asume que las comunas correspondientes a la zona sur de Cali son: 10, 16, 17, 18, 19 y 22.

## comunas 10,16,17,18,19,22
points4 <- SpatialPointsDataFrame(coords = apartamentos_sur[,c("longitud","latitud")],
                                 data = apartamentos_sur,
                                 proj4string = CRS(proj4string(comunas)))

cruce <- over(points4, comunas)

apartamentos_sur$comuna<- cruce$COMUNA

apartamentos_sur$clasif<- ifelse(apartamentos_sur$comuna%in%c(10,16,17,18,19,22),"Bien","Mal")

## Por ultimo se contrasta esta clasificacion con los barrios 

t2<-head(apartamentos_sur %>% group_by(barrio) %>% summarise(Bien=sum(clasif=="Bien"),Mal=sum(clasif=="Mal"))%>%
        arrange(desc(Mal)))

kable(t2, format = "html") %>%
  kable_styling(position = "center")
barrio Bien Mal
valle del lili 727 110
pance 177 28
ciudad jardín 202 16
bochalema 18 15
ciudad bochalema 35 13
el caney 112 12

El análisis permitió detectar inconsistencias en la localización de algunas viviendas no acordes a la ubicación de los barrios, como se mencionó anteriormente sugiere posibles errores en el proceso de geocodificación.

8.1 Ajuste modelo de regresión multiple

Se ajusta el modelo de regresión multiple.

## Modelo
mod2=lm(preciom~ areaconst + parqueaderos + estrato + banios + habitaciones, apartamentos_sur)
summary(mod2)
## 
## Call:
## lm(formula = preciom ~ areaconst + parqueaderos + estrato + banios + 
##     habitaciones, data = apartamentos_sur)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1252.31   -42.15    -2.06    36.32   934.06 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -221.04614   13.47771 -16.401  < 2e-16 ***
## areaconst       1.46061    0.04876  29.956  < 2e-16 ***
## parqueaderos   48.36353    3.02343  15.996  < 2e-16 ***
## estrato        57.00608    2.79648  20.385  < 2e-16 ***
## banios         48.60871    3.04050  15.987  < 2e-16 ***
## habitaciones  -22.71789    3.39549  -6.691 2.68e-11 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 95.17 on 2781 degrees of freedom
## Multiple R-squared:  0.7536, Adjusted R-squared:  0.7531 
## F-statistic:  1701 on 5 and 2781 DF,  p-value: < 2.2e-16

El modelo ajustado para los apartamentos en la zona sur muestra los siguientes coeficientes:

Evaluación del Modelo

plot_ly(data = apartamentos_sur, x = ~habitaciones, y = ~preciom, type = "box")

8.2 Validación de supuestos

Validacion de supuestos

A continuación se validan los supuestos del modelo.

8.2.1. Normalidad

Se emplea la prueba de Shapiro-Wilk para analizar si los residuos siguen una distribución normal.

\[ H_0: \text{Los residuos siguen una distribución normal} \]

\[ H_1: \text{Los residuos no siguen una distribución normal} \]

Los resultados arrojan un valor de W = 0.78 y un p-value ≈ 0, lo que indica que los residuos no presentan una distribución normal.

## Validacion de supuestos

res2<-mod2$residuals
## Normalidad de residuales
shapiro.test(res2)
## 
##  Shapiro-Wilk normality test
## 
## data:  res2
## W = 0.78157, p-value < 2.2e-16

8.2.2. Homocedasticidad

Para evaluar si los residuos tienen varianza constante, se aplica la prueba de Breusch-Pagan.

\[ H_0: \text{Los residuos presentan varianza constante (homocedasticidad)} \]

\[ H_1: \text{Los residuos no presentan varianza constante (heterocedasticidad)} \]

Se obtiene un valor de BP = 956 y un p-value ≈ 0, lo que sugiere que los residuos no son homocedásticos.

## Homocedasticidad
bptest(mod2)
## 
##  studentized Breusch-Pagan test
## 
## data:  mod2
## BP = 956.83, df = 5, p-value < 2.2e-16

8.2.3. Indenpendencia

Se utiliza la prueba de Durbin-Watson para examinar si los residuos son independientes. \[ H_0: \text{Los residuos no presentan autocorrelación (independencia)} \]

\[ H_1: \text{Los residuos presentan autocorrelación} \]

En este caso, el resultado muestra un valor de DW = 1.5 y un p-value = 0, lo que indica que los residuos no son independientes y están correlacionados entre sí.

## Independecia
dwtest(mod2)
## 
##  Durbin-Watson test
## 
## data:  mod2
## DW = 1.5041, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0

Conclusión: No se cumple ninguno de los supuestos del modelo, una opción en este caso es realizar una transformación de la variable respuesta y evaluar nuevamente el modelo.

8.3. Predicción valor de la vivienda

Se requiere predecir el valor de una vivienda con las siguientes caracteristicas.

Características Vivienda 2
Tipo Apartamento
Área construida 300
Parqueaderos 3
Baños 3
Habitaciones 5
Estrato 5 o 6
Zona Sur
Crédito preaprobado 850 millones

Mediante la función predict se realiza la predicción, primero declarando un dataframe con los datos sobre la vivienda que se quiere vender.

## Prediccion

new_dat2 <- data.frame(
  areaconst = 300,
  parqueaderos = 3,
  estrato = c(5, 6),
  banios = 3,
  habitaciones = 5
)


predict(mod2,new_dat2)
##        1        2 
## 679.4951 736.5012

El resultado indica que un apartamento con estas caracteristicas de estrato 5 valdria en promedio 679.5 millones de pesos y si es estrato 5 valdría 736.5 millones de pesos.

8.4. Potenciales ofertas

Siguiendo las misma metodologia del modelo anterior se buscan ofertas potenciales para la vivienda solicitada.

apartamentos_sur$res<-res2
apartamentos_sur$pred<-mod2$fitted.values
df4=head(apartamentos_sur[apartamentos_sur$preciom<850 & apartamentos_sur$res<=0,]%>% arrange(desc(preciom)),5)


kable(df4[,-c(8,9,10,11,12,13)], format = "html") %>%
  kable_styling(position = "center")
zona estrato preciom areaconst parqueaderos banios habitaciones res pred
Zona Sur 5 730 573 3 8 5 -591.28574 1321.2857
Zona Sur 6 699 164 4 5 3 -29.87470 728.8747
Zona Sur 5 690 486 2 4 4 -284.13201 974.1320
Zona Sur 5 670 300 3 5 6 -83.99465 753.9947
Zona Sur 6 660 210 4 5 3 -136.06285 796.0628
leaflet() %>%
  addProviderTiles("CartoDB.Positron") %>%  # Fondo del mapa
  addPolygons(data = comunas, color = "black", weight = 1, fillOpacity = 0) %>%  # Comunas en el mapa
  addCircleMarkers(
    lng = df4$longitud, lat = df4$latitud, 
    radius = 3, color = "blue", fillOpacity = 1
  )