Introducción

El presente informe tiene como objetivo analizar el mercado inmobiliario urbano a partir de una base de datos real de viviendas ofertadas.

Se aplican técnicas de análisis multivariado como:

Con el fin de identificar patrones, segmentaciones y relaciones relevantes para la toma de decisiones estratégicas.

library(dplyr)
library(ggplot2)
library(FactoMineR)
library(factoextra)
library(cluster)
library(corrplot)
library(paqueteMODELOS)
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>
head(vivienda)
## # A tibble: 6 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1147 Zona O… <NA>        3     250        70            1      3            6
## 2  1169 Zona O… <NA>        3     320       120            1      2            3
## 3  1350 Zona O… <NA>        3     350       220            2      2            4
## 4  5992 Zona S… 02          4     400       280            3      5            3
## 5  1212 Zona N… 01          5     260        90            1      2            3
## 6  1724 Zona N… 01          5     240        87            1      3            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
summary(vivienda)
##        id           zona               piso              estrato     
##  Min.   :   1   Length:8322        Length:8322        Min.   :3.000  
##  1st Qu.:2080   Class :character   Class :character   1st Qu.:4.000  
##  Median :4160   Mode  :character   Mode  :character   Median :5.000  
##  Mean   :4160                                         Mean   :4.634  
##  3rd Qu.:6240                                         3rd Qu.:5.000  
##  Max.   :8319                                         Max.   :6.000  
##  NA's   :3                                            NA's   :3      
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  30.0   Min.   : 1.000   Min.   : 0.000  
##  1st Qu.: 220.0   1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 330.0   Median : 123.0   Median : 2.000   Median : 3.000  
##  Mean   : 433.9   Mean   : 174.9   Mean   : 1.835   Mean   : 3.111  
##  3rd Qu.: 540.0   3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1999.0   Max.   :1745.0   Max.   :10.000   Max.   :10.000  
##  NA's   :2        NA's   :3        NA's   :1605     NA's   :3       
##   habitaciones        tipo              barrio             longitud     
##  Min.   : 0.000   Length:8322        Length:8322        Min.   :-76.59  
##  1st Qu.: 3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median : 3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   : 3.605                                         Mean   :-76.53  
##  3rd Qu.: 4.000                                         3rd Qu.:-76.52  
##  Max.   :10.000                                         Max.   :-76.46  
##  NA's   :3                                              NA's   :3       
##     latitud     
##  Min.   :3.333  
##  1st Qu.:3.381  
##  Median :3.416  
##  Mean   :3.418  
##  3rd Qu.:3.452  
##  Max.   :3.498  
##  NA's   :3

Exploración inicial de datos

La base de datos contiene 8.322 registros de viviendas y 13 variables que describen características físicas, ubicación y precio.

Se identifican variables numéricas como precio, área construida, número de baños y habitaciones, así como variables categóricas como zona, tipo de vivienda y barrio.

Se observan algunos valores faltantes (NA), especialmente en parqueaderos.

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

Se realizó un análisis de valores faltantes en las variables numéricas.Se encontró que la mayoría de variables presentaban menos del 1% de datos faltantes, por lo cual se imputaron usando la media.

La variable parqueaderos presentó aproximadamente un 19% de valores faltantes. Por lo que al proceder a hacer una eliminación se piede casi un quinto de la base de datos, por lo que en este caso es mejor hacer una imputación. En este caso, se utilizó la mediana para la imputación, dado que es una variable de conteo y la mediana es más robusta ante valores extremos.

Esta estrategia permitió conservar la totalidad de las observaciones sin introducir sesgos significativos.

vars <- vivienda %>%
  select(preciom, areaconst, parqueaderos, banios, habitaciones, estrato)

vivienda_num <- vars %>%
  mutate(
    parqueaderos = ifelse(is.na(parqueaderos),
                          median(parqueaderos, na.rm=TRUE),
                          parqueaderos)
  ) %>%
  mutate(across(-parqueaderos,
                ~ifelse(is.na(.), mean(., na.rm=TRUE), .)))

colSums(is.na(vivienda_num))
##      preciom    areaconst parqueaderos       banios habitaciones      estrato 
##            0            0            0            0            0            0

Matriz de correlaciones

cor_mat <- cor(vivienda_num)

corrplot(cor_mat, method="color", addCoef.col="black")

La matriz de correlaciones muestra asociaciones importantes entre las variables analizadas. Se observa una fuerte correlación positiva entre el precio y el área construida (0.69), lo cual indica que viviendas de mayor tamaño tienden a tener mayor valor comercial.

El precio también presenta alta correlación con el número de baños (0.67) y parqueaderos (0.62), sugiriendo que estas características influyen significativamente en el valor de la vivienda. Asimismo, el estrato muestra una correlación positiva con el precio (0.61), lo cual refleja la relación entre nivel socioeconómico y valor del inmueble. Por otro lado, el número de habitaciones presenta correlaciones moderadas, lo que indica que no siempre más habitaciones implican mayor precio si no están acompañadas de mayor área o calidad.

Al encontrar estas relaciones, se justifica la aplicación de técnicas multivariadas como el Análisis de Componentes Principales (PCA) para sintetizar la información, y obtener mejores resultados.

Consideraciones metodológicas

Si bien la base de datos incluye variables geográficas como latitud y longitud, estas no fueron incorporadas en los análisis multivariados realizados.

Dado que el objetivo del estudio es identificar patrones asociados a características físicas, tipológicas y socioeconómicas de las viviendas, se priorizaron variables directamente relacionadas con el valor y estructura del inmueble.

La dimensión espacial fue considerada a través de la variable categórica zona, lo que permitió capturar diferencias territoriales de manera interpretativa sin introducir complejidad geoespacial adicional en los modelos.

Análisis de Componentes Principales (PCA)

Antes de aplicar el PCA, las variables fueron estandarizadas para eliminar el efecto de las diferentes escalas de medición.

Este proceso asegura que todas las variables contribuyan de manera equitativa al análisis.

datos_scaled <- scale(vivienda_num)
pca <- prcomp(datos_scaled)

summary(pca)
## Importance of components:
##                          PC1    PC2    PC3     PC4     PC5     PC6
## Standard deviation     1.835 1.0958 0.7890 0.62298 0.48690 0.43076
## Proportion of Variance 0.561 0.2001 0.1038 0.06468 0.03951 0.03093
## Cumulative Proportion  0.561 0.7611 0.8649 0.92956 0.96907 1.00000

El Análisis de Componentes Principales permitie reducir la dimensionalidad del conjunto de datos.

El primer componente principal explica el 56.1% de la variabilidad total, mientras que el segundo componente explica un 20.0%. Por lo que, los dos primeros componentes representan el 76.1% de la variabilidad acumulada, lo cual indica que una gran parte de la información original puede resumirse en solo dos dimensiones.

Esto evidencia la existencia de patrones comunes entre las variables analizadas.

fviz_eig(pca, addlabels=TRUE)

Lo anterior se representa graficamente en el gráfico de sedimentación (Scree Plot) muestra que los dos primeros componentes concentran la mayor proporción de varianza, confirmando que son suficientes para representar la estructura de los datos.

El gráfico de variables del PCA permite interpretar la contribución de cada variable a los componentes principales.

fviz_pca_var(pca, col.var="contrib")

El primer componente (56.1% de varianza) está fuertemente asociado con el precio, el área construida, el número de baños y parqueaderos. Esto sugiere que este componente representa el tamaño y valor general de la vivienda.Es decir, viviendas con mayor área, más baños y parqueaderos tienden a tener precios más altos.

El segundo componente (20%) muestra un contraste entre el estrato y el número de habitaciones. Esto indica que un mayor número de habitaciones no necesariamente implica un mayor nivel socioeconómico. Este hallazgo sugiere que la calidad y ubicación de la vivienda pueden ser más determinantes que la cantidad de habitaciones.

Resumiendo, el PCA revela que el valor de la vivienda depende más de su tamaño, calidad y ubicación que del número de habitaciones por sí solo.

Por último para hacer el análisis mas profundo, se intentó visualizar un biplot del PCA; sin embargo, debido al gran número de observaciones, la gráfica resultó poco interpretable. Por esta razón, se priorizó el análisis de cargas y varianza explicada.

Análisis de Conglomerados (Clustering)

El análisis de conglomerados tiene como objetivo identificar grupos de viviendas con características similares, permitiendo segmentar el mercado inmobiliario.

Esta técnica facilita reconocer patrones en los datos y clasificar las viviendas en segmentos homogéneos, lo cual resulta útil para la toma de decisiones comerciales y estrategias de mercado.

fviz_nbclust(datos_scaled, kmeans, method = "wss")

Al analizar el gráfico del método del codo, no se observa facilmente un punto de inflexión completamente definido. Sin embargo, se evidencia una disminución pronunciada en la variabilidad al pasar de 1 a 2 conglomerados, y reducciones progresivamente menores a partir de allí.

A partir de 4 conglomerados la curva comienza a estabilizarse, lo que indica que agregar más grupos no genera mejoras sustanciales. Por esta razón, se decidió trabajar con 4 clusters, ya que representan un balance adecuado entre capacidad explicativa e interpretabilidad de los segmentos.

Por lo tanto, se seleccionaron 4 clusters, logrando un equilibrio entre capacidad explicativa e interpretabilidad de los segmentos.

set.seed(123)

km <- kmeans(datos_scaled, centers = 4, nstart = 25)

km$size
## [1] 2520 3962  941  899

La segmentación generó cuatro conglomerados con tamaños relativamente balanceados.

Esto indica que la clasificación logró identificar grupos representativos dentro del mercado inmobiliario, evitando la formación de segmentos demasiado pequeños o poco significativos.

vivienda_cluster <- vivienda_num %>%
  mutate(cluster = km$cluster)

aggregate(. ~ cluster, vivienda_cluster, mean)
##   cluster   preciom areaconst parqueaderos   banios habitaciones  estrato
## 1       1  515.5547 173.68943     1.967063 3.526323     3.391594 5.450357
## 2       2  220.1055  91.12276     1.373801 2.072438     2.892983 4.042655
## 3       3  444.4346 298.11068     1.834219 4.453773     6.433581 3.893730
## 4       4 1136.1290 418.86615     3.794216 5.121246     4.383760 5.723026

El análisis de conglomerados permitió identificar cuatro segmentos diferenciados en el mercado inmobiliario.

Un primer segmento corresponde a viviendas económicas, con menor precio, área y número de baños, orientadas a estratos medios.

Un segundo grupo representa viviendas de nivel medio, con características balanceadas en tamaño y precio.

Se identificó además un segmento de viviendas amplias con muchas habitaciones pero ubicadas en estratos no tan altos, lo cual sugiere propiedades grandes en zonas menos exclusivas.

Finalmente, se observa un segmento de viviendas que podemos llamar premium, con altos precios, gran área construida y mayor número de parqueaderos y baños, asociado a estratos altos.

Ahora veamos cómo se ve esta distribución graficamente

fviz_cluster(km, data = datos_scaled)

El gráfico de conglomerados permite visualizar la segmentación de las viviendas en los cuatro grupos con características relativamente diferenciadas. Se observa que los clusters se separan principalmente a lo largo de la primera componente principal, lo que indica que variables como precio, área construida y número de baños tienen un papel importante en la diferenciación de los segmentos. Cada conglomerado representa perfiles de vivienda distintos, desde propiedades de menor valor y tamaño hasta viviendas de mayor precio y características más amplias. La segmentación facilita la identificación de patrones en el mercado inmobiliario y puede apoyar la toma de decisiones estratégicas según el tipo de vivienda analizada.

Análisis de Correspondencias

El análisis de correspondencias múltiples (MCA) se aplicó a las variables categóricas con el fin de explorar asociaciones entre categorías de zona, tipo de vivienda, barrio y estrato.

Esta técnica permite representar las relaciones entre categorías en un espacio bidimensional, facilitando la identificación de patrones de asociación en el mercado inmobiliario.

La variable barrio no fue incluida en el análisis de correspondencias debido a su alta cantidad de categorías, lo que puede generar dispersión excesiva y reducir la claridad interpretativa del modelo.

vivienda_cat <- vivienda %>%
  select(zona, tipo, estrato) %>%
  na.omit() %>%
  mutate(across(everything(), as.factor))

mca_res <- MCA(vivienda_cat, graph = FALSE)
fviz_mca_var(mca_res, repel = TRUE)

El análisis de correspondencias múltiples permitió examinar las relaciones estructurales entre las variables categóricas zona, tipo de vivienda y estrato socioeconómico, identificando patrones de asociación dentro del mercado inmobiliario urbano.

La primera dimensión (21.1% de la inercia explicada) refleja principalmente diferencias territoriales y socioeconómicas, evidenciando que ciertas zonas de la ciudad se asocian con determinados niveles de estrato. En particular, se observa una diferenciación clara entre zonas con mayor concentración de estratos altos y aquellas con predominancia de estratos medios.

La segunda dimensión (17% de la inercia explicada) introduce un contraste adicional entre zonas y niveles socioeconómicos, sugiriendo que la configuración espacial de la oferta inmobiliaria no es homogénea y responde a patrones estructurales del mercado urbano.

Asimismo, el tipo de vivienda presenta una diferenciación moderada en el espacio factorial, lo que indica que casas y apartamentos tienden a concentrarse en determinadas zonas y estratos específicos. Estos resultados evidencian que la oferta inmobiliaria no solo depende de características físicas, sino también de dinámicas territoriales y socioeconómicas claramente definidas.

Desde una perspectiva estratégica, estos resultados permiten a la empresa inmobiliaria identificar patrones territoriales en la oferta, facilitando la segmentación comercial según tipo de vivienda y nivel socioeconómico predominante en cada zona.

Este análisis cualitativo complementa los hallazgos del PCA y del clustering, aportando una visión integral del mercado inmobiliario urbano.

Conclusiones