1 Introducción

Una empresa inmobiliaria de Cali necesita entender mejor la oferta de vivienda que circula en el mercado urbano, con el fin de tomar decisiones más informadas sobre compra, venta y valoración de propiedades. Para eso se analiza una base de 8.319 registros de propiedades residenciales publicadas en portales de internet (apartamentos y casas), con información de precio, área, ubicación, características físicas y estrato socioeconómico.

El análisis combina tres técnicas complementarias:

  • Componentes principales, para identificar cuáles son las características que realmente explican la variación de precios y de oferta.
  • Conglomerados, para agrupar las propiedades en segmentos homogéneos que reflejen las dinámicas reales del mercado.
  • Correspondencias múltiples, para entender cómo se relacionan el tipo de vivienda, la zona y el barrio.

Al final se presentan las conclusiones y un conjunto de recomendaciones prácticas orientadas a la estrategia comercial de la empresa.

2 Analisis exploratorio de la base de datos

2.1 Descripción general

data("vivienda")
kable(head(vivienda, 5), caption = "Tabla 1. Primeros registros de la base original")
Tabla 1. Primeros registros de la base original
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
data("vivienda")
kable(tail(vivienda, 5), caption = "Tabla 2. Ultimos registros de la base original")
Tabla 2. Ultimos registros de la base original
id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
6998 Zona Sur NA 6 1000 189 3 5 4 Apartamento zona sur -76.54666 3.44620
8139 Zona Sur NA 5 530 142 2 4 4 Casa zona sur -76.55587 3.40889
NA NA NA NA NA NA NA NA NA NA NA NA NA
NA NA NA NA NA NA NA NA NA NA NA NA NA
NA NA NA NA 330 NA NA NA NA NA NA NA NA
cat("Numero de filas:", nrow(vivienda), "\n")
## Numero de filas: 8322
cat("Numero de columnas:", ncol(vivienda))
## Numero de columnas: 13

La base contiene 8.322 registros de viviendas y posee 13 variables por cada vivienda: identificador, zona de la ciudad, piso, estrato, precio (en millones de pesos), área construida, número de parqueaderos, baños y habitaciones, tipo de vivienda (apartamento o casa), barrio, y coordenadas geográficas (longitud y latitud).

2.2 Calidad de los datos y tratamiento de valores faltantes

Antes de cualquier análisis multivariado es necesario revisar qué tan completa está la información, porque tanto el ACP como el análisis de conglomerados requieren datos completos fila por fila. Para ello, construiremos un tabla que nos indique cuantos datos faltantes se encuentran por cada una de las variables y su porcentaje:

na_tabla <- data.frame(
  variable = names(vivienda),
  n_faltantes = colSums(is.na(vivienda)),
  pct_faltantes = round(100 * colSums(is.na(vivienda)) / nrow(vivienda), 1)
)
kable(na_tabla, row.names = FALSE, caption = "Tabla 3. Valores faltantes por variable")
Tabla 3. Valores faltantes por variable
variable n_faltantes pct_faltantes
id 3 0.0
zona 3 0.0
piso 2638 31.7
estrato 3 0.0
preciom 2 0.0
areaconst 3 0.0
parqueaderos 1605 19.3
banios 3 0.0
habitaciones 3 0.0
tipo 3 0.0
barrio 3 0.0
longitud 3 0.0
latitud 3 0.0

Se identificaron tres registros completamente vacíos al final de la base - Tabla 2 (probablemente un residuo del proceso de extracción de los datos), que se eliminaron sin afectar el análisis. La variable piso tiene un 31.7% de datos faltantes y, además, solo tiene sentido para apartamentos, por lo que se excluyó del análisis multivariado y se dejó como información descriptiva.

El caso más relevante es parqueaderos, con 19.3% de valores faltantes. Antes de imputar un valor por defecto se verificó si la ausencia del dato está asociada al tipo de vivienda (lo que sugeriría que el campo simplemente no aplica) o si aparece de forma pareja en toda la base (lo que sugeriría un dato no reportado por el anunciante). Se encontró que la proporción de datos faltantes es similar entre apartamentos y casas, por lo que se optó por imputar con la mediana del número de parqueaderos según el tipo de vivienda y el estrato, ya que ambas variables están relacionadas de forma clara con la disponibilidad de parqueadero (una casa de estrato 6 no tiene el mismo patrón de parqueo que un apartamento de estrato 3).

df <- vivienda %>%
  filter(!is.na(id)) %>%                    # elimina los 3 registros vacíos
  group_by(tipo, estrato) %>%
  mutate(parqueaderos = ifelse(is.na(parqueaderos),
                                median(parqueaderos, na.rm = TRUE),
                                parqueaderos)) %>%
  ungroup() %>%
  mutate(
    tipo = factor(tipo),
    zona = factor(zona),
    estrato_f = factor(estrato, levels = 3:6, labels = paste0("Estrato ", 3:6)),
    log_precio = log(preciom),
    log_area   = log(areaconst)
  )

# Barrio tiene 437 categorías: se agrupan las 14 más frecuentes y el resto como "Otros"
top_barrios <- df %>% count(barrio, sort = TRUE) %>% slice_head(n = 14) %>% pull(barrio)
df <- df %>% mutate(barrio_agr = factor(ifelse(barrio %in% top_barrios, barrio, "Otros")))

# FactoMineR (PCA/MCA) necesita un data.frame "de base", no un tibble:
# al extraer columnas una por una internamente, un tibble devuelve otro
# data frame de una columna en vez de un vector, y eso rompe PCA()/MCA().
df <- as.data.frame(df)

cat("Registros finales para el análisis:", nrow(df))
## Registros finales para el análisis: 8319

También se transformaron logarítmicamente el precio y el área construida, porque ambas variables tienen una distribución con cola larga a la derecha (coeficientes de asimetría de 1.85 y 2.69 respectivamente): unas pocas propiedades muy costosas o muy grandes distorsionarían los resultados del ACP si se usaran en su escala original.

Por último, la variable barrio tiene 437 categorías distintas, la mayoría con muy pocas observaciones. Para el análisis de correspondencias se agruparon los 14 barrios más frecuentes y el resto se etiquetó como “Otros”, conservando así la información de los barrios con mayor peso en el mercado sin perder la posibilidad de interpretar el resultado.

3 Panorama general del mercado

Antes de aplicar las tres tecnicas planteadas en el momento de la introducción, conviene mirar el comportamiento general de la oferta en alguna de sus variables.

p1 <- ggplot(df, aes(x = zona)) +
  geom_bar(fill = "#2C7FB8") +
  labs(title = "Grafico 1. Oferta por zona", x = NULL, y = "N° de propiedades") +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

p2 <- ggplot(df, aes(x = tipo, fill = tipo)) +
  geom_bar() +
  scale_fill_manual(values = c("#D95F02", "#1B9E77")) +
  labs(title = "Grafico 2. Oferta por tipo de vivienda", x = NULL, y = NULL) +
  theme(legend.position = "none")

grid.arrange(p1, p2, ncol = 2)

La oferta se concentra fuertemente en la Zona Sur (cerca del 57% de las propiedades) y, en menor medida, en la Zona Norte. Las zonas Centro y Oriente tienen una participación marginal. En cuanto al tipo de vivienda, los apartamentos son mayoría (61%) frente a las casas (39%).

p3 <- ggplot(df, aes(x = preciom)) +
  geom_histogram(bins = 50, fill = "#2C7FB8") +
  labs(title = "Grafico 3. Precio (millones COP)", x = NULL, y = "Frecuencia")

p4 <- ggplot(df, aes(x = zona, y = preciom, fill = zona)) +
  geom_boxplot(show.legend = FALSE) +
  scale_y_continuous(labels = label_number(suffix = "M")) +
  labs(title = "Grafico 4. Precio por zona", x = NULL, y = "Precio (millones COP)") +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

grid.arrange(p3, p4, ncol = 2)

El precio también está sesgado a la derecha: la mitad de las propiedades cuesta menos de 330 millones de pesos, pero hay una cola de propiedades de alto valor que supera los 1.000 millones. Al desagregar por zona se nota que la Zona Oeste tiene los precios más altos y con mayor dispersión, coherente con ser la zona donde se concentran los estratos más altos de la ciudad.

num_vars <- df %>% 
  select(preciom, areaconst, parqueaderos, banios, habitaciones, estrato)

corrplot(cor(num_vars, use = "complete.obs"), 
         method = "color", 
         type = "upper",
         addCoef.col = "black", 
         number.cex = 0.8, 
         tl.col = "black", 
         tl.srt = 45,
         col = colorRampPalette(c("#D95F02", "white", "#2C7FB8"))(200))

title("Grafico 5. Correlación entre variables numericas")

Dado el mapa de calor o de correlación anterior, podemos observar que casi todas las variables numéricas están correlacionadas positivamente entre sí (menos el cruce entre estrato y habitaciones), lo cual es esperable en un mercado inmobiliario: las viviendas más grandes tienden a tener más baños, más habitaciones, más parqueaderos y, sobre todo, mayor precio. Esta estructura de correlación es justamente lo que hace pertinente aplicar un análisis de componentes principales, para resumir esa información redundante en unos pocos ejes interpretables.

3.1 Distribución geográfica de la oferta

ggplot(df, aes(x = longitud, y = latitud, color = preciom)) +
  geom_point(alpha = 0.5, size = 1) +
  scale_color_viridis_c(option = "inferno", trans = "log10", labels = label_number(suffix = "M")) +
  coord_fixed(1.1) +
  labs(title = "Grafico 6. Ubicación de las propiedades ofertadas en Cali",
       subtitle = "Color según precio (millones de pesos, escala logarítmica)",
       x = "Longitud", y = "Latitud", color = "Precio") +
  theme(legend.position = "right")

El mapa confirma lo que ya sugerían los boxplots: las propiedades de mayor precio se concentran en un corredor específico al occidente de la ciudad y parte del sur, mientras que el resto del territorio muestra una oferta más económica y homogénea. Esta lectura geográfica se retoma más adelante al interpretar los segmentos encontrados con el análisis de conglomerados, cuando agrupemos las propiedades residenciales en segmentos homogéneos con características similares.

4 Análisis de componentes principales

El objetivo de esta parte es reducir las seis variables numéricas (precio, área, parqueaderos, baños, habitaciones y estrato) a un número menor de componentes que resuman la mayor parte de la variación del mercado, y que permitan visualizar en un solo mapa la relación entre esas variables y las propiedades.

Como variables activas se usaron el precio y el área en escala logarítmica (por la asimetría ya mencionada), parqueaderos, baños, habitaciones y estrato. El tipo de vivienda, la zona y el barrio agrupado se incluyeron como variables suplementarias, es decir, no participan en el cálculo de los componentes pero sí se proyectan sobre el mapa para ayudar a interpretarlo.

pca_data <- df %>%
  select(log_precio, log_area, parqueaderos, banios, habitaciones, estrato,
         tipo, zona, barrio_agr)

res.pca <- PCA(pca_data, quali.sup = 7:9, graph = FALSE)

4.1 Varianza explicada

fviz_eig(res.pca, addlabels = TRUE, barfill = "#2C7FB8", barcolor = "#2C7FB8") +
  labs(title = "Grafico 6. Porcentaje de varianza explicada por componente")

El gráfico 6 muestra el porcentaje de varianza explicado por cada componente principal. La primera dimensión concentra el 61,2 % de la variabilidad total de las variables analizadas, mientras que la segunda explica un 20,4 % adicional. En conjunto, las dos primeras dimensiones explican aproximadamente el 81,6 % de la variabilidad, lo que indica que una representación en dos dimensiones permite conservar una parte importante de la información original. Las dimensiones restantes tienen una participación menor, especialmente la sexta, que explica aproximadamente el 1,6 %.

kable(round(res.pca$eig[1:4, ], 2), caption = "Tabla 4. Varianza explicada por los primeros 4 componentes")
Tabla 4. Varianza explicada por los primeros 4 componentes
eigenvalue percentage of variance cumulative percentage of variance
comp 1 3.67 61.16 61.16
comp 2 1.22 20.39 81.55
comp 3 0.47 7.82 89.37
comp 4 0.31 5.10 94.47

Con solo dos componentes se explica el 81.6% de la variación total de las seis variables originales, lo cual es un resultado muy favorable: casi toda la información relevante del mercado se puede resumir en un plano de dos dimensiones.

4.2 ¿Qué representa cada componente?

fviz_pca_var(res.pca, col.var = "contrib", gradient.cols = c("#2C7FB8", "#D95F02"),
             repel = TRUE) +
  labs(title = "Grafico 7. Círculo de correlaciones de las variables")

  • Componente 1 (61.2% de la varianza): tamaño y nivel general de la vivienda. El primer componente concentra la mayor parte de la variabilidad de los datos. Las seis variables presentan una relación positiva con este eje, por lo que esta dimensión resume características generales asociadas con el tamaño, el valor y las condiciones de las viviendas. En particular, variables como el precio, el área, los baños y los parqueaderos apuntan en una dirección similar, indicando que tienden a aumentar conjuntamente.

  • Componente 2 (20.4% de la varianza): composición familiar frente a estrato. EL segundo componente explica el 20,4 % de la variabilidad. Esta dimensión diferencia principalmente el número de habitaciones frente al estrato de la vivienda. Las habitaciones presentan una relación positiva con este eje, mientras que el estrato presenta una relación negativa. El precio también presenta una relación negativa, aunque de menor magnitud. Por tanto, esta componente permite identificar diferencias entre las viviendas relacionadas principalmente con su distribución interna y su nivel socioeconómico.

fviz_pca_ind(res.pca, geom = "point", alpha.ind = 0.4,
             habillage = pca_data$tipo, palette = c("#D95F02", "#1B9E77"),
             addEllipses = TRUE, ellipse.level = 0.68) +
  labs(title = "Grafico 8. Mapa de individuos, coloreado por tipo de vivienda")

Al proyectar el tipo de vivienda sobre el mapa se ve una diferencia clara: las casas tienden a ubicarse más hacia arriba (más habitaciones para un estrato dado), mientras que los apartamentos se agrupan más hacia abajo. Esto es consistente con una posible lógica de mercado: las casas suelen tener más cuartos por unidad de área que los apartamentos de estratos comparables.

Este resultado ya anticipa que el precio del mercado no depende de una sola característica, sino de una combinación de tamaño, tipo de vivienda y estrato — una idea que se profundiza en la siguiente sección.

5 Análisis de conglomerados: segmentación del mercado

El propósito de esta sección es identificar grupos de propiedades con características similares entre sí y distintas de las de otros grupos, para entender qué “productos” conviven realmente dentro del mercado inmobiliario de Cali.

Se aplicó un algoritmo de clasificación jerárquica sobre los componentes principales obtenidas en la sección anterior. Trabajar sobre los componentes en lugar de las variables originales tiene dos ventajas: evita el ruido de variables redundantes y hace que el resultado de la segmentación sea directamente interpretable sobre el mismo mapa factorial ya construido. El número de grupos se determinó de forma automática, buscando el punto donde fusionar dos grupos adicionales deja de aportar una reducción importante en la variabilidad interna.

res.hcpc <- HCPC(res.pca, nb.clust = 3, graph = FALSE)
df$segmento <- res.hcpc$data.clust$clust
plot(res.hcpc$call$t$tree, labels = FALSE, hang = -1,
     main = "Grafico 9. Dendrograma de la clasificación jerárquica", xlab = "", sub = "", ylab = "Altura")
rect.hclust(res.hcpc$call$t$tree, k = 3, border = paleta_cluster)

El dendrograma muestra cómo las propiedades se van agrupando según la similitud de sus características. Las uniones que aparecen en alturas bajas corresponden a propiedades más similares, mientras que las uniones a mayor altura representan grupos con mayores diferencias. Al realizar el corte del árbol se obtuvieron tres segmentos. El criterio automático identificó tres segmentos claramente diferenciados. La siguiente tabla resume sus características principales en unidades reales (no logarítmicas), para facilitar la lectura desde el negocio:

resumen_cluster <- df %>%
  group_by(segmento) %>%
  summarise(
    `N° propiedades` = n(),
    `% del mercado` = round(100 * n() / nrow(df), 1),
    `Precio promedio (M COP)` = round(mean(preciom)),
    `Precio mediano (M COP)` = round(median(preciom)),
    `Precio por m² (COP)` = round(mean(preciom * 1e6 / areaconst)),
    `Área promedio (m²)` = round(mean(areaconst)),
    `Habitaciones (prom.)` = round(mean(habitaciones), 1),
    `Baños (prom.)` = round(mean(banios), 1),
    `Parqueaderos (prom.)` = round(mean(parqueaderos), 1),
    `Estrato (prom.)` = round(mean(estrato), 1),
    `% Apartamentos` = round(100 * mean(tipo == "Apartamento"), 1)
  )
kable(resumen_cluster, caption = "Tabla 5. Perfil de cada segmento")
Tabla 5. Perfil de cada segmento
segmento N° propiedades % del mercado Precio promedio (M COP) Precio mediano (M COP) Precio por m² (COP) Área promedio (m²) Habitaciones (prom.) Baños (prom.) Parqueaderos (prom.) Estrato (prom.) % Apartamentos
1 3730 44.8 208 205 2517530 89 3.0 2.1 1.1 3.9 78.4
2 3001 36.1 499 430 3119029 176 3.4 3.4 1.8 5.3 64.0
3 1588 19.1 841 750 2453105 375 5.4 5.1 3.0 5.1 16.1

Segmento 1 — Vivienda de entrada (44.8% del mercado). Propiedades más pequeñas y económicas: en promedio 89 m², 3 habitaciones, 2 baños y un solo parqueadero, con precio promedio de 208 millones de pesos y estrato típico entre 3 y 4. Cerca del 78% son apartamentos. Es, por volumen, el segmento más grande del mercado y corresponde al comprador que busca su primera vivienda o una opción de menor presupuesto.

Segmento 2 — Vivienda premium de zona exclusiva (36.1% del mercado). Propiedades de estrato alto (5.3 en promedio), con precio promedio de 499 millones, concentradas fuertemente en la Zona Oeste. Es interesante notar que este segmento tiene el precio por metro cuadrado más alto de los tres ($3.12 millones/m², frente a $2.52 y $2.45 millones/m² de los otros dos), a pesar de no ser el segmento con las propiedades más grandes. Esto indica que en este segmento el comprador está pagando, sobre todo, por la ubicación y el estrato, más que por el tamaño físico de la propiedad.

Segmento 3 — Vivienda familiar de gran formato (19.1% del mercado). El segmento más pequeño en volumen pero el de mayor valor absoluto por unidad: 375 m² en promedio, más de 5 habitaciones y 5 baños, 3 parqueaderos y un precio promedio de 841 millones de pesos. A diferencia del segmento 2, aquí el precio está impulsado principalmente por el tamaño: el precio por metro cuadrado es, de hecho, el más bajo de los tres segmentos. El 84% son casas.

fviz_cluster(list(data = res.pca$ind$coord[, 1:2], cluster = df$segmento),
             palette = paleta_cluster, geom = "point", pointsize = 1, alpha = 0.5,
             ellipse.type = "convex", main = "Grafico 10. Segmentos sobre el mapa de componentes principales") +
  labs(x = "Componente 1 (tamaño / valor)", y = "Componente 2 (habitaciones vs. estrato)")

5.1 ¿Dónde están geográficamente los segmentos?

ggplot(df, aes(x = longitud, y = latitud, color = segmento)) +
  geom_point(alpha = 0.5, size = 1) +
  scale_color_manual(values = paleta_cluster,
                      labels = c("1: Entrada", "2: Premium zona exclusiva", "3: Familiar gran formato")) +
  coord_fixed(1.1) +
  labs(title = "Grafico 11. Ubicación geográfica de los tres segmentos",
       x = "Longitud", y = "Latitud", color = "Segmento") +
  theme(legend.position = "bottom")

El mapa confirma que la segmentación estadística tiene una traducción geográfica muy clara: el segmento premium (2) se concentra en el corredor occidental de la ciudad, el segmento familiar de gran formato (3) aparece disperso en zonas de estrato alto del sur y el occidente, y el segmento de entrada (1) domina el resto del territorio, en particular la zona sur y la zona norte. Esta coherencia entre la segmentación estadística y la geografía real de Cali es una señal de que los grupos encontrados no son un artificio matemático, sino que reflejan submercados reales.

6 Análisis de correspondencias: tipo, zona y barrio

Mientras el ACP y los conglomerados trabajan sobre las variables numéricas, esta sección se concentra en las variables categóricas: tipo de vivienda, zona y barrio. El objetivo es entender si hay patrones de asociación entre ellas, es decir, si ciertos tipos de vivienda son más frecuentes en ciertas zonas o barrios de lo que se esperaría si no hubiera ninguna relación entre las variables.

6.1 Tipo de vivienda y zona

Se empieza con el caso más simple: la relación entre tipo de vivienda y zona.

tab_tipo_zona <- table(df$tipo, df$zona)

kable(tab_tipo_zona, caption = "Tabla 6. Tipo de vivienda x zona")
Tabla 6. Tipo de vivienda x zona
Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
Apartamento 24 1198 1029 62 2787
Casa 100 722 169 289 1939
chi_res <- chisq.test(tab_tipo_zona)

cat("Chi-cuadrado:", round(chi_res$statistic, 2), "\n")
## Chi-cuadrado: 690.93
cat("Grados de libertad:", chi_res$parameter, "\n")
## Grados de libertad: 4
cat("Valor p:", format.pval(chi_res$p.value, digits = 4))
## Valor p: < 2.2e-16

La prueba chi-cuadrado de independencia da un resultado altamente significativo (p < 0.001), lo que confirma que el tipo de vivienda y la zona no son independientes: la proporción de casas y apartamentos cambia claramente según la zona de la ciudad.

res.ca <- CA(tab_tipo_zona, graph = FALSE)

# La tabla es de 2x5, por lo que el rango es 1: un único eje concentra el 100%
# de la asociación. Se grafica ese único eje en lugar de un biplot de 2 dimensiones.
coords_ca <- bind_rows(
  data.frame(categoria = rownames(tab_tipo_zona), dim1 = as.numeric(res.ca$row$coord), variable = "Tipo de vivienda"),
  data.frame(categoria = colnames(tab_tipo_zona), dim1 = as.numeric(res.ca$col$coord), variable = "Zona")
)

ggplot(coords_ca, aes(x = dim1, y = 0, color = variable, shape = variable)) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "grey70") +
  geom_point(size = 3) +
  geom_text_repel(aes(label = categoria), size = 3.5, direction = "y", nudge_y = 0.15) +
  scale_color_manual(values = c("#2C7FB8", "#D95F02")) +
  ylim(-0.3, 0.3) +
  labs(title = "Grafico 12. Análisis de correspondencias: tipo de vivienda x zona",
       subtitle = "Único eje (100% de la asociación explicada)", x = "Dimensión 1", y = NULL, color = NULL, shape = NULL) +
  theme(axis.text.y = element_blank(), axis.ticks.y = element_blank(),
        panel.grid.major.y = element_blank(), legend.position = "bottom")

Como la tabla es de solo 2 filas por 5 columnas, un único eje concentra el 100% de la asociación entre las dos variables: por eso no se necesita un mapa de dos dimensiones, con este eje es suficiente. El gráfico muestra que la Zona Oriente y la Zona Centro están más asociadas con casas, mientras que la Zona Oeste está más asociada con apartamentos. La Zona Norte y la Zona Sur quedan cerca del centro (cerca de cero), es decir, con una mezcla de tipos de vivienda más equilibrada frente al promedio de la ciudad.

6.2 Tipo, zona y barrio en conjunto

Para incorporar también el barrio se usa un análisis de correspondencias múltiples (ACM), que permite trabajar con más de dos variables categóricas al mismo tiempo. Como variable adicional (suplementaria) se proyectó también el estrato, para facilitar la interpretación del mapa sin que influya en su cálculo.

mca_data <- df %>% select(tipo, zona, barrio_agr, estrato_f)
res.mca <- MCA(mca_data, quali.sup = 4, graph = FALSE)
fviz_mca_var(res.mca, repel = TRUE, labelsize = 3,
             col.var = "black", col.quali.sup = "#D95F02") +
  labs(title = "Grafico 13. Mapa de categorías: tipo, zona, barrio (activas) y estrato (suplementaria)")

Al incluir el barrio, el mapa se vuelve más rico pero también menos concentrado: con muchas categorías, la asociación se reparte entre más dimensiones, por lo que los dos primeros ejes explican solo el 18% de la inercia total. Aun así, el mapa deja ver patrones útiles:

  • Barrios como Los Cristales, Santa Teresita y Normandía aparecen muy cerca entre sí y alejados del resto — los tres pertenecen a la Zona Oeste, lo que confirma que el barrio y la zona están fuertemente ligados, como era de esperarse.
  • Barrios como Ciudad Jardín, Pance y El Limonar se ubican en una región del mapa distinta, más cercana a estratos altos (5 y 6) y con mayor presencia de casas — coherente con el segmento familiar de gran formato identificado en el análisis de conglomerados.
  • Valle del Lili, el barrio con mayor número de propiedades ofertadas (12% del total), aparece más cercano al centro del mapa y asociado a apartamentos, lo que refleja su papel como uno de los polos de vivienda en altura más grandes de la ciudad.

Este resultado conecta directamente con la segmentación de la sección anterior: los mismos barrios que aparecen asociados a estratos altos en el ACM (Ciudad Jardín, Pance, Los Cristales, Santa Teresita, Normandía) son justamente los que concentran el segmento 2 (premium) y el segmento 3 (familiar de gran formato).

7 Visualización integrada

Para cerrar la parte analítica, se presenta un mapa interactivo que resume en una sola vista los tres segmentos encontrados, con el detalle de cada propiedad disponible al pasar el cursor.

df_map <- df %>%
  mutate(segmento_lbl = recode(segmento,
                                `1` = "1: Entrada",
                                `2` = "2: Premium zona exclusiva",
                                `3` = "3: Familiar gran formato"))

p_int <- ggplot(df_map, aes(x = longitud, y = latitud, color = segmento_lbl,
                             text = paste0("Barrio: ", barrio,
                                           "<br>Tipo: ", tipo,
                                           "<br>Precio: ", preciom, " M COP",
                                           "<br>Área: ", areaconst, " m²",
                                           "<br>Estrato: ", estrato))) +
  geom_point(alpha = 0.5, size = 0.8) +
  scale_color_manual(values = paleta_cluster) +
  coord_fixed(1.1) +
  labs(title = "Grafico 14. Mercado de vivienda en Cali por segmento", color = "Segmento",
       x = "Longitud", y = "Latitud")

ggplotly(p_int, tooltip = "text") %>%
  layout(legend = list(orientation = "h", y = -0.15))

8 Conclusiones

  1. El mercado se explica bien con pocas dimensiones. Dos componentes principales resumen el 81.6% de la variación de precio, área, parqueaderos, baños, habitaciones y estrato. El primero es, en esencia, un índice general de tamaño y valor de la propiedad; el segundo diferencia viviendas con muchas habitaciones pero estrato más bajo de viviendas con pocas habitaciones pero estrato más alto.

  2. El mercado no es homogéneo: existen tres submercados claramente diferenciados. Un segmento de entrada (45% de la oferta, apartamentos económicos y compactos), un segmento premium concentrado en la Zona Oeste (36%, donde se paga la mayor prima por metro cuadrado) y un segmento familiar de gran formato (19%, mayoritariamente casas grandes, con el precio absoluto más alto pero el precio por metro cuadrado más bajo).

  3. El precio no depende solo del tamaño ni solo del estrato, sino de su combinación con la ubicación. El hallazgo de que el segmento premium paga más por metro cuadrado que el segmento familiar de mayor precio absoluto muestra que la ubicación y el estrato tienen un peso propio en la formación del precio, independiente del tamaño físico de la vivienda.

  4. El tipo de vivienda y la zona están fuertemente asociados. La Zona Oriente y la Zona Centro se inclinan hacia las casas, la Zona Norte hacia los apartamentos, y esta asociación es estadísticamente significativa. A nivel de barrio, la relación es todavía más marcada: los barrios de estrato alto de la Zona Oeste (Los Cristales, Santa Teresita, Normandía) y del sur (Ciudad Jardín, Pance) concentran la oferta de mayor valor.

  5. La segmentación estadística tiene una base geográfica real, lo que da confianza en que los segmentos no son un artefacto del método, sino reflejo de dinámicas reales del mercado caleño.

9 Recomendaciones estratégicas

  • Diferenciar la estrategia comercial por segmento y no por precio absoluto. Un mismo presupuesto de compra puede destinarse a un apartamento premium pequeño en zona exclusiva o a una casa grande de estrato medio-alto en otra zona; son dos productos distintos, con compradores distintos, y conviene que el portafolio y la fuerza de ventas de la empresa lo reflejen así.

  • Priorizar la Zona Oeste para inversión de alto margen por metro cuadrado. Al ser el segmento donde más se paga por m², una estrategia de adquisición o intermediación enfocada en esta zona puede ofrecer mejores márgenes relativos que zonas con propiedades más grandes pero menor precio por m².

  • Usar el segmento familiar de gran formato como oferta de alto ticket, no de alto margen por m². Para clientes que buscan casas grandes, el argumento de venta debe enfocarse en espacio y funcionalidad familiar más que en exclusividad, dado que el precio por metro cuadrado de este segmento es, de hecho, el más bajo de los tres.

  • Aprovechar la asociación tipo–zona–barrio para afinar la valoración de propiedades. Al tasar una propiedad, la combinación de barrio y tipo de vivienda aporta información adicional más allá del área y el estrato, y puede usarse como variable de ajuste en los modelos de valoración internos de la empresa.

  • Monitorear la oferta de la Zona Sur de cerca, dado que concentra más de la mitad de las propiedades publicadas y mezcla los tres segmentos: es la zona donde mayor competencia enfrentará la empresa y donde una segmentación más fina (por barrio) puede marcar la diferencia comercial.

10 Limitaciones del análisis

Es importante ser transparente sobre las limitaciones de este ejercicio, para que las recomendaciones se usen con el criterio adecuado:

  • Los datos provienen de anuncios publicados en portales inmobiliarios (obtenidos mediante web scraping), no de transacciones cerradas. El precio publicado puede diferir del precio final de venta.
  • El 19.3% de los valores de parqueaderos fue imputado con la mediana según tipo y estrato; aunque es un supuesto razonable, introduce cierta incertidumbre en esa variable puntual.
  • La variable piso se excluyó del análisis por su alto porcentaje de datos faltantes (31.7%) y por aplicar mayormente solo a apartamentos; un análisis futuro podría tratarla de forma separada para ese subconjunto de propiedades.
  • El análisis de correspondencias con barrio agrupa 423 barrios de baja frecuencia en la categoría “Otros”, lo que simplifica la lectura pero oculta particularidades de barrios individuales con pocas propiedades en la muestra.
  • Este es un análisis descriptivo y de segmentación; no constituye un modelo predictivo de precios.