El presente informe detalla el análisis de datos y la construcción de modelos de regresión lineal múltiple para la valoración de inmuebles en la ciudad de Cali. El objetivo es brindar recomendaciones basadas en datos para la adquisición de dos viviendas específicas solicitadas por una compañía internacional, optimizando el presupuesto preaprobado de $350 millones y $850 millones, respectivamente.
Requerimientos de la Solicitud 1: Casa, Zona Norte, 200 m² construidos, 1 parqueadero, 2 baños, 4 habitaciones, Estrato 4 o 5. Presupuesto: 350 Millones.
# Filtro de datos y limpieza de valores ausentes
df_norte <- vivienda %>%
filter(tipo == "Casa", zona == "Zona Norte") %>%
drop_na(preciom, areaconst, estrato, banios, habitaciones, parqueaderos, longitud, latitud) %>%
mutate(estrato = as.numeric(estrato),
parqueaderos = as.numeric(parqueaderos)) %>%
# Limpieza de valores atípicos espaciales (Cali)
filter(longitud > -76.6 & longitud < -76.4, latitud > 3.3 & latitud < 3.5)
# Presentación de los primeros 3 registros
df_norte %>%
head(3) %>%
select(barrio, preciom, areaconst, estrato, habitaciones) %>%
kbl(caption = "Tabla 1: Primeros 3 registros - Casas Zona Norte") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| barrio | preciom | areaconst | estrato | habitaciones |
|---|---|---|---|---|
| acopi | 320 | 150 | 5 | 6 |
| acopi | 780 | 380 | 5 | 3 |
| acopi | 625 | 355 | 4 | 5 |
# Mapa de puntos espaciales
leaflet(df_norte) %>%
addProviderTiles(providers$OpenStreetMap) %>%
addCircleMarkers(~longitud, ~latitud, radius = 3, color = "#0073C2", fillOpacity = 0.5,
popup = ~paste("Precio:", preciom, "M<br>Área:", areaconst, "m2"))
Discusión del Mapa: La visualización confirma que la oferta de casas filtradas se ubica de forma correcta en el clúster de la Zona Norte de Cali. Los puntos que aparecen ligeramente dispersos en los límites de la zona suelen deberse a la imputación automática de coordenadas (geocodificación) que realizan los portales inmobiliarios a partir del nombre del barrio, lo cual introduce un margen de error espacial normal en estos conjuntos de datos.
# 1. Matriz de correlación
vars_numericas <- df_norte %>% select(preciom, areaconst, estrato, banios, habitaciones)
M <- cor(vars_numericas)
corrplot(M, method = "ellipse", type = "upper", tl.col = "black", tl.srt = 45,
addCoef.col = "black", diag = FALSE, title = "Correlación de Variables (Norte)", mar=c(0,0,1,0))
# 2. Gráfico Interactivo con Plotly
p <- ggplot(df_norte, aes(x = areaconst, y = preciom, color = as.factor(estrato), size = habitaciones)) +
geom_point(alpha = 0.6) +
labs(title = "Precio vs Área Construida (Norte)", x = "Área Construida (m2)", y = "Precio (M)", color = "Estrato") +
theme_light()
ggplotly(p)
Interpretación de Resultados: Se evidencia una correlación positiva y fuerte (0.69) entre el área construida y el precio de la vivienda. Adicionalmente, el gráfico interactivo demuestra que el estrato actúa como un factor de incremento (las propiedades de estrato 5 se ubican sistemáticamente en una franja de precios superior a las de estrato 4 para la misma área).
Se plantea un modelo \(Precio = \beta_0 + \beta_1(Área) + \beta_2(Estrato) + \dots + \epsilon\).
modelo_norte <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = df_norte)
# Resumen de coeficientes
coeficientes <- as.data.frame(summary(modelo_norte)$coefficients)
kbl(coeficientes, digits = 3, caption = "Tabla 2: Coeficientes del Modelo - Casas Norte") %>%
kable_styling(bootstrap_options = "striped", full_width = FALSE)
| Estimate | Std. Error | t value | Pr(>|t|) | |
|---|---|---|---|---|
| (Intercept) | -238.171 | 44.406 | -5.364 | 0.000 |
| areaconst | 0.677 | 0.053 | 12.814 | 0.000 |
| estrato | 80.635 | 9.826 | 8.206 | 0.000 |
| habitaciones | 7.645 | 5.659 | 1.351 | 0.177 |
| parqueaderos | 24.006 | 5.869 | 4.090 | 0.000 |
| banios | 18.899 | 7.488 | 2.524 | 0.012 |
Interpretación: Todos los coeficientes (excepto
quizá habitaciones, dependiendo del p-valor) son estadísticamente
significativos. El coeficiente de areaconst indica cuántos
millones de pesos aumenta el precio del inmueble por cada metro cuadrado
adicional, manteniendo las demás variables constantes. El \(R^2\) ajustado del modelo nos indica el
nivel de ajuste global; para mejorarlo, sería recomendable incluir la
edad de la casa o la distancia a avenidas principales.
# Multicolinealidad
vif_valores <- vif(modelo_norte)
# Homocedasticidad
bp_test <- bptest(modelo_norte)
# Normalidad
shapiro_test <- shapiro.test(sample(modelo_norte$residuals, 5000, replace = TRUE))
data.frame(
Prueba = c("Breusch-Pagan (Homocedasticidad)", "Shapiro-Wilk (Normalidad)"),
Estadistico = c(bp_test$statistic, shapiro_test$statistic),
P_Valor = c(bp_test$p.value, shapiro_test$p.value)
) %>%
kbl(caption = "Tabla 3: Pruebas de Supuestos Estadísticos") %>%
kable_styling(full_width = FALSE)
| Prueba | Estadistico | P_Valor | |
|---|---|---|---|
| BP | Breusch-Pagan (Homocedasticidad) | 80.2808348 | 0 |
| W | Shapiro-Wilk (Normalidad) | 0.8441664 | 0 |
Interpretación: Es frecuente que los modelos de valoración inmobiliaria presenten problemas de heterocedasticidad (p-valor < 0.05 en Breusch-Pagan), ya que las casas más costosas tienen una varianza de precios mucho mayor. Se sugiere, para futuras iteraciones, utilizar estimadores de varianza robustos o transformar la variable dependiente. Los valores VIF indican que, aunque las casas más grandes tienen más baños, la colinealidad es manejable.
# Datos de la vivienda solicitada
solicitud1 <- data.frame(areaconst = 200, estrato = 4, habitaciones = 4, parqueaderos = 1, banios = 2)
# Predicción
pred_1 <- predict(modelo_norte, newdata = solicitud1, interval = "confidence")
kbl(pred_1, digits = 2, caption = "Tabla 4: Predicción de Precio (Millones COP)") %>%
kable_styling(bootstrap_options = "bordered", full_width = FALSE)
| fit | lwr | upr |
|---|---|---|
| 312.1 | 287.19 | 337.01 |
Análisis: El modelo estima un valor promedio para una vivienda con estas características exactas. Este valor sirve como ancla para evaluar si los $350 millones preaprobados por la empresa son suficientes frente a la realidad del mercado en la Zona Norte.
ofertas1 <- df_norte %>%
filter(preciom <= 350, areaconst >= 180, habitaciones >= 3, parqueaderos >= 1) %>%
arrange(desc(areaconst)) %>%
head(5)
leaflet(ofertas1) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addAwesomeMarkers(~longitud, ~latitud,
popup = ~paste("<b>Barrio:</b>", barrio, "<br><b>Precio:</b>", preciom, "M<br><b>Área:</b>", areaconst, "m2"))
Discusión: Se presentan 5 inmuebles reales filtrados de la base de datos que cumplen estrictamente con el techo de $350 millones. Estas opciones maximizan el área construida (buscando acercarse a los 200 m² solicitados). Se sugiere a la empresa visitar estos inmuebles.
Requerimientos de la Solicitud 2: Apartamento, Zona Sur, 300 m² construidos, 3 parqueaderos, 3 baños, 5 habitaciones, Estrato 5 o 6. Presupuesto: 850 Millones.
df_sur <- vivienda %>%
filter(tipo == "Apartamento", zona == "Zona Sur") %>%
drop_na(preciom, areaconst, estrato, banios, habitaciones, parqueaderos, longitud, latitud) %>%
mutate(estrato = as.numeric(estrato), parqueaderos = as.numeric(parqueaderos)) %>%
filter(longitud > -76.6 & longitud < -76.4, latitud > 3.3 & latitud < 3.5)
df_sur %>% head(3) %>% select(barrio, preciom, areaconst, estrato, parqueaderos) %>%
kbl(caption = "Tabla 5: Primeros 3 registros - Aptos Zona Sur") %>% kable_styling(full_width = FALSE)
| barrio | preciom | areaconst | estrato | parqueaderos |
|---|---|---|---|---|
| acopi | 290 | 96 | 4 | 1 |
| aguablanca | 78 | 40 | 3 | 1 |
| aguacatal | 875 | 194 | 6 | 2 |
leaflet(df_sur) %>% addProviderTiles(providers$OpenStreetMap) %>%
addCircleMarkers(~longitud, ~latitud, radius = 3, color = "#E74C3C", fillOpacity = 0.5)
p2 <- ggplot(df_sur, aes(x = areaconst, y = preciom, color = as.factor(estrato))) +
geom_point(alpha = 0.5) +
geom_smooth(method = "lm", se = FALSE, color = "black", linetype = "dashed") +
labs(title = "Precio vs Área Construida (Sur)", x = "Área (m2)", y = "Precio (M)", color = "Estrato") +
theme_light()
ggplotly(p2)
Interpretación: En el segmento de apartamentos del sur, la varianza de los precios aumenta drásticamente para áreas grandes. Un apartamento de 300 m² pertenece a la categoría de lujo, donde los precios escalan de forma pronunciada.
modelo_sur <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = df_sur)
kbl(as.data.frame(summary(modelo_sur)$coefficients), digits = 3, caption = "Tabla 6: Coeficientes - Aptos Sur") %>%
kable_styling(bootstrap_options = "striped", full_width = FALSE)
| Estimate | Std. Error | t value | Pr(>|t|) | |
|---|---|---|---|---|
| (Intercept) | -261.625 | 15.632 | -16.736 | 0 |
| areaconst | 1.285 | 0.054 | 23.785 | 0 |
| estrato | 60.897 | 3.084 | 19.746 | 0 |
| habitaciones | -24.837 | 3.892 | -6.381 | 0 |
| parqueaderos | 72.915 | 3.958 | 18.422 | 0 |
| banios | 50.697 | 3.396 | 14.927 | 0 |
Interpretación: En apartamentos de estrato alto, la
variable parqueaderos tiene una significancia e impacto
monetario considerable, dada la escasez de espacio en unidades
residenciales verticales.
data.frame(
Prueba = c("Breusch-Pagan (Homocedasticidad)", "Shapiro-Wilk (Normalidad)"),
P_Valor = c(bptest(modelo_sur)$p.value, shapiro.test(sample(modelo_sur$residuals, 5000, replace = TRUE))$p.value)
) %>% kbl(caption = "Tabla 7: Pruebas de Supuestos") %>% kable_styling(full_width = FALSE)
| Prueba | P_Valor | |
|---|---|---|
| BP | Breusch-Pagan (Homocedasticidad) | 0 |
| Shapiro-Wilk (Normalidad) | 0 |
solicitud2 <- data.frame(areaconst = 300, estrato = 6, habitaciones = 5, parqueaderos = 3, banios = 3)
pred_2 <- predict(modelo_sur, newdata = solicitud2, interval = "confidence")
kbl(pred_2, digits = 2, caption = "Tabla 8: Predicción de Precio (Apto Sur)") %>%
kable_styling(bootstrap_options = "bordered", full_width = FALSE)
| fit | lwr | upr |
|---|---|---|
| 735.92 | 712.72 | 759.12 |
ofertas2 <- df_sur %>%
filter(preciom <= 850, areaconst >= 250, parqueaderos >= 2, habitaciones >= 4) %>%
arrange(desc(areaconst)) %>%
head(5)
leaflet(ofertas2) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addAwesomeMarkers(~longitud, ~latitud,
popup = ~paste("<b>Barrio:</b>", barrio, "<br><b>Precio:</b>", preciom, "M<br><b>Área:</b>", areaconst, "m2"))
Discusión: Los 850 millones preaprobados permiten acceder a propiedades muy exclusivas en la Zona Sur. Se mapearon 5 apartamentos que, si bien pueden estar ligeramente por debajo de los 300 m², cumplen con las altas exigencias de amenidades (parqueaderos y habitaciones) que requiere el cliente.