El presente informe tiene como objetivo realizar un análisis multidimensional del mercado inmobiliario para apoyar la toma de decisiones estratégicas.
Se utilizó una base de datos con ofertas de vivienda, realizando una limpieza de valores nulos para garantizar la calidad del análisis.
if(!require(remotes)) install.packages("remotes")
## Cargando paquete requerido: remotes
remotes::install_github("centromagis/paqueteMODELOS", force = TRUE)
## Downloading GitHub repo centromagis/paqueteMODELOS@HEAD
## stringi (1.8.7 -> 1.8.9) [CRAN]
## rlang (1.2.0 -> 1.3.0) [CRAN]
## Rcpp (1.1.1 -> 1.1.2) [CRAN]
## xfun (0.57 -> 0.60 ) [CRAN]
## Installing 4 packages: stringi, rlang, Rcpp, xfun
## Installing packages into 'C:/Users/jstorresm12/AppData/Local/R/win-library/4.4'
## (as 'lib' is unspecified)
##
## There are binary versions available but the source versions are later:
## binary source needs_compilation
## stringi 1.8.7 1.8.9 TRUE
## rlang 1.2.0 1.3.0 TRUE
## Rcpp 1.1.1 1.1.2 TRUE
## xfun 0.57 0.60 TRUE
##
## Binaries will be installed
## package 'stringi' successfully unpacked and MD5 sums checked
## package 'rlang' successfully unpacked and MD5 sums checked
## Warning: cannot remove prior installation of package 'rlang'
## Warning in file.copy(savedcopy, lib, recursive = TRUE): problema al copiar
## C:\Users\jstorresm12\AppData\Local\R\win-library\4.4\00LOCK\rlang\libs\x64\rlang.dll
## a
## C:\Users\jstorresm12\AppData\Local\R\win-library\4.4\rlang\libs\x64\rlang.dll:
## Permission denied
## Warning: restored 'rlang'
## package 'Rcpp' successfully unpacked and MD5 sums checked
## package 'xfun' successfully unpacked and MD5 sums checked
## Warning: cannot remove prior installation of package 'xfun'
## Warning in file.copy(savedcopy, lib, recursive = TRUE): problema al copiar
## C:\Users\jstorresm12\AppData\Local\R\win-library\4.4\00LOCK\xfun\libs\x64\xfun.dll
## a C:\Users\jstorresm12\AppData\Local\R\win-library\4.4\xfun\libs\x64\xfun.dll:
## Permission denied
## Warning: restored 'xfun'
##
## The downloaded binary packages are in
## C:\Users\jstorresm12\AppData\Local\Temp\RtmpEVnna9\downloaded_packages
## ── R CMD build ─────────────────────────────────────────────────────────────────
## WARNING: Rtools is required to build R packages, but is not currently installed.
##
## Please download and install Rtools 4.4 from https://cran.r-project.org/bin/windows/Rtools/.
## checking for file 'C:\Users\jstorresm12\AppData\Local\Temp\RtmpEVnna9\remotes27ec7f384914\Centromagis-paqueteMODELOS-3b06257/DESCRIPTION' ... ✔ checking for file 'C:\Users\jstorresm12\AppData\Local\Temp\RtmpEVnna9\remotes27ec7f384914\Centromagis-paqueteMODELOS-3b06257/DESCRIPTION' (3.2s)
## ─ preparing 'paqueteMODELOS': (1.2s)
## checking DESCRIPTION meta-information ... ✔ checking DESCRIPTION meta-information
## ─ checking for LF line-endings in source and make files and shell scripts (1.5s)
## ─ checking for empty or unneeded directories
## ─ building 'paqueteMODELOS_0.1.0.tar.gz'
##
##
## Installing package into 'C:/Users/jstorresm12/AppData/Local/R/win-library/4.4'
## (as 'lib' is unspecified)
library(paqueteMODELOS)
## Cargando paquete requerido: boot
## Cargando paquete requerido: broom
## Cargando paquete requerido: GGally
## Cargando paquete requerido: ggplot2
## Cargando paquete requerido: gridExtra
## Cargando paquete requerido: knitr
## Cargando paquete requerido: summarytools
# Cargue de datos
data("vivienda")
str(vivienda)
## 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")=List of 3
## ..$ cols :List of 13
## .. ..$ id : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ zona : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ piso : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ estrato : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ preciom : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ areaconst : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ parqueaderos: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ banios : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ habitaciones: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ tipo : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ barrio : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ longitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ latitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## ..$ default: list()
## .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
## ..$ delim : chr ";"
## ..- attr(*, "class")= chr "col_spec"
## - attr(*, "problems")=<externalptr>
1.1. Exploracion y limpieza de datos
library(dplyr)
##
## Adjuntando el paquete: 'dplyr'
## The following object is masked from 'package:gridExtra':
##
## combine
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(tidyr)
cat("Valores faltantes por variable:\n")
## Valores faltantes por variable:
colSums(is.na(vivienda))
## id zona piso estrato preciom areaconst
## 3 3 2638 3 2 3
## parqueaderos banios habitaciones tipo barrio longitud
## 1605 3 3 3 3 3
## latitud
## 3
vivienda_limpia <- vivienda %>% drop_na()
cat("\nTotal de observaciones después de limpiar:\n")
##
## Total de observaciones después de limpiar:
nrow(vivienda_limpia)
## [1] 4808
1.2. PCA
if(!require(factoextra)) install.packages("factoextra")
## Cargando paquete requerido: factoextra
## Welcome to factoextra!
## Want to learn more? See two factoextra-related books at https://www.datanovia.com/library/principal-component-methods
library(factoextra)
# Seleccion de variables numéricas de interés
vivienda_pca_data <- vivienda_limpia %>%
select(preciom, areaconst, estrato, parqueaderos, banios, habitaciones)
res_pca <- prcomp(vivienda_pca_data, scale. = TRUE)
summary(res_pca)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6
## Standard deviation 1.8866 1.0884 0.69530 0.58528 0.49647 0.42886
## Proportion of Variance 0.5932 0.1974 0.08057 0.05709 0.04108 0.03065
## Cumulative Proportion 0.5932 0.7906 0.87117 0.92827 0.96935 1.00000
fviz_eig(res_pca, addlabels = TRUE, ylim = c(0, 60))
# Círculo de correlaciones de variables
fviz_pca_var(res_pca,
col.var = "contrib", # Colorear según su contribución
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE) # Evitar sobreposición de texto
El grupo principal (Correlación Positiva): Las flechas de preciom,
parqueaderos, banios y areaconst están muy juntas y apuntan en la misma
dirección. Esto significa que están fuertemente correlacionadas. En
términos de negocio: a mayor área construida, las viviendas tienden a
tener más baños, más parqueaderos y, en consecuencia, un precio mayor.
El eje horizontal (Dim1) explica el 59.3% de la información total. Como
todas las flechas apuntan hacia la derecha de este eje, se puede
analizar que la Dimensión 1 como el “Tamaño y Valor” de la propiedad. El
estrato apunta hacia arriba (Dim2 positiva) y habitaciones apunta hacia
abajo (Dim2 negativa). El hecho de que estén casi separadas por un
ángulo de 90 grados indica que no tienen mucha relación entre sí. Es
decir, un estrato alto no garantiza que la casa tenga muchas
habitaciones.
Usando el algoritmo de K-Means
# número de clusters (Método del codo)
fviz_nbclust(scale(vivienda_pca_data), kmeans, method = "wss") +
labs(title = "Método del Codo para determinar Clusters")
set.seed(123)
res_kmeans <- kmeans(scale(vivienda_pca_data), centers = 3, nstart = 25)
fviz_cluster(res_kmeans, data = scale(vivienda_pca_data),
geom = "point",
ellipse.type = "convex",
ggtheme = theme_minimal(),
main = "Segmentación del Mercado Inmobiliario")
Cluster 3 (Cuadrados azules - Izquierda): Representa el segmento de
viviendas económicas. Tienen valores negativos en la Dimensión 1, lo que
indica que son propiedades con menor precio, menor área construida, y
menos comodidades (baños/parqueaderos).
Cluster 1 (Círculos rojos - Centro): Es el segmento medio del mercado. Propiedades con características y precios promedio.
Cluster 2 (Triángulos verdes - Derecha): Representa el segmento de lujo o de alto valor. Tienen valores fuertemente positivos en la Dimensión 1, indicando que son las propiedades más caras, grandes y con mayores comodidades.
Nota: La variable barrio suele tener muchísimas categorías distintas, lo que hace que los gráficos sean imposibles de leer. Por tanto, graficaremos la relación principal entre tipo y zona, que da una visión macro muy clara para la empresa.
if(!require(FactoMineR)) install.packages("FactoMineR")
## Cargando paquete requerido: FactoMineR
library(FactoMineR)
# variables categóricas principales (Tipo y Zona)
vivienda_cat <- vivienda_limpia %>%
select(tipo, zona) %>%
mutate(across(everything(), as.factor))
res_mca <- MCA(vivienda_cat, graph = FALSE)
fviz_mca_var(res_mca,
repel = TRUE,
col.var = "blue",
shape.var = 15,
ggtheme = theme_minimal(),
title = "Relación entre Tipo de Vivienda y Zona")
Apartamento está fuertemente agrupado a la izquierda con Zona Oeste y
Zona Norte. Esto nos indica que la oferta inmobiliaria en estas zonas
está dominada por apartamentos. El punto de Casa está más cercano al
centro y se orienta hacia la Zona Sur. Esto sugiere que si un cliente
busca una casa, la mayor probabilidad de encontrarla (o la mayor
concentración de esta oferta) está en el sur de la ciudad. Las zonas
centro y oriente estan muy alejadas del resto, lo que significa que
tienen un comportamiento “atípico” o una oferta mucho menor en
comparación con los grandes bloques del Norte/Oeste.
A continuacion se presenta un mapa interactivo con las ubicaciones de casas y apartamentos (Casas azules, Apartamentos rojos), donde se puede hacer zoon y dar clic en los puntos para que muestre la informacion del inmueble
if(!require(leaflet)) install.packages("leaflet")
## Cargando paquete requerido: leaflet
library(leaflet)
library(dplyr)
set.seed(123)
vivienda_mapa <- vivienda_limpia %>% sample_n(1000)
mapa_inmobiliario <- leaflet(vivienda_mapa) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud,
lat = ~latitud,
radius = 4,
color = ~ifelse(tipo == "Casa", "blue", "red"),
stroke = FALSE,
fillOpacity = 0.7,
popup = ~paste("<b>Tipo:</b>", tipo, "<br>",
"<b>Precio:</b> $", preciom, "M<br>",
"<b>Barrio:</b>", barrio, "<br>",
"<b>Zona:</b>", zona)
)
mapa_inmobiliario
Los determinantes del valor: Según el Análisis de Componentes Principales (PCA), el precio de las propiedades está directamente y fuertemente correlacionado con el área construida, el número de baños y los parqueaderos. Sorprendentemente, el estrato y la cantidad de habitaciones tienen dinámicas más independientes y no garantizan por sí solos un precio más elevado si no van acompañados de un área mayor.
Segmentación del mercado: El análisis de conglomerados reveló la existencia de tres nichos de mercado claramente definidos:
Segmento Económico: Propiedades más pequeñas, con menos comodidades y precios accesibles.
Segmento Medio: El grueso del mercado, con características estándar en área y precio.
Segmento de Lujo: Propiedades exclusivas que destacan significativamente por su gran extensión, múltiples parqueaderos/baños y valoraciones topes.
Especialización geográfica de la oferta: El Análisis de Correspondencias y el mapa interactivo demostraron que la ciudad (Cali) tiene una oferta territorialmente polarizada. Las Zonas Norte y Oeste están fuertemente dominadas por la oferta de apartamentos, mientras que la Zona Sur concentra la mayor oferta de casas tradicionales.
Recomendaciones para la Inmobiliaria:
Estrategia de Captación e Inversión: Se sugiere enfocar los esfuerzos de captación de apartamentos en las Zonas Norte y Oeste, ya que son los productos de mayor rotación allí. Si la empresa busca desarrollar o comercializar casas unifamiliares, el foco estratégico y comercial debe dirigirse indiscutiblemente a la Zona Sur.
Optimización de la Valoración: Al tasar una nueva propiedad para compra o venta, los agentes inmobiliarios deben priorizar el área construida, baños y parqueaderos sobre el simple número de habitaciones, ya que estos son los verdaderos impulsores del precio de mercado.
Oportunidades de Nicho: Las zonas Centro y Oriente muestran una oferta habitacional menor o atípica. Esto podría representar un “océano azul” para proyectos de renovación urbana o vivienda asequible, donde la competencia actual de la oferta es considerablemente más baja.