1 Objetivo

Asesorar a la empresa C&A para brindarle la mejor opción de negocio a os de sus clienten que solicitan inmuebles con las siguientes características:

Fuente: Actividad 2
Fuente: Actividad 2

2 Limpieza de base de datos

Inicialmente se procede a cargar la base de datos de viviendas en Cali y a limpiarla de información atípica o datos faltantes.

library(paqueteMODELOS)
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>

3 Filtro de zona norte

Se identificó el grupo de viviendas ubicadas en la zona norte de la ciudad de Cali y se obtuvo el siguiente resultado:

library(dplyr)
library(leaflet)
library(knitr)

base1 <- datos_imputados %>%
  filter(tolower(tipo) == "casa" & tolower(zona) == "zona norte")

head(base1, 3) %>% kable(caption = "Primeros 3 registros - Casas Zona Norte")
Primeros 3 registros - Casas Zona Norte
id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
1209 Zona Norte 02 5 320 150 2 4 6 Casa acopi -76.51341 3.47968
1592 Zona Norte 02 5 780 380 2 3 3 Casa acopi -76.51674 3.48721
4057 Zona Norte 02 6 750 445 2 7 6 Casa acopi -76.52950 3.38527
table(base1$tipo, base1$zona) %>% kable(caption = "Comprobación de Tipo vs Zona")
Comprobación de Tipo vs Zona
Zona Norte
Casa 722
leaflet(base1) %>%
  addTiles() %>%
  addCircleMarkers(
    ~longitud, ~latitud,
    popup = ~paste("Precio:", preciom, "M | Área:", areaconst, "m²"),
    radius = 4, color = "red", stroke = FALSE, fillOpacity = 0.7
  )

Al cargar la información en mapa se evidencia que a pesar de tener la clasificación como zona norte no todos los puntos se encuentran al norte de la ciudad. Para corregir esto se filtra según cuatro puntos extremos que pueden clasificarse como zona norte de la ciudad de Cali, lo que esté fuera de esos rangos sale del análisis.

library(leaflet)
library(htmltools)

base1_limpia <- base1 %>%
  filter(
    latitud  >= 3.45 & latitud  <= 3.50,   
    longitud >= -76.55 & longitud <= -76.50 
  )

leaflet(base1_limpia) %>%
  addTiles() %>%
  addCircleMarkers(~longitud, ~latitud, color = "green", radius = 4, fillOpacity = 0.8) %>%
  addControl(
    html = "<h4 style='margin:0; padding:5px; background:white; border-radius:4px;'>Casas Filtradas en Zona Norte</h4>",
    position = "topright"
  )

4 Análisis exploratorio en correlación con variable precio

El análisis de correlación cruzada muestra que la variable con mayor poder explicativo respecto al precio del inmueble (preciom) es el área construida (areaconst), presentando una relación lineal positiva muy marcada. Las variables estrato, banos y parqueaderos también muestran una correlación positiva, mostrando que para el mercado es importante las viviendas amplias y el nivel socioeconómico de la ubicación.

library(plotly)
library(GGally)

vars_num <- base1_limpia %>% 
  select(preciom, areaconst, estrato, banios, habitaciones) %>% 
  na.omit()

p <- ggpairs(vars_num)
ggplotly(p)

El área construida vs precio muestra la correlación más alta, lo que quiere decir que a mayor metraje de la vivienda, mayor valor. Los baños y estrato tienen un impacto positivo considerable sobre el precio. Las habitaciones presenta una relación menos directa con el precio, ya que es más importante el tamaño de la vivienda que el número de habitaciones.

5 Modelo de regresión lineal múltiple

El modelo de regresión lineal múltiple estimado resultó ser significativo (p-valor < 0.05). Los coeficientes asociados a areaconst, estrato, banios y parqueaderos presentaron signos positivos y concuerdan con la teoría económica del mercado inmobiliario, donde cada unidad adicional incrementa el valor promedio de la vivienda en millones de pesos.

modelo_casas <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = base1_limpia)

base1_limpia <- base1_limpia %>%
  mutate(prediccion_precio = predict(modelo_casas, newdata = .))
summary(modelo_casas)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base1_limpia)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -733.92  -81.57  -17.03   44.32  948.84 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -168.13161   47.15908  -3.565 0.000405 ***
## areaconst       0.85873    0.06285  13.662  < 2e-16 ***
## estrato        56.90315   10.49182   5.424 9.88e-08 ***
## habitaciones    8.32179    5.69505   1.461 0.144700    
## parqueaderos   30.95801    6.37798   4.854 1.71e-06 ***
## banios         12.26769    7.26996   1.687 0.092259 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 166 on 420 degrees of freedom
## Multiple R-squared:  0.594,  Adjusted R-squared:  0.5891 
## F-statistic: 122.9 on 5 and 420 DF,  p-value: < 2.2e-16

El coeficiente de determinación (R^2) indica la proporción de la variabilidad del precio explicada por el conjunto de covariables.

6 Validación de supuestos del modelo

Al revisar la fórmula con pruebas detalladas, se evidenció que los precios de las casas tienen saltos muy grandes, algunas son muy baratas y otras muy caras y no se cumple la distribución normal. Esto hace que la fórmula cometa errores más grandes en las casas lujosas que en las normales. Para solucionarlo a futuro, se recomienda calcular los precios usando escalas proporcionales como porcentajes.

library(lmtest)
library(car)

par(mfrow = c(2, 2))
plot(modelo_casas)

par(mfrow = c(1,1))


bptest(modelo_casas)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo_casas
## BP = 61.267, df = 5, p-value = 6.65e-12
shapiro.test(residuals(modelo_casas)[1:5000])
## 
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo_casas)[1:5000]
## W = 0.83535, p-value < 2.2e-16
vif(modelo_casas)
##    areaconst      estrato habitaciones parqueaderos       banios 
##     1.517179     1.288074     1.662416     1.257304     1.865781

7 Predicción del precio de viviendas

Se aplicó la fórmula para calcular cuánto debería costar la casa que pide el primer cliente con su presupuesto máximo de 350 millones, se filtró las 5 mejores opciones reales del mercado que se ajustan a lo que busca y que no se salen de su crédito pre-aprobado.

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

pred_1 <- predict(modelo_casas, newdata = solicitud_1, interval = "confidence")
pred_1
##        fit     lwr      upr
## 1 320.0072 293.559 346.4553

8 Viviendas sugeridas al primer cliente

Se presentan las opciones sugeridas según las indicaciones del primer cliente:

library(dplyr)
library(knitr)

precio_estimado_sol1 <- predict(modelo_casas, newdata = solicitud_1)

ofertas_sol1_especificas <- base1_limpia %>%
  filter(!is.na(preciom)) %>%
  filter(preciom <= 350) %>%
  mutate(
    diferencia_solicitud = abs(preciom - precio_estimado_sol1)
  ) %>%
  arrange(diferencia_solicitud) %>%
  slice_head(n = 5)

leaflet(ofertas_sol1_especificas) %>%
  addTiles() %>%
  addMarkers(
    ~longitud, ~latitud,
    popup = ~paste0("<b>Tipo:</b>", tipo, "<br>",
                    "<b>Área:</b> ", areaconst, " m²<br>",
                    "<b>Parqueaderos:</b>", parqueaderos, "<br>",
                    "<b>Baños:</b>", banios, "<br>",
                    "<b>Habitaciones:</b> ", habitaciones, "<br>",
                    "<b>Estrato:</b>", estrato, "<br>",
                    "<b>Precio:</b> $", preciom, "M<br>")
  )

El modelo encontró casas mucho más grandes, con más parqueaderos y en mejores estratos. Esto confirma que cuando el presupuesto sube, el mercado tiene en cuenta principalmente el espacio extra y la exclusividad de la ubicación.

9 Viviendas sugeridas al segundo cliente

Se presentan las opciones sugeridas según las indicaciones del segundo cliente:

library(dplyr)
library(knitr)
library(leaflet)
library(htmltools)

base2 <- datos_imputados %>%
  filter(tolower(tipo) == "apartamento" & tolower(zona) == "zona sur")

head(base2, 3) %>% kable(caption = "Primeros 3 registros - Apartamentos Zona sur")
Primeros 3 registros - Apartamentos Zona sur
id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
5098 Zona Sur 05 4 290 96 1 2 3 Apartamento acopi -76.53464 3.44987
698 Zona Sur 02 3 78 40 1 1 2 Apartamento aguablanca -76.50100 3.40000
8199 Zona Sur NA 6 875 194 2 5 3 Apartamento aguacatal -76.55700 3.45900
# 3. Tabla de comprobación usando base2
table(base2$tipo, base2$zona) %>% kable(caption = "Comprobación de Tipo vs Zona")
Comprobación de Tipo vs Zona
Zona Sur
Apartamento 2787
# 4. Mapa interactivo de los apartamentos con título
leaflet(base2) %>%
  addTiles() %>%
  addCircleMarkers(
    ~longitud, ~latitud,
    popup = ~paste("<b>Precio:</b> $", preciom, "M<br><b>Área:</b> ", areaconst, " m²"),
    radius = 4, color = "blue", stroke = FALSE, fillOpacity = 0.7
  ) %>%
  addControl(
    html = "<h4 style='margin:0; padding:5px; background:white; border-radius:4px;'>Ubicación de Apartamentos - Zona sur</h4>",
    position = "topright"
  )

Para el caso del segundo cliente sucede lo mismo que en el primer cliente, a pesar de que las viviendas se ecuentren clasificadas como zona sur, no todas pertenecen a esa zona y se realiza el mismo procedimiento de definir unas coordenadas límite en Google maps para delimitar la zona sur, los puntos fuera de esos limites se eliminan.

library(leaflet)
library(htmltools)

base2_limpia <- base2 %>%
  filter(
    latitud  >= 3.30 & latitud  <= 3.39,   
    longitud >= -76.56 & longitud <= -76.50 
  )

leaflet(base2_limpia) %>%
  addTiles() %>%
  addCircleMarkers(~longitud, ~latitud, color = "green", radius = 4, fillOpacity = 0.8) %>%
  addControl(
    html = "<h4 style='margin:0; padding:5px; background:white; border-radius:4px;'>Apartamentos filtrados en Zona sur</h4>",
    position = "topright"
  )
library(plotly)
library(GGally)

vars_num_2 <- base2_limpia %>% 
  select(preciom, areaconst, estrato, banios, habitaciones) %>% 
  na.omit()

p <- ggpairs(vars_num_2)
ggplotly(p)

Para el caso del segundo cliente, se puede evidenciar que coincide con el primer caso en cuanto a que el precio va muy de la mano con el tamaño del inmueble. La segunda correlación fuerte es el número de baños, lo que quiere decir que entre más baños tenga un apartamento, más alto su valor. Depués encontramos que un estrato más alto si influye en el precio, pero no de la misma forma que las variables anteriores. Por último, las habitaciones no son una variable tan fuerte para definir el precio del apartamento.

modelo_apto <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = base2_limpia)

base2_limpia <- base2_limpia %>%
  mutate(prediccion_precio = predict(modelo_apto, newdata = .))
summary(modelo_apto)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base2_limpia)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1244.93   -35.68    -3.21    36.95   869.68 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -270.7806    17.5785 -15.404  < 2e-16 ***
## areaconst       1.4726     0.0654  22.516  < 2e-16 ***
## estrato        50.0588     3.7187  13.461  < 2e-16 ***
## habitaciones  -18.2428     4.6226  -3.946 8.27e-05 ***
## parqueaderos   89.7124     5.4825  16.364  < 2e-16 ***
## banios         52.3223     4.1218  12.694  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 96.26 on 1627 degrees of freedom
## Multiple R-squared:  0.8024, Adjusted R-squared:  0.8018 
## F-statistic:  1321 on 5 and 1627 DF,  p-value: < 2.2e-16

El valor p también es menor a 0.05, igual que con el caso del cliente 1, lo que significa que el conjunto de covariables significativa. También encontramos que todas las variables se encuentra de forma positiva, quiere decir que un aumento en ellas se traduce e un incremento del inmueble, pero en habitaciones, al aumentar el número de habitaciones sin que se incremente el metraje del apartamento puede llegar a disminuir su precio en 18.2 millones de pesos.

library(lmtest)
library(car)

par(mfrow = c(2, 2))
plot(modelo_apto)

par(mfrow = c(1,1))


bptest(modelo_apto)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo_apto
## BP = 667.11, df = 5, p-value < 2.2e-16
shapiro.test(residuals(modelo_apto)[1:5000])
## 
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo_apto)[1:5000]
## W = 0.74687, p-value < 2.2e-16
vif(modelo_apto)
##    areaconst      estrato habitaciones parqueaderos       banios 
##     2.309762     1.772237     1.422627     2.225700     2.776279

Según Shapiro-Wilk se rechaza la hipótesis nula, dado que el valor p está por debajo de 0.05 y se considera que la distribución no es normal como en el caso del cliente 1. Y no existen problemas de multicolinealidad entre las variables predictoras, al encontrarse por debajo del umbral (<5).

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

pred_2 <- predict(modelo_apto, newdata = solicitud_2, interval = "confidence")
pred_2
##        fit      lwr     upr
## 1 756.1842 728.2634 784.105

Según la predicción del precio de las caracteristicas del caso 2, el crédito preaprobado cumple satisfactoriamente con el posible precio del inmueble.

library(dplyr)
library(knitr)

precio_estimado_sol2 <- predict(modelo_apto, newdata = solicitud_2)

ofertas_sol2_especificas <- base2_limpia %>%
  filter(!is.na(preciom)) %>%
  filter(preciom <= 850) %>%
  mutate(
    diferencia_solicitud = abs(preciom - precio_estimado_sol2)
  ) %>%
  arrange(diferencia_solicitud) %>%
  slice_head(n = 5)

leaflet(ofertas_sol2_especificas) %>%
  addTiles() %>%
  addMarkers(
    ~longitud, ~latitud,
    popup = ~paste0("<b>Tipo:</b>", tipo, "<br>",
                    "<b>Área:</b> ", areaconst, " m²<br>",
                    "<b>Parqueaderos:</b>", parqueaderos, "<br>",
                    "<b>Baños:</b>", banios, "<br>",
                    "<b>Habitaciones:</b> ", habitaciones, "<br>",
                    "<b>Estrato:</b>", estrato, "<br>",
                    "<b>Precio:</b> $", preciom, "M<br>")
  )

10 Conclusiones

  • Los datos categóricos no siempre reflejan la realidad espacial. Aunque un registro afirme pertenecer a la “Zona Norte”, el mapeo detallado reveló inconsistencias que requirieron una limpieza técnica basada en coordenadas.

  • El valor de las viviendas en la zona estudiada depende primordialmente del área construida, seguida por el estrato socioeconómico y la disponibilidad de baños y parqueaderos. El número de habitaciones no incrementa el valor, sino que debe estar respaldado por un tamaño en metros cuadrados.

  • Solicitud 1: Con un valor promedio estimado en los 320 millones y un límite de 346.5 millones, la solicitud es 100% viable frente al crédito pre-aprobado de 350 millones. Existe un margen cómodo para cubrir costos adicionales.

  • Solicitud 2: El crédito de 850 millones otorga un amplio poder de negociación en el mercado, permitiendo filtrar propiedades de mayor metraje, más parqueaderos y ubicaciones más exclusivas sin superar la capacidad financiera pre-aprobada.

  • Con los presupuestos de los dos clientes pueden encontrar viviendas según las características que ellos solicitan, así que pueden aceptar los créditos preaprobados para negociar las opciones que se les ha presentado.