Introducción

La empresa inmobiliaria busca comprender el mercado de viviendas urbanas mediante un análisis multidimensional que permita identificar patrones, segmentaciones y relaciones relevantes para la toma de decisiones estratégicas.

Carga y limpieza de datos

Comenzamos por cargar el df y analizar que tan limpios estan y si debemos hacer limpieza adicional para dejarlos lo mejor posible para el primer analisis de componentes principales.

data("vivienda")
glimpse(vivienda)
## Rows: 8,322
## Columns: 13
## $ id           <dbl> 1147, 1169, 1350, 5992, 1212, 1724, 2326, 4386, 1209, 159…
## $ zona         <chr> "Zona Oriente", "Zona Oriente", "Zona Oriente", "Zona Sur…
## $ piso         <chr> NA, NA, NA, "02", "01", "01", "01", "01", "02", "02", "02…
## $ estrato      <dbl> 3, 3, 3, 4, 5, 5, 4, 5, 5, 5, 6, 4, 5, 6, 4, 5, 5, 4, 5, …
## $ preciom      <dbl> 250, 320, 350, 400, 260, 240, 220, 310, 320, 780, 750, 62…
## $ areaconst    <dbl> 70, 120, 220, 280, 90, 87, 52, 137, 150, 380, 445, 355, 2…
## $ parqueaderos <dbl> 1, 1, 2, 3, 1, 1, 2, 2, 2, 2, NA, 3, 2, 2, 1, 4, 2, 2, 2,…
## $ banios       <dbl> 3, 2, 2, 5, 2, 3, 2, 3, 4, 3, 7, 5, 6, 2, 4, 4, 4, 3, 2, …
## $ habitaciones <dbl> 6, 3, 4, 3, 3, 3, 3, 4, 6, 3, 6, 5, 6, 2, 5, 5, 4, 3, 3, …
## $ tipo         <chr> "Casa", "Casa", "Casa", "Casa", "Apartamento", "Apartamen…
## $ barrio       <chr> "20 de julio", "20 de julio", "20 de julio", "3 de julio"…
## $ longitud     <dbl> -76.51168, -76.51237, -76.51537, -76.54000, -76.51350, -7…
## $ latitud      <dbl> 3.43382, 3.43369, 3.43566, 3.43500, 3.45891, 3.36971, 3.4…

De acuerdo al metadata anterior vemos unos valores NA, procedemos a buscar por columna cuantos valores nulos tenemos

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 identificaron valores faltantes en varias columnas. Un detalle importante es que las columnas piso y parqueaderos tienen muchos valores faltantes, los cuales elegimos no eliminar debido a 2 razones:

  1. Son demasiados datos, casi un tercio del dataset, lo cual es perjudicial para nuestro análisis.
  2. La falta de estos datos asumimos que es mayormente debido a que, por ejemplo, una casa no tiene el atributo “piso” o simplemente no está especificado. Para parqueaderos, vimos que la mayoría de anuncios no reportan 0 sino que dejan el campo vacío, convirtiéndolo en valor nulo.

Para estos casos decidimos llenar los valores faltantes con “No aplica”.

Para estos casos decidimos llenar los valores con “No Aplica”.

vivienda_limpia <- vivienda[complete.cases(vivienda[, c('estrato','preciom','areaconst',
                                                          'banios','habitaciones',
                                                          'longitud','latitud','tipo',
                                                          'zona','barrio')]), ]
vivienda_limpia$piso[is.na(vivienda_limpia$piso)] <- "No aplica"
vivienda_limpia$parqueaderos[is.na(vivienda_limpia$parqueaderos)] <- 0
dim(vivienda_limpia)
## [1] 8319   13

ya con esta cantidad de datos limpios procedemos a nuestro analisis de componentes principales.

Análisis de Componentes Principales (PCA)

Procedemos primeramente a seleccionar las columnas con tipo de dato numerico, decidimos dejar por fuera ID por ser solo un identificador y las dimensiones lat y long pues estas las vamos a analizar mejor en un mapa.

De acuerdo a los recursos en el area de reflexion es muy importante que escalemos las unidades a las variables para calcular el PCA (lo que hace es restar la media y las divide por la desviación estándar), R aqui ya viene con esas funciones incorporadas.

vars_pca <- vivienda_limpia[, c("estrato", "preciom", "areaconst", 
                                  "parqueaderos", "banios", "habitaciones")]
res_pca <- PCA(vars_pca, scale.unit = TRUE, graph = FALSE)
res_pca$eig
##        eigenvalue percentage of variance cumulative percentage of variance
## comp 1  3.4153640              56.922733                          56.92273
## comp 2  1.2594349              20.990581                          77.91331
## comp 3  0.4596298               7.660497                          85.57381
## comp 4  0.4345931               7.243218                          92.81703
## comp 5  0.2410646               4.017743                          96.83477

Aqui graficamos el resultado para de manera visual observar que variables son mas representativas para nuestro analisis.

fviz_eig(res_pca, addlabels = TRUE)

fviz_pca_var(res_pca, col.var = "contrib",
             gradient.cols = c("blue", "yellow", "red"), repel = TRUE)

Interpretación: El análisis de componentes principales aplicado sobre las variables numéricas ya estandarizadas que seleccionamos (estrato, preciom, areaconst, parqueaderos, banios, habitaciones), nos permitió reducir la dimensionalidad del problema conservando la mayor parte de la información original.

Los dos primeros componentes explican en conjunto el 77.9% de la varianza total (Dim1: 56.9%, Dim2: 21.0%), lo cual es un porcentaje satisfactorio para trabajar con solo dos dimensiones en lugar de las seis variables originales.

Dimensión 1 (56.9%): Tamaño y valor de la vivienda: todas las variables analizadas (preciom, areaconst, banios, parqueaderos, estrato y habitaciones) presentan cargas positivas y de magnitud similar sobre este eje, como se observa en el gráfico por la dirección hacia la derecha de todas las flechas.

Esto indica que existe una fuerte correlación positiva entre estas variables: a mayor precio, mayor área construida, más baños y más parqueaderos. Este componente puede interpretarse como un índice general de tamaño/valor de la propiedad, donde las viviendas se ordenan de menor a mayor “categoría” inmobiliaria.

Dimensión 2 (21.0%): Contraste entre habitaciones y estrato: en este eje se observa un patrón distinto: habitaciones presenta la carga positiva más alta, mientras que estrato presenta la carga negativa más marcada, ubicándose en direcciones opuestas del plano. Las variables areaconst y banios se mantienen prácticamente neutrales en esta dimensión.

Este comportamiento sugiere una relación inversa entre número de habitaciones y estrato socioeconómico: las viviendas con mayor número de habitaciones tienden a pertenecer a estratos más bajos, mientras que las viviendas de estratos altos tienden a ser más compactas en número de cuartos, aunque de mayor valor por metro cuadrado.

Este hallazgo es consistente con dinámicas comunes del mercado inmobiliario urbano, donde los estratos altos priorizan calidad y ubicación sobre cantidad de espacios, mientras que en estratos bajos predominan viviendas familiares más numerosas en cuartos.

Análisis de Conglomerados (Clusters)

Aqui primeramente volvemos a escalar las unidades a las variables con las que estamos trabajando.

vars_cluster <- scale(vars_pca)
fviz_nbclust(vars_cluster, kmeans, method = "wss") + labs(subtitle = "Método del codo")

fviz_nbclust(vars_cluster, kmeans, method = "silhouette") + labs(subtitle = "Método de la silueta")

Recordemos que el ancho de silueta mide qué tan bien separado está cada punto de los clusters vecinos (valores cercanos a 1 = buena separación). Como vemos en los graficos de ambos metodos observamos un cambio en el cluster 4 por lo cual decidimos elegir este aunque la silueta matemáticamente prefiere k=2, el codo muestra un quiebre claro en k=4, y desde el punto de vista de negocio (segmentar el mercado por zona/estrato) k=4 da resultados mucho más ricos e interpretables que solo 2 grupos.

set.seed(123)
res_kmeans <- kmeans(vars_cluster, centers = 4, nstart = 25)
res_kmeans$size
## [1] 1006 2895  881 3537
res_kmeans$centers
##      estrato     preciom  areaconst parqueaderos     banios habitaciones
## 1  1.0706888  2.04032552  1.5873063    1.7050146  1.3697445    0.4781104
## 2  0.6899251  0.10023766 -0.0939632    0.2101233  0.1687568   -0.1757296
## 3 -0.7170819  0.05693307  0.8877774   -0.2350717  0.9830570    2.0287536
## 4 -0.6906127 -0.67653762 -0.5956852   -0.5983753 -0.7725720   -0.4974763
fviz_cluster(res_kmeans, data = vars_cluster,
             geom = "point", ellipse.type = "convex",
             palette = "jco", ggtheme = theme_minimal())

Tabla de tamaño y porcentaje por cluster

tabla_clusters <- data.frame(
  Cluster = 1:length(res_kmeans$size),
  Tamaño = res_kmeans$size,
  Porcentaje = round(100 * res_kmeans$size / sum(res_kmeans$size), 1)
)
knitr::kable(tabla_clusters, caption = "Tamaño y proporción de cada cluster")
Tamaño y proporción de cada cluster
Cluster Tamaño Porcentaje
1 1006 12.1
2 2895 34.8
3 881 10.6
4 3537 42.5

Interpretación:

El análisis de k-means, aplicado sobre las seis variables numéricas estandarizadas, identificó 4 segmentos de vivienda claramente diferenciados:

Cluster Tamaño % del total Perfil
1 1,006 12.1% Premium/Lujo — estrato alto, precio muy por encima del promedio, área grande, muchos parqueaderos y baños
2 2,895 34.8% Estrato alto, tamaño estándar — estrato por encima del promedio, pero precio, área y habitaciones cercanos al promedio general
3 881 10.6% Familiar numerosa, estrato bajo — estrato por debajo del promedio, pero el mayor número de habitaciones de todos los grupos
4 3,537 42.5% Económicas — todas las variables por debajo del promedio; es el segmento más grande de la oferta

El hallazgo más relevante es que los clusters 2 y 3 validan con datos reales el patrón detectado en el PCA: existe un contraste entre viviendas de estrato alto pero compactas (cluster 2) frente a viviendas de estrato bajo pero con más habitaciones

(cluster 3). Esto confirma que la relación inversa entre estrato y número de habitaciones no es solo un artefacto estadístico del PCA, sino un patrón consistente que también emerge de forma independiente en el análisis de conglomerados.

Adicionalmente, se observa que el mercado está dominado por vivienda económica (cluster 4, 42.5%) y de estrato alto estándar (cluster 2, 34.8%), mientras que los extremos —tanto el segmento premium (12.1%) como el familiar numeroso de estrato bajo (10.6%)— representan nichos más pequeños del mercado.

Análisis de Correspondencia

Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio), para identificar patrones de comportamiento de la oferta en mercado inmobiliario.

tabla_zona_tipo <- table(vivienda_limpia$zona, vivienda_limpia$tipo)
res_ca <- CA(tabla_zona_tipo, graph = FALSE)
res_ca$eig
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.08305442                    100                               100

aqui contamos cuántas propiedades hay para cada combinación de zona y tipo — construye una tabla cruzada (5 zonas x 2 tipos).

Esta tabla de conteos es la base de datos que necesitamos para este analisis, ya que este método trabaja con variables categóricas, no numéricas.

coords <- data.frame(
  categoria = c(names(res_ca$row$coord), rownames(res_ca$col$coord)),
  dim1 = c(res_ca$row$coord, res_ca$col$coord[,1]),
  grupo = c(rep("Zona", length(res_ca$row$coord)), rep("Tipo", nrow(res_ca$col$coord)))
)
ggplot(coords, aes(x = dim1, y = 0, color = grupo, label = categoria)) +
  geom_point(size = 3) + geom_text(vjust = -1) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  theme_minimal() +
  labs(title = "Análisis de Correspondencia: Zona vs Tipo", x = "Dimensión 1", y = "")

Interpretación: Zona Oeste esta más asociada a apartamentos; Centro y Oriente a casas. El Análisis de Correspondencia entre zona y tipo de vivienda arrojó una única dimensión que explica el 100% de la varianza (resultado esperado, dado que tipo es una variable binaria). Las coordenadas obtenidas permiten identificar tres patrones geográficos claros:

Visualización geográfica

vivienda_limpia$cluster <- as.factor(res_kmeans$cluster)

ggplot(vivienda_limpia, aes(x = longitud, y = latitud, color = cluster)) +
  geom_point(alpha = 0.5, size = 1) +
  scale_color_manual(values = c("1" = "#E74C3C", "2" = "#3498DB", 
                                  "3" = "#F1C40F", "4" = "#00FF00"),
                      labels = c("1" = "Premium/Lujo", 
                                 "2" = "Estrato alto, tamaño estándar",
                                 "3" = "Familiar numerosa, estrato bajo",
                                 "4" = "Económicas")) +
  theme_minimal() +
  labs(title = "Distribución geográfica de los segmentos de vivienda",
       x = "Longitud", y = "Latitud", color = "Segmento")

Interpretación: Sur/suroeste = premium y estrato alto; Norte/noreste = económicas

Este hallazgo revela una segmentación geográfica del mercado por tipo de propiedad: el occidente de la ciudad concentra el desarrollo de vivienda vertical (apartamentos), mientras que el centro y oriente mantienen predominantemente vivienda horizontal (casas). Este resultado es consistente con los patrones de urbanización típicos de ciudades intermedias colombianas, donde las zonas de expansión reciente suelen desarrollarse con proyectos de apartamentos, mientras que las zonas más antiguas o consolidadas conservan mayor proporción de vivienda unifamiliar.

Conclusiones y recomendaciones

El análisis del mercado inmobiliario, basado en 8,319 propiedades, permite extraer cuatro conclusiones clave para la toma de decisiones:

  1. El mercado se mueve como un solo bloque de “valor”. Precio, tamaño, número de baños y parqueaderos suben y bajan juntos. En la práctica, esto significa que no existen combinaciones “raras” en el mercado: una propiedad grande casi siempre viene con más baños, más parqueaderos y mayor precio, y viceversa.

  2. A mayor estrato, viviendas más compactas. Se identificó un patrón claro y consistente: las propiedades de estratos altos tienden a tener menos habitaciones que las de estratos bajos, aun cuando su valor es mayor. Esto refleja una lógica de mercado donde el estrato alto compra ubicación y calidad, mientras que el estrato bajo prioriza espacio.

  3. La oferta se concentra en cuatro segmentos bien definidos. Identificamos: Premium (12% del mercado), Estrato alto estándar (35%), Familiar de estrato bajo (11%) y Económico (42%, el segmento más grande). Es decir, casi 3 de cada 4 propiedades del mercado corresponden a los segmentos económico y de estrato alto estándar, dejando los extremos (premium y familiar) como nichos más pequeños.

  4. La ciudad está dividida geográficamente por tipo y nivel de vivienda. El sur y suroeste concentran la vivienda premium y de estrato alto; el norte y noreste concentran la vivienda económica. Además, la zona occidental se especializa en apartamentos, mientras que el centro y oriente predominan en casas.

Recomendaciones

Para inversión y desarrollo:

El segmento económico, al ser el más grande, es también el más competido — es probable que ofrezca menores márgenes. El segmento “Familiar de estrato bajo” (viviendas grandes en estrato bajo) representa una oportunidad menos explotada, con buen tamaño de mercado y menor competencia. La Zona Oeste es el lugar natural para nuevos proyectos de apartamentos; el Centro y Oriente son más aptos para vivienda tipo casa.

Para ventas y mercadeo:

Como el precio, el tamaño y las comodidades (baños, parqueaderos) van siempre de la mano, conviene promocionar las propiedades destacando estos atributos en conjunto, no por separado — así es como el comprador realmente percibe el valor. Para atraer compradores familiares de estrato bajo que buscan más espacio, conviene enfocar la oferta en las zonas donde se concentra este segmento.

Próximos pasos sugeridos:

Profundizar el análisis por barrio (no solo por zona) para afinar aún más la segmentación geográfica. Incorporar datos de tiempo en el mercado (cuánto tarda en venderse cada tipo de propiedad) para entender qué segmentos rotan más rápido y cuáles se quedan estancados.