Análisis de Viviendas para C&A
Introducción.
C&A, una empresa de bienes raíces en Cali, ha recibido una solicitud de asesoría por parte de una compañía internacional que busca dos viviendas para sus empleados. Para responder a esta solicitud, se realizó un análisis detallado basado en técnicas de modelado estadístico y exploración geoespacial con el objetivo de identificar las opciones más adecuadas dentro del presupuesto establecido.
Este informe presenta:
Análisis exploratorio de las características de las viviendas disponibles en el mercado inmobiliario.
Modelado predictivo para estimar los precios de las viviendas con base en variables clave.
Selección de las mejores opciones en cada zona con base en criterios estratégicos.
Visualización geoespacial de las opciones disponibles.
Conclusiones y recomendaciones finales para la empresa C&A y su cliente.
Metodología del Análisis
Para garantizar una evaluación precisa, se implementaron las siguientes técnicas:
Filtrado de Datos: Se segmentaron las viviendas según el tipo solicitado y la zona de interés. validación de Datos: Se excluyeron registros con información incompleta (NA) en variables clave.
Análisis Exploratorio: Se analizaron correlaciones entre variables como precio, área, estrato y demás características.
Modelado Predictivo: Se construyó un modelo de regresión lineal múltiple para predecir precios.
visualización Geoespacial: Se generaron mapas interactivos para representar la distribución de las viviendas.
Selección Estratégica: Se identificaron todas las opciones viables, un Top 10 de mejores oportunidades, y se establecieron recomendaciones claras para la toma de decisiones.
Carga y exploración de datos.
## rlang (1.1.4 -> 1.1.5 ) [CRAN]
## purrr (1.0.2 -> 1.0.4 ) [CRAN]
## glue (1.7.0 -> 1.8.0 ) [CRAN]
## cli (3.6.3 -> 3.6.4 ) [CRAN]
## Rcpp (1.0.13 -> 1.0.14) [CRAN]
## digest (0.6.36 -> 0.6.37) [CRAN]
## curl (5.2.1 -> 6.2.1 ) [CRAN]
## xfun (0.48 -> 0.51 ) [CRAN]
## lubridate (1.9.3 -> 1.9.4 ) [CRAN]
## knitr (1.48 -> 1.49 ) [CRAN]
## package 'rlang' successfully unpacked and MD5 sums checked
## package 'glue' successfully unpacked and MD5 sums checked
## package 'cli' successfully unpacked and MD5 sums checked
## package 'Rcpp' successfully unpacked and MD5 sums checked
## package 'digest' successfully unpacked and MD5 sums checked
## package 'curl' successfully unpacked and MD5 sums checked
## package 'xfun' successfully unpacked and MD5 sums checked
##
## The downloaded binary packages are in
## C:\Users\Toshiba\AppData\Local\Temp\RtmpaUQOZi\downloaded_packages
## ── R CMD build ─────────────────────────────────────────────────────────────────
## checking for file 'C:\Users\Toshiba\AppData\Local\Temp\RtmpaUQOZi\remotes57fc457d64a3\Centromagis-paqueteMODELOS-3b06257/DESCRIPTION' ... ✔ checking for file 'C:\Users\Toshiba\AppData\Local\Temp\RtmpaUQOZi\remotes57fc457d64a3\Centromagis-paqueteMODELOS-3b06257/DESCRIPTION' (374ms)
## ─ preparing 'paqueteMODELOS': (8.2s)
## checking DESCRIPTION meta-information ... ✔ checking DESCRIPTION meta-information
## ─ checking for LF line-endings in source and make files and shell scripts (422ms)
## ─ checking for empty or unneeded directories
## ─ building 'paqueteMODELOS_0.1.0.tar.gz'
##
##
Convertir Zona a Carácter Para Evitar Problemas de Filtrado.
Estructura y Primeros Registros.
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=
## .. cols(
## .. id = col_double(),
## .. zona = col_character(),
## .. piso = col_character(),
## .. estrato = col_double(),
## .. preciom = col_double(),
## .. areaconst = col_double(),
## .. parqueaderos = col_double(),
## .. banios = col_double(),
## .. habitaciones = col_double(),
## .. tipo = col_character(),
## .. barrio = col_character(),
## .. longitud = col_double(),
## .. latitud = col_double()
## .. )
## - attr(*, "problems")=<externalptr>
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1147 | Zona Oriente | NA | 3 | 250 | 70 | 1 | 3 | 6 | Casa | 20 de julio | -76.51168 | 3.43382 |
| 1169 | Zona Oriente | NA | 3 | 320 | 120 | 1 | 2 | 3 | Casa | 20 de julio | -76.51237 | 3.43369 |
| 1350 | Zona Oriente | NA | 3 | 350 | 220 | 2 | 2 | 4 | Casa | 20 de julio | -76.51537 | 3.43566 |
| 5992 | Zona Sur | 02 | 4 | 400 | 280 | 3 | 5 | 3 | Casa | 3 de julio | -76.54000 | 3.43500 |
| 1212 | Zona Norte | 01 | 5 | 260 | 90 | 1 | 2 | 3 | Apartamento | acopi | -76.51350 | 3.45891 |
Cargar el Shapefile de Cali y transformar CRS.
## Reading layer `barrios' from data source `C:\Users\Toshiba\Desktop\mapas cali' using driver `ESRI Shapefile'
## Simple feature collection with 338 features and 9 fields
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: 104550.1 ymin: 97278.59 xmax: 119174.7 ymax: 116499.4
## Projected CRS: PCS_CALI_BOG
Filtrado de Datos.
# Base 1: Casas en Zona Norte
base1 <- vivienda %>% filter(tipo == "Casa", zona == "Zona Norte")
# Base 2: Apartamentos en Zona Sur
base2 <- vivienda %>% filter(tipo == "Apartamento", zona == "Zona Sur")
# Mostrar primeros registros de cada base
kable(head(base1, 3), caption = "Primeros registros de Casas en 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 | NA | 7 | 6 | Casa | acopi | -76.52950 | 3.38527 |
| 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 |
Análisis Exploratorio de Datos.
Se analizaron las relaciones entre variables clave mediante gráficos interactivos y matrices de correlación.
# Matriz de correlación con gráficos interactivos
ggplot(base1, aes(x = areaconst, y = preciom, color = as.factor(estrato))) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, color = "black") +
labs(title = "Relación entre Área Construida y Precio", x = "Área Construida", y = "Precio") +
theme_minimal()# Matriz de correlación
ggpairs(base1 %>% select(preciom, areaconst, estrato, banios, habitaciones, parqueaderos))# Gráfico interactivo para Casas en Zona Norte
plot_ly(data = base1, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers', color = ~estrato) %>%
layout(title = "Relación entre Área Construida y Precio - Zona Norte")# Gráfico interactivo para Apartamentos en Zona Sur
plot_ly(data = base2, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers', color = ~estrato) %>%
layout(title = "Relación entre Área Construida y Precio - Zona Sur")Modelo de Regresión Lineal Múltiple.
Se construyeron modelos de regresión lineal múltiple para estimar el precio de las viviendas en función de variables relevantes.
modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + banios + parqueaderos, data = base1)
modelo2 <- lm(preciom ~ areaconst + estrato + habitaciones + banios + parqueaderos, data = base2)
# Resumen del modelo
kable(tidy(modelo1), caption = "Coeficientes del Modelo de Regresión - Casas en Zona Norte")| term | estimate | std.error | statistic | p.value |
|---|---|---|---|---|
| (Intercept) | -238.1708979 | 44.4055069 | -5.363544 | 0.0000001 |
| areaconst | 0.6767346 | 0.0528121 | 12.814001 | 0.0000000 |
| estrato | 80.6349477 | 9.8263227 | 8.206015 | 0.0000000 |
| habitaciones | 7.6451100 | 5.6587338 | 1.351028 | 0.1773984 |
| banios | 18.8993776 | 7.4880029 | 2.523954 | 0.0119643 |
| parqueaderos | 24.0059798 | 5.8688857 | 4.090381 | 0.0000514 |
| term | estimate | std.error | statistic | p.value |
|---|---|---|---|---|
| (Intercept) | -261.625007 | 15.632196 | -16.736292 | 0 |
| areaconst | 1.285049 | 0.054027 | 23.785327 | 0 |
| estrato | 60.897089 | 3.084076 | 19.745652 | 0 |
| habitaciones | -24.836930 | 3.892286 | -6.381064 | 0 |
| banios | 50.696747 | 3.396374 | 14.926725 | 0 |
| parqueaderos | 72.914680 | 3.957968 | 18.422252 | 0 |
Validación del Modelo.
Se realizaron pruebas de validación del modelo para evaluar su desempeño.
Predicción de Precios.
solicitud1 <- data.frame(areaconst = 200, estrato = 4, habitaciones = 4, banios = 2, parqueaderos = 1)
pred1 <- predict(modelo1, solicitud1)
solicitud2 <- data.frame(areaconst = 300, estrato = 5, habitaciones = 5, banios = 3, parqueaderos = 3)
pred2 <- predict(modelo2, solicitud2)
cat("Precio estimado para la Vivienda 1: ", round(pred1, 2), "millones de pesos")## Precio estimado para la Vivienda 1: 312.1 millones de pesos
##
## Precio estimado para la Vivienda 2: 675.02 millones de pesos
Recomendaciones de Viviendas con todas las opciones + Top 10.
recomendadas1 <- base1 %>% filter(preciom <= 350)
recomendadas2 <- base2 %>% filter(preciom <= 850)
# Mapa con todas las opciones
leaflet() %>%
addProviderTiles(providers$CartoDB.Positron) %>% # Fondo más limpio
addPolygons(data = cali_shp, fillColor = "transparent", color = "gray", weight = 1, opacity = 0.5) %>%
addCircleMarkers(data = recomendadas1, ~longitud, ~latitud, color = "blue", radius = 5, popup = ~paste("Casa - Precio: ", preciom, "millones")) %>%
addCircleMarkers(data = recomendadas2, ~longitud, ~latitud, color = "red", radius = 5, popup = ~paste("Apartamento - Precio: ", preciom, "millones"))Mapa Top 10.
# Seleccionar el Top 10 de opciones más recomendadas según área y estrato
top10_casas <- recomendadas1 %>% arrange(desc(areaconst), estrato) %>% head(10)
top10_apartamentos <- recomendadas2 %>% arrange(desc(areaconst), estrato) %>% head(10)
# Mapa Top 10
leaflet() %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data = cali_shp, fillColor = "transparent", color = "gray", weight = 1, opacity = 0.5) %>%
addCircleMarkers(data = top10_casas, ~longitud, ~latitud, color = "blue", radius = 7, popup = ~paste("Top 10 Casa - Precio: ", preciom, "millones")) %>%
addCircleMarkers(data = top10_apartamentos, ~longitud, ~latitud, color = "red", radius = 7, popup = ~paste("Top 10 Apartamento - Precio: ", preciom, "millones"))Filtrar Casas y Aptos en Zona.
Se filtraron los datos para incluir solo las viviendas que cumplen con las condiciones de la solicitud. Además, se eliminaron registros con valores NA en variables esenciales.
recomendadas1 <- recomendadas1 %>%
filter(!is.na(habitaciones) & habitaciones > 0, !is.na(banios) & banios > 0, !is.na(preciom) & preciom > 0)
# Filtrar apartamentos en Zona Sur eliminando registros con NA en habitaciones o baños
recomendadas2 <- recomendadas2 %>%
filter(!is.na(habitaciones) & habitaciones > 0, !is.na(banios) & banios > 0, !is.na(preciom) & preciom > 0)Seleccionar la mejor opción en cada zona.
Se identificaron las mejores opciones disponibles, asegurando que cumplan con las necesidades de la empresa cliente.
mejor_casa_norte <- recomendadas1 %>%
arrange(desc(areaconst), desc(estrato), preciom) %>%
slice(1)
mejor_apto_sur <- recomendadas2 %>%
arrange(desc(areaconst), desc(estrato), preciom) %>%
slice(1)
# Unir en un solo DataFrame
mejor_opcion <- bind_rows(mejor_casa_norte, mejor_apto_sur)
# Mostrar la tabla con las mejores opciones
kable(mejor_opcion, caption = "Mejor opción en cada zona después de la validación de datos")| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1189 | Zona Norte | NA | 3 | 330 | 400 | NA | 5 | 8 | Casa | la floresta | -76.51300 | 3.44400 |
| 6121 | Zona Sur | 07 | 5 | 299 | 932 | 1 | 3 | 3 | Apartamento | valle del lili | -76.54087 | 3.37348 |
Recomendaciones para C&A:
1️⃣ Priorizar la opción en Zona Sur (Apartamento en Valle del Lili), ya que se encuentra dentro del presupuesto y en una zona de alta valorización.
2️⃣ Revisar la opción en Zona Norte (Casa en La Floresta), pues aunque tiene buen área, el número de baños y parqueaderos podría ser un factor limitante.
3️⃣ Explorar nuevas opciones en el mercado si los criterios son demasiado estrictos.
Crear un gráfico de comparación.
datos_grafico <- bind_rows(recomendadas1, recomendadas2) %>%
mutate(destacado = ifelse(id %in% mejor_opcion$id, "Mejor Opción", "Otra Vivienda"))
ggplot(datos_grafico, aes(x = as.factor(estrato), y = areaconst, fill = destacado)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Comparación de Área Construida por Estrato",
x = "Estrato", y = "Área Construida (m²)") +
scale_fill_manual(values = c("Mejor Opción" = "#7FFFD4", "Otra Vivienda" = "gray")) +
theme_minimal()Zonas por Variables.
leaflet() %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data = cali_shp, fillColor = "transparent", color = "gray", weight = 1, opacity = 0.5) %>%
addCircleMarkers(data = recomendadas1, ~longitud, ~latitud, color = "blue", radius = 5, popup = ~paste("Casa - Precio: ", preciom, "millones")) %>%
addCircleMarkers(data = recomendadas2, ~longitud, ~latitud, color = "red", radius = 5, popup = ~paste("Apartamento - Precio: ", preciom, "millones"))Seleccionar la mejor opción en cada zona.
mejor_casa_norte <- recomendadas1 %>%
arrange(desc(areaconst), desc(estrato), preciom) %>%
slice(1)
mejor_apto_sur <- recomendadas2 %>%
arrange(desc(areaconst), desc(estrato), preciom) %>%
slice(1)
# Seleccionar la peor opción en cada zona
peor_casa_norte <- recomendadas1 %>%
arrange(areaconst, estrato, preciom) %>%
slice(1)
peor_apto_sur <- recomendadas2 %>%
arrange(areaconst, estrato, preciom) %>%
slice(1)
# Unir en DataFrames
mejor_opcion <- bind_rows(mejor_casa_norte, mejor_apto_sur)
peor_opcion <- bind_rows(peor_casa_norte, peor_apto_sur)Mejores y Peores Zonas.
Se generaron mapas interactivos para visualizar la distribución de las opciones recomendadas.
leaflet() %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data = cali_shp, fillColor = "transparent", color = "gray", weight = 1, opacity = 0.5) %>%
# Marcar mejor casa en Zona Norte (Azul)
addCircleMarkers(data = mejor_casa_norte, ~longitud, ~latitud, color = "blue", radius = 8,
popup = ~htmltools::HTML(paste("<b>🏡 MEJOR CASA (Zona Norte)</b><br>",
"📍 Ubicación: ", barrio, "<br>",
"💰 Precio: ", preciom, " millones<br>",
"📏 Área: ", areaconst, " m²<br>",
"🏙️ Estrato: ", estrato, "<br>",
"🚗 Parqueaderos: ", parqueaderos, "<br>",
"🛁 Baños: ", banios, "<br>",
"🛏️ Habitaciones: ", habitaciones)),
label = ~htmltools::HTML(paste("📍 Casa en ", barrio, " - ", preciom, "M"))) %>%
# Marcar mejor apartamento en Zona Sur (Verde)
addCircleMarkers(data = mejor_apto_sur, ~longitud, ~latitud, color = "green", radius = 8,
popup = ~htmltools::HTML(paste("<b>🏢 MEJOR APARTAMENTO (Zona Sur)</b><br>",
"📍 Ubicación: ", barrio, "<br>",
"💰 Precio: ", preciom, " millones<br>",
"📏 Área: ", areaconst, " m²<br>",
"🏙️ Estrato: ", estrato, "<br>",
"🚗 Parqueaderos: ", parqueaderos, "<br>",
"🛁 Baños: ", banios, "<br>",
"🛏️ Habitaciones: ", habitaciones)),
label = ~htmltools::HTML(paste("📍 Apto en ", barrio, " - ", preciom, "M"))) %>%
# Marcar peor casa en Zona Norte (Rojo)
addCircleMarkers(data = peor_casa_norte, ~longitud, ~latitud, color = "red", radius = 8,
popup = ~htmltools::HTML(paste("<b>⚠️ PEOR CASA (Zona Norte)</b><br>",
"📍 Ubicación: ", barrio, "<br>",
"💰 Precio: ", preciom, " millones<br>",
"📏 Área: ", areaconst, " m²<br>",
"🏙️ Estrato: ", estrato, "<br>",
"🚗 Parqueaderos: ", parqueaderos, "<br>",
"🛁 Baños: ", banios, "<br>",
"🛏️ Habitaciones: ", habitaciones)),
label = ~htmltools::HTML(paste("⚠️ Casa en ", barrio, " - ", preciom, "M"))) %>%
# Marcar peor apartamento en Zona Sur (Naranja)
addCircleMarkers(data = peor_apto_sur, ~longitud, ~latitud, color = "orange", radius = 8,
popup = ~htmltools::HTML(paste("<b>⚠️ PEOR APARTAMENTO (Zona Sur)</b><br>",
"📍 Ubicación: ", barrio, "<br>",
"💰 Precio: ", preciom, " millones<br>",
"📏 Área: ", areaconst, " m²<br>",
"🏙️ Estrato: ", estrato, "<br>",
"🚗 Parqueaderos: ", parqueaderos, "<br>",
"🛁 Baños: ", banios, "<br>",
"🛏️ Habitaciones: ", habitaciones)),
label = ~htmltools::HTML(paste("⚠️ Apto en ", barrio, " - ", preciom, "M")))Conclusiónes.
Se han identificado todas las viviendas disponibles dentro del presupuesto solicitado.
Se han seleccionado las mejores opciones en cada zona con base en criterios estratégicos.
El apartamento en Zona Sur es la mejor opción, mientras que la casa en Zona Norte debe evaluarse con más detalle.
Decisión para C&A:
✔ Recomendar la opción en Valle del Lili como la más viable, zona sur.
✔ Recomendar la opción en la floresta como la más viable zona norte.
✔ Usar este análisis para mejorar futuras estrategias de asesoramiento inmobiliario.
Recomendaciones Estratégicas para la Empresa.
🔹 Si la empresa está dispuesta a flexibilizar los criterios, podría encontrar mejores opciones en Zona Norte.
🔹 Se recomienda contactar directamente a los vendedores de las viviendas seleccionadas para negociar mejores precios o evaluar más detalles sobre los inmuebles.
🔹 Incluir nuevas variables en el análisis como cercanía a transporte, colegios o seguridad podría mejorar la toma de decisiones en futuras búsquedas.