Preparación del entorno

#install.packages("devtools")
#devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
library(paqueteMODELOS)


paquetes <- c("devtools", "tidyverse", "FactoMineR", "factoextra",
              "cluster", "corrplot", "ggrepel", "scales", "gridExtra",
              "knitr", "VIM")



nuevos <- paquetes[!(paquetes %in% installed.packages()[, "Package"])]
if (length(nuevos) > 0) install.packages(nuevos, dependencies = TRUE)


library(tidyverse)    
library(FactoMineR)   
library(factoextra)   
library(cluster)      
library(corrplot)     
library(ggrepel)      
library(scales)       
library(gridExtra) 
library(patchwork)
library(VIM)
library(stringr)
library(stringi)
library(knitr)
library(kableExtra)
library(naniar)
library(dplyr)


set.seed(123)

Contexto

La base de datos vivienda contiene información de oferta de propiedades en la ciudad de Cali, con variables de ubicación (zona, barrio, piso), características físicas (área construida, número de baños, habitaciones, parqueaderos), variables socioeconómicas (estrato) y comerciales (precio en millones).

El objetivo de este análisis es aplicar técnicas de estadística multivariada como Análisis de Componentes Principales, Análisis de Conglomerados y Análisis de Correspondencias, para identificar los factores que más explican la variación de precios, segmentar la oferta en grupos homogéneos y entender cómo se relacionan el tipo de vivienda, la zona y el barrio, de forma que la dirección de la empresa cuente con evidencia visual y cuantitativa para la toma de decisiones.

Diccionario de datos

Variable Tipo Descripción
id Cuantitativa discreta (ID) Identificador único de cada vivienda/registro en la base
zona Cualitativa nominal Zona geográfica de la ciudad donde se ubica la vivienda
barrio Cualitativa nominal Barrio específico dentro de la zona
tipo Cualitativa nominal Tipo de inmueble (casa / apartamento)
estrato Cualitativa ordinal Estrato socioeconómico de la vivienda
piso Cualitativa ordinal Piso en el que se ubica la unidad
preciom Cuantitativa continua Precio de venta de la vivienda, en millones de pesos colombianos (COP)
areaconst Cuantitativa continua Área construida de la vivienda, en metros cuadrados (m²)
habitaciones Cuantitativa discreta Número de habitaciones/alcobas
banios Cuantitativa discreta Número de baños
parqueaderos Cuantitativa discreta Número de parqueaderos asignados a la vivienda
latitud Cuantitativa continua Coordenada geográfica de latitud de la vivienda
longitud Cuantitativa continua Coordenada geográfica de longitud de la vivienda

Carga y exploración inicial de los datos

data("vivienda")
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
#dim(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…

La base de datos está compuesta por 8.322 registros y 13 variables divididas entre cualitativas y cuantitativas, por lo que se debe tener cuidado a la hora de hacer uso de la técnica que se va a ajustar teniendo en cuenta qué tipos de datos admite cada una.

Análisis Univariado

# =============================================================================
# BOXPLOTS DE VARIABLES CUANTITATIVAS 
# =============================================================================

vars_cuanti <- vivienda %>%
  select(preciom, areaconst, parqueaderos, banios, habitaciones, latitud, longitud) %>%
  pivot_longer(cols = everything(), names_to = "variable", values_to = "valor")

ggplot(vars_cuanti, aes(x = variable, y = valor, fill = variable)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.3, outlier.size = 0.8) +
  facet_wrap(~ variable, scales = "free", ncol = 3) +  # "free" = cada panel con su propio rango
  labs(title = "Distribución de las variables cuantitativas",
       x = NULL, y = NULL) +
  theme_minimal() +
  theme(legend.position = "none",
        strip.text = element_text(face = "bold"),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank())

En general, se puede observar que todas las variables cuantitativas presentan una asimetría positiva (cola a la derecha) con outliers marcados por encima del bigote superior(a excepción de la variable longitud que tiene algunos por debajo). Esto sugiere la presencia de un segmento reducido de propiedades de alto valor (posiblemente estratos altos o zonas exclusivas) que se aleja considerablemente del resto del mercado. En contraste, las coordenadas geográficas (latitud, longitud) muestran una distribución más simétrica y sin atípicos relevantes, y su rango (3.33°–3.50° N, -76.59° a -76.46° O) es consistente con la extensión geográfica del municipio de Santiago de Cali.

Especificamente para estos casos de las variables de preciom y areaconst de manera individual los valores extremos son posibles, pero se verifica si son coherentes con las demás variables, es decir, si los valores atípicos realmente corresponden a viviendas ubicadas en una mejor zona y con un área construida amplia.

Para revisar lo anterior se crea la variable precio_m2 (precio de venta / área construida) porque el precio absoluto de una vivienda confunde efecto de tamaño con efecto de valorización por ubicación/estrato. Esta variable derivada permite comparar propiedades de tamaños distintos en una misma escala y es el indicador estándar utilizado en el sector inmobiliario para el análisis de valoración.

vivienda <- vivienda %>%
  mutate(precio_m2 = preciom / areaconst)

#sum(is.na(vivienda$precio_m2))
#sum(is.na(vivienda$preciom) | is.na(vivienda$areaconst))

summary(vivienda$precio_m2)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##  0.1461  1.9167  2.6400  2.7222  3.3795  9.4681       3
# Revisar los casos más extremos de precio y área
vivienda %>%
  arrange(desc(preciom)) %>%
  select(id, zona, tipo, estrato, areaconst, preciom, precio_m2) %>%
  head(15)
## # A tibble: 15 × 7
##       id zona       tipo        estrato areaconst preciom precio_m2
##    <dbl> <chr>      <chr>         <dbl>     <dbl>   <dbl>     <dbl>
##  1  6100 Zona Oeste Casa              5       800    1999      2.50
##  2  7510 Zona Oeste Casa              6       400    1950      4.88
##  3  4609 Zona Oeste Apartamento       6       450    1950      4.33
##  4  7872 Zona Oeste Casa              6       400    1950      4.88
##  5  4564 Zona Norte Casa              5       734    1940      2.64
##  6  5861 Zona Sur   Casa              6       320    1900      5.94
##  7  2758 Zona Sur   Casa              6       450    1900      4.22
##  8  3202 Zona Sur   Casa              6       335    1900      5.67
##  9  3652 Zona Sur   Casa              6       850    1900      2.24
## 10  4576 Zona Sur   Casa              6       450    1900      4.22
## 11  4731 Zona Sur   Casa              6       700    1900      2.71
## 12  6817 Zona Sur   Casa              6       470    1900      4.04
## 13  4308 Zona Sur   Casa              6      1092    1900      1.74
## 14  6772 Zona Sur   Casa              6       335    1900      5.67
## 15  8020 Zona Oeste Apartamento       6       261    1900      7.28

Teniendo en cuenta los 15 casos de viviendas con precio más altos, estos cuentan con un precio_m2 que va de 1.74 a 7.28, donde la mayoría están cercanos o por encima de la mediana general. Además, todos son de estratos 5 o 6, en zonas como Oeste, Norte o Sur, que tienden a ser de mayor valor. Es decir, que este es un patrón consistente para los precios altos.

vivienda %>%
  arrange(desc(areaconst)) %>%
  select(id, zona, tipo, estrato, areaconst, preciom, precio_m2) %>%
  head(15)
## # A tibble: 15 × 7
##       id zona         tipo  estrato areaconst preciom precio_m2
##    <dbl> <chr>        <chr>   <dbl>     <dbl>   <dbl>     <dbl>
##  1  3324 Zona Oriente Casa        3      1745     255     0.146
##  2  5396 Zona Sur     Casa        6      1600    1600     1    
##  3  5684 Zona Sur     Casa        6      1586    1800     1.13 
##  4   315 Zona Sur     Casa        6      1500    1650     1.1  
##  5  5467 Zona Sur     Casa        6      1500    1500     1    
##  6   534 Zona Norte   Casa        3      1440     370     0.257
##  7  1017 Zona Oriente Casa        3      1365     200     0.147
##  8  5016 Zona Sur     Casa        6      1250    1500     1.2  
##  9    37 Zona Sur     Casa        5      1200    1450     1.21 
## 10  5474 Zona Oeste   Casa        5      1200    1200     1    
## 11  4349 Zona Norte   Casa        5      1188     650     0.547
## 12  4130 Zona Sur     Casa        6      1100    1500     1.36 
## 13  4308 Zona Sur     Casa        6      1092    1900     1.74 
## 14  6433 Zona Sur     Casa        6      1090    1800     1.65 
## 15  5978 Zona Sur     Casa        6      1050    1600     1.52

Por otro lado, al revisar los casos tomando los de mayor área construida, se observa que hay tres casos pertenecientes al estrato 3. Cuando se compara el valor mínimo de las descriptivas generales de la variable precio_m2 se observa que toma un valor de 0.146 que corresponde exactamente al registro id= 3324, el que cuenta con mayor área construida, mostrando un patrón de ser una casa grande, pero a un precio por metro cuadrado muy bajo.

Por lo tanto, se verifica si esto es un patrón consistente en estrato 3 o son apenas tres registros aislados que rompen el patrón y habría que realizar alguna modificación.

# Buscar TODOS los casos con precio_m2 anormalmente bajo
vivienda %>%
  filter(precio_m2 < quantile(precio_m2, 0.01, na.rm = TRUE)) %>%  # percentil 1 más bajo
  select(id, zona, tipo, estrato, areaconst, preciom, precio_m2) %>%
  arrange(precio_m2)
## # A tibble: 84 × 7
##       id zona         tipo        estrato areaconst preciom precio_m2
##    <dbl> <chr>        <chr>         <dbl>     <dbl>   <dbl>     <dbl>
##  1  3324 Zona Oriente Casa              3      1745     255     0.146
##  2  1017 Zona Oriente Casa              3      1365     200     0.147
##  3   921 Zona Oriente Casa              3       870     190     0.218
##  4   534 Zona Norte   Casa              3      1440     370     0.257
##  5  6472 Zona Sur     Apartamento       5       605     170     0.281
##  6  6121 Zona Sur     Apartamento       5       932     299     0.321
##  7  2732 Zona Sur     Casa              4       465     175     0.376
##  8  2344 Zona Oriente Casa              3       600     250     0.417
##  9  1106 Zona Oriente Casa              3       350     150     0.429
## 10   243 Zona Norte   Casa              3       435     190     0.437
## # ℹ 74 more rows
# ¿Se concentran en estrato 3? ¿En zonas específicas?
vivienda %>%
  filter(precio_m2 < 1) %>%
  count(zona, estrato, sort = TRUE)
## # A tibble: 15 × 3
##    zona         estrato     n
##    <chr>          <dbl> <int>
##  1 Zona Oriente       3    82
##  2 Zona Sur           3    27
##  3 Zona Norte         3    21
##  4 Zona Sur           4    15
##  5 Zona Norte         5    13
##  6 Zona Sur           5     7
##  7 Zona Sur           6     6
##  8 Zona Norte         4     5
##  9 Zona Centro        3     3
## 10 Zona Centro        4     2
## 11 Zona Oeste         3     2
## 12 Zona Oeste         4     2
## 13 Zona Oeste         5     1
## 14 Zona Oriente       4     1
## 15 Zona Oriente       5     1
# Comparar precio_m2 promedio por estrato (¿estrato 3 es sistemáticamente bajo,
# o son solo estos 2-3 casos aislados?)
vivienda %>%
  group_by(estrato) %>%
  summarise(precio_m2_mediana = median(precio_m2, na.rm = TRUE),
            precio_m2_min = min(precio_m2, na.rm = TRUE),
            n = n())
## # A tibble: 5 × 4
##   estrato precio_m2_mediana precio_m2_min     n
##     <dbl>             <dbl>         <dbl> <int>
## 1       3              1.71         0.146  1453
## 2       4              2.5          0.376  2129
## 3       5              2.82         0.281  2750
## 4       6              3.66         0.85   1987
## 5      NA             NA          Inf         3

Con lo anterior se puede confirmar que los tres casos no son errores puntuales, sino un patrón real y sistemático de estrato 3.

En particular, si fueran errores se esperaría tener solo 2 o 3 casos aislados que rompen el patrón en el estrato 3, pero se observa que la mayoría de los casos donde precio_m2 \(< 1\) están en estrato 3 e incluyen zonas como Oriente, Sur, Norte y algunos en el Centro. Además, se observa que la mediana de precio_m2 aumenta de forma consistente dependiendo el estrato, es decir que es coherente que el que tenga menor valor corresponda al estrato 3.

Se identificó entonces que los valores más bajos de precio_m2 se concentran de forma sistemática en zona Oriente y estrato 3, siendo consistente con zonas históricamente populares de la ciudad y es común encontrar lotes o casas construidas sobre terrenos grandes, pero con un valor de mercado bajo por metro cuadrado.

Antes de proceder al análisis de las variables cualitativas, se decide revisar particularmente la variable Barrio ya que hay algunos casos de barrios duplicados como “caney”/“el caney” y “cristales”/“los cristales”, por lo que se hace necesario estandarizarlos. (ver lista de barrios en el Anexo C: Listado de barrios originales)

Para estandarizar los datos se quitan los caracteres especiales como tildes, se dejan todos los nombres en minúscula y sin espacios, y se dejan solo los nombres correspondientes para no generar duplicados. (ver Anexo D: Tabla de equivalencias de estandarización de barrios)

vivienda <- vivienda %>%
  mutate(
    # Paso 0: corregir problemas de codificación conocidos ANTES de cualquier otra limpieza
    barrio_fix = barrio %>%
      iconv(from = "UTF-8", to = "UTF-8", sub = "") %>%   # descarta bytes corruptos ilegibles
      str_to_lower() %>%
      str_trim() %>%
      str_squish(),

    # Paso 1: clave de comparación -> sin tildes, sin espacios, sin artículos
    # (esta clave NUNCA se muestra, solo sirve para agrupar duplicados)
    barrio_clave = barrio_fix %>%
      stri_trans_general("Latin-ASCII") %>%     # quita tildes: "río" -> "rio", "pérez" -> "perez"
      str_remove("^urbanizaci[oó]n\\s+") %>%
      str_remove("^(el|la|los|las)\\s+") %>%
      str_remove_all("\\s+")                    # quita TODOS los espacios: "agua blanca" -> "aguablanca"
  )

# Paso 2: dentro de cada clave, elegir como nombre oficial la variante más frecuente
mapa_barrios <- vivienda %>%
  count(barrio_clave, barrio_fix, sort = TRUE) %>%
  group_by(barrio_clave) %>%
  slice_max(n, n = 1, with_ties = FALSE) %>%   # la variante más común de cada grupo
  ungroup() %>%
  select(barrio_clave, barrio_std = barrio_fix)

# Paso 3: unir de vuelta para tener el nombre estandarizado definitivo
vivienda <- vivienda %>%
  left_join(mapa_barrios, by = "barrio_clave")
vivienda %>%
  filter(barrio_clave %in% c("aguablanca", "alamedadelrio", "alferezreal")) %>%
  distinct(barrio, barrio_std, barrio_clave)
## # A tibble: 5 × 3
##   barrio          barrio_std      barrio_clave 
##   <chr>           <chr>           <chr>        
## 1 agua blanca     aguablanca      aguablanca   
## 2 aguablanca      aguablanca      aguablanca   
## 3 alameda del río alameda del río alamedadelrio
## 4 alameda del rio alameda del río alamedadelrio
## 5 alferez real    alferez real    alferezreal
# Verifica la codificación actual del vector
Encoding(vivienda$barrio) %>% table()
## .
## unknown   UTF-8 
##    7055    1267
# Si aparece "unknown" o "latin1" en vez de "UTF-8", fuerza la conversión
vivienda$barrio <- iconv(vivienda$barrio, from = "latin1", to = "UTF-8")
n_distinct(vivienda$barrio_std)
## [1] 357

Tras la revisión a la base de datos que contenía originalmente 437 valores distintos en la variable barrio, se evidenciaron inconsistencias de escritura, diferencias en el uso de tildes, espacios y problemas de codificación de caracteres especiales, que generaban duplicidad de categorías correspondientes al mismo barrio. Tras estandarizar los nombres, el número de barrios distintos se redujo a 357. Aun así, la variable mantiene alta fragmentación: para el Análisis de Correspondencias Múltiples se agruparon los barrios menos frecuentes en la categoría “Otros”, conservando únicamente los 15 barrios con mayor número de viviendas.

# =============================================================================
# DIAGRAMAS DE BARRAS DE VARIABLES CUALITATIVAS 
# =============================================================================
# Se agrupan los barrios poco frecuentes en "Otros" porque son
#demasiadas categorías con pocos casos que distorsionan el analisis y las visualizaciones
top_barrios <- vivienda %>% 
  count(barrio_std, sort = TRUE) %>%
  slice_head(n = 15) %>%
  pull(barrio_std)

vivienda<- vivienda %>%
  mutate(barrio_agr = fct_other(barrio_std, keep = as.character(top_barrios),
                                 other_level = "Otros"))


# Función que arma un diagrama de barras con conteo + porcentaje sobre cada barra
graf_barras <- function(datos, var, titulo) {
  datos %>%
    count(.data[[var]]) %>%
    mutate(pct = n / sum(n) * 100,
           etiqueta = paste0(n, "\n(", round(pct, 1), "%)")) %>%
    ggplot(aes(x = reorder(.data[[var]], -n), y = n)) +
    geom_col(fill = "steelblue", alpha = 0.85) +
    geom_text(aes(label = etiqueta), vjust = -0.15, size = 3) +
    labs(title = titulo, x = NULL, y = "Frecuencia") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 30, hjust = 1, size= 9),
          plot.margin = margin(t = 10, r = 5, b = 5, l = 5)) +
    scale_y_continuous(expand = expansion(mult = c(0, 0.28)))  # espacio para la etiqueta
}

g_zona    <- graf_barras(vivienda, "zona",    "Zona")
g_tipo    <- graf_barras(vivienda, "tipo",    "Tipo de vivienda")
g_estrato <- graf_barras(vivienda, "estrato", "Estrato")
g_barrio  <- graf_barras(vivienda, "barrio_agr", "Barrio (agrupado, top 15 + Otros)")
# Panel: fila superior con zona/tipo/estrato (3 columnas), fila inferior
# con barrio a todo el ancho y más alto (para que quepan las 16 categorías)

(g_zona | g_tipo | g_estrato) / g_barrio +
  plot_layout(heights = c(1, 1.4)) +   # la fila de barrio ocupa más espacio vertical
  plot_annotation(title = "Distribución de las variables cualitativas")

Se puede observar que hay una fuerte dominancia en la zona Sur (56.8%), que junto con la zona Norte acumulan alrededor del 80% de la base. En cuanto al tipo de vivienda hay una proporción razonablemente equilibrada entre casas y apartamentos.

También se evidencia que no hay presencia de estratos 1 ni 2 y que la mayoría hacen parte del estrato 5, sin embargo, se puede considerar una distribución relativamente pareja entre los estratos 4, 5, 6, no hay un estrato que domine en gran manera.

A nivel de Barrio, la oferta está fragmentada, aunque existen 357 barrios distintos (tras estandarizar), uno solo (Valle de Lili) concentra el 12.1% de las viviendas y el 47.2% restante se distribuye en cientos de barrios con presencia marginal, lo que llevó a agruparlos en la categoría ‘Otros’ para análisis posteriores.

vivienda %>%
  filter(str_detect(barrio, "lferez|lfV")) %>%
  distinct(barrio, barrio_fix, barrio_clave, barrio_std)
## # A tibble: 2 × 4
##   barrio                barrio_fix            barrio_clave        barrio_std    
##   <chr>                 <chr>                 <chr>               <chr>         
## 1 alferez real          alferez real          alferezreal         alferez real  
## 2 hacienda alferez real hacienda alferez real haciendaalferezreal hacienda alfe…

Análisis bivariado

vivienda %>%
  filter(!is.na(zona), !is.na(tipo)) %>%
  ggplot(aes(x = zona, fill = tipo)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Proporción de tipo de vivienda por zona",
       x = NULL, y = "Proporción", fill = "Tipo") +
  theme_minimal()

El gráfico permite observar que varía la presencia de casas o apartamentos dependiendo la zona donde se encuentre. En la zona Oriente y Centro predominan las casas con un 83% y 81% respectivamente. Por otro lado, en la zona Oeste predominan los apartamentos (85%), mientras que en las zonas Norte y Sur están mucho más equilibradas con una mezcla cercana a 60/40 a favor de apartamentos.

vivienda %>%
  filter(!is.na(zona), !is.na(estrato)) %>%
  ggplot(aes(x = zona, fill = as.factor(estrato))) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Proporción de estrato de vivienda por zona",
       x = NULL, y = "Proporción", fill = "Estrato") +
  theme_minimal()

Analizando los estratos que se encuentran en cada zona, se ve un patrón marcado mostrando que la variable zona no solo identifica un aspecto geográfico sino que también está muy correlacionada a nivel socioeconómico. La zona Oeste tiene mayor proporción del estrato 6, siendo la zona de mayor poder adquisitivo, sin apenas presencia del estrato 3. En cuanto a la zona Centro y Oriente son casi exclusivamente del estrato 3. Por su parte la zona Sur tiene una mezcla entre los estratos 4, 5, 6 con una baja proporción del estrato 3 y la zona Norte es la más heterogénea de todas con una mezcla de proporciones entre los cuatro estratos.

vivienda %>%
  filter(!is.na(zona), !is.na(piso)) %>%
  ggplot(aes(x = zona, fill = piso)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Proporción de piso por zona",
       x = NULL, y = "Proporción", fill = "Tipo") +
  theme_minimal()

Este gráfico es coherente con lo que se había analizado anteriormente del tipo de vivienda, donde en las zonas de centro y oriente predominan las casas, por lo que coincide el hecho de que estas solo tengan un piso o incluso 3 y rara vez superan los 3 niveles, que se observan casos más que todo en la zona Centro que es donde pueden presentarse edificios empresariales de hasta 11 pisos. Las zonas Norte, Sur y Oeste son las únicas que llegan hasta el piso 12 con una distribución mucho más repartida entre todos los niveles, lo cual es coherente porque son las zonas donde hay mayor presencia de edificios.

# Precio por zona
vivienda %>%
  filter(!is.na(zona), !is.na(preciom)) %>%
  ggplot(aes(x = reorder(zona, preciom, median), y = preciom, fill = zona)) +
  geom_boxplot(alpha = 0.8, outlier.alpha = 0.2) +
  scale_y_continuous(labels = scales::comma) +
  labs(title = "Precio de vivienda por zona", x = NULL, y = "Precio (millones COP)") +
  theme_minimal() + theme(legend.position = "none")

El precio mediano crece de forma escalonada según la zona, en el mismo orden que ya se había identificado por estrato. Zona Oriente (~220 millones) y Zona Centro (~310 millones) muestran las medianas más bajas y cajas más compactas, seguidas de Zona Norte y Zona Sur (~320-340 millones, con numerosos atípicos superiores hasta cerca de 2,000 millones), y finalmente Zona Oeste, que se despega claramente del resto con una mediana de ~580 millones y una caja mucho más ancha (desde ~400 hasta ~900 millones), sin apenas atípicos por encima del bigote. En este último punto se puede señalar que mientras las zonas Norte y Sur tienen colas de atípicos muy largas y densas (muchas viviendas puntuales muy caras rompiendo con el resto del patrón de su zona), en Oeste el precio alto no es atípico sino que es común al segmento completo, lo que confirma que es una zona homogéneamente superior.

# Precio_m2 por estrato 
vivienda%>%
  filter(!is.na(estrato), !is.na(precio_m2)) %>%
  ggplot(aes(x = reorder(estrato, precio_m2, median), y = precio_m2, fill = estrato)) +
  geom_boxplot(alpha = 0.8, outlier.alpha = 0.2) +
  labs(title = "Precio por m² según estrato", x = "Estrato", y = "Precio/m² (millones COP)") +
  theme_minimal() + theme(legend.position = "none")

Esta gráfica confirma la existencia de un patrón de valorización creciente y consistente. La mediana sube de forma monótona de 1.71 millones/\(m^2\) en estrato 3 a 3.66 millones/\(m^2\) en estrato 6, con las cajas también desplazándose hacia arriba sin solaparse casi nada entre estratos consecutivos, es decir, la separación no es solo en el promedio, sino en la distribución completa. El estrato 3 es también el único que muestra atípicos hacia abajo (el de menor \(m^2\) que se identificó anteriormente), consistente con el segmento de casas grandes de bajo valor por metro.

# Área construida por tipo de vivienda
vivienda %>%
  filter(!is.na(areaconst), !is.na(tipo)) %>%
  ggplot(aes(x = reorder(tipo, areaconst, median), y = areaconst, fill = tipo)) +
  geom_boxplot(alpha = 0.8, outlier.alpha = 0.2) +
  labs(title = "Área construida según tipo de vivienda", x = NULL, y = "Área (m²)") +
  theme_minimal() + theme(legend.position = "none")

Las casas muestran en general ser más grandes que los apartamentos. La mediana de casa (~230 \(m^2\)) casi triplica la de apartamento (~80 \(m^2\)) y la caja completa de casa está desplazada muy por encima de la de apartamento, con apenas superposición entre ambas distribuciones. Los apartamentos muestran una caja comprimida cerca de cero con una cola densa de atípicos hacia arriba (edificios de gran formato o dúplex atípicos), mientras que las casas tienen una dispersión natural mucho mayor incluso dentro del rango “normal” (bigote superior cercano a 700 \(m^2\)), reflejo de que el terreno de una casa varía mucho más que la planta de un apartamento estandarizado.

vivienda %>%
  filter(!is.na(longitud), !is.na(latitud), !is.na(zona)) %>%
  ggplot(aes(x = longitud, y = latitud, color = zona)) +
  geom_point(alpha = 0.4, size = 0.8) +
  coord_fixed() +
  labs(title = "Distribución geográfica de las viviendas por zona",
       x = "Longitud", y = "Latitud", color = "Zona") +
  theme_minimal()

Se observa que los valores de latitud y longitud corresponden correctamente con las zonas específicas de la ciudad, formando segmentos bien delimitados. La zona centro por su reducido tamaño muestral, se observa como un núcleo geográfico pequeño rodeado por las demás zonas. Se identifica una franja de transición en el sector central de la ciudad donde las zonas Norte, Oeste, Oriente y Centro se entremezclan, reflejando probablemente los límites administrativos del área metropolitana más densa.

Matriz de correlaciones

mat_cor<- vivienda %>%
  select(preciom, areaconst, precio_m2, parqueaderos, banios, habitaciones) %>%
  cor(use = "pairwise.complete.obs")

corrplot(mat_cor, method = "color", type = "upper", addCoef.col = "black",
         tl.col = "black", tl.srt = 45, number.cex = 0.7,
         title = "Correlación entre variables numéricas", mar = c(0, 0, 2, 0))

La matriz de correlación confirma la existencia de un grupo de variables asociadas al tamaño/magnitud de la vivienda (preciom, areaconst, parqueaderos, banios), con correlaciones entre 0.57 y 0.69, que se esperaría que posteriormente definan el primer componente del ACP. Se destaca que banios (r=0.67) explica el precio considerablemente mejor que habitaciones (r=0.26), sugiriendo que el número de baños es un mejor proxy de la categoría de la vivienda. La variable precio_m2, por su parte, muestra correlaciones bajas o negativas con las demás variables (r=-0.27 con área, r=-0.33 con habitaciones), confirmando que captura una dimensión de valorización independiente del tamaño, consistente con economías de escala en el precio por metro cuadrado, y validando su inclusión como variable diferenciada en el análisis multivariado.

Preparación de los datos

Valores faltantes por variable

faltantes <- colSums(is.na(vivienda)) %>% sort(decreasing = TRUE)
faltantes
##         piso parqueaderos           id         zona      estrato    areaconst 
##         2638         1605            3            3            3            3 
##       banios habitaciones         tipo       barrio     longitud      latitud 
##            3            3            3            3            3            3 
##    precio_m2   barrio_fix barrio_clave   barrio_std   barrio_agr      preciom 
##            3            3            3            3            3            2
ggplot(data.frame(variable = names(faltantes), n_na = faltantes),
       aes(x = reorder(variable, n_na), y = n_na)) +
  geom_col(fill = "steelblue") +
  coord_flip() +
  labs(title = "Datos faltantes por variable",
       x = NULL, y = "N° de valores faltantes") +
  theme_minimal() -> g_na
g_na

En general, las variables no tienen gran cantidad de datos faltantes a excepción de parqueaderos y pisos que cuentan con un 19% y 31% de datos faltantes respectivamente.

Como la mayoría de variables tienen 3 datos faltantes, se sospecha que pueden coincidir los 3 registros con información faltante.

# Identificar y excluir específicamente las filas completamente vacías
filas_vacias <- which(is.na(vivienda$zona) & is.na(vivienda$estrato) &
                       is.na(vivienda$barrio) & is.na(vivienda$tipo))
filas_vacias 
## [1] 8320 8321 8322
vivienda <- vivienda %>%
  filter(!row_number() %in% filas_vacias)

dim(vivienda)  # 8319 filas en vez de 8322
## [1] 8319   18

Se identificó que los 2-3 valores faltantes presentes en la mayoría de las variables correspondían, en realidad, a las mismas tres observaciones (filas 8320-8322), las cuales se encontraban completamente vacías a excepción de un valor de precio en un caso. Dado que estas filas no contienen información sustantiva sobre las características de la vivienda, no corresponden a un caso de datos faltantes susceptible de imputación, sino a registros sin contenido analítico, por lo que se excluyeron del análisis (8,322 → 8,319 observaciones).

Con los datos restantes, se comprueba qué tipos de datos faltantes se tienen en las variables restantes y de esta forma hacer el tratamiento correspondiente.

colSums(is.na(vivienda))
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0         2635            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##         1602            0            0            0            0            0 
##      latitud    precio_m2   barrio_fix barrio_clave   barrio_std   barrio_agr 
##            0            0            0            0            0            0

Prueba formal de MCAR (Test de Little)

\[ H_0: \text{Los datos faltantes son MCAR} \]

\[ H_1: \text{Los datos faltantes no son MCAR} \]

#se comprueba solo usando las variables originales
vivienda %>%
  select(id, zona, piso, estrato, preciom, areaconst, parqueaderos,
         banios, habitaciones, tipo, barrio, longitud, latitud) %>%
  mcar_test()  # H0: los datos SON MCAR. p < 0.05 -> se rechaza MCAR
## # A tibble: 1 × 4
##   statistic    df p.value missing.patterns
##       <dbl> <dbl>   <dbl>            <int>
## 1     2211.    35       0                4

Tras excluir las tres observaciones sin contenido analítico y restringir el test a las variables originales de la base, el resultado del test de Little arroja un valor p muy cercano a cero, por lo que se rechaza la hipótesis nula, indica que hay evidencia estadística fuerte de que el patrón de valores faltantes está sistemáticamente relacionado con otras variables del conjunto de datos.

El siguiente paso será revisar para cada variable con valores faltantes, ¿con cuáles variables se asocia esta ausencia de dato?, para lo que se usa la prueba chi-cuadrado para verificar si existe una asociación real entre dos variables categóricas o si el patrón que se observa podría deberse simplemente al azar.

\[ H_0: \text{Las dos variables son independientes} \]

\[ H_1: \text{Las dos variables no son independientes} \]

# =============================================================================
# PISO
# =============================================================================
vivienda <- vivienda %>%
  mutate(falta_piso = is.na(piso))

# ¿Se asocia con tipo? 
chisq.test(table(vivienda$tipo, vivienda$falta_piso))
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  table(vivienda$tipo, vivienda$falta_piso)
## X-squared = 128.1, df = 1, p-value < 2.2e-16
# ¿Se asocia con zona?
chisq.test(table(vivienda$zona, vivienda$falta_piso))
## 
##  Pearson's Chi-squared test
## 
## data:  table(vivienda$zona, vivienda$falta_piso)
## X-squared = 148.66, df = 4, p-value < 2.2e-16
# ¿Se asocia con variables numéricas? (t-test)
t.test(areaconst ~ falta_piso, data = vivienda)
## 
##  Welch Two Sample t-test
## 
## data:  areaconst by falta_piso
## t = -6.3496, df = 4604, p-value = 2.368e-10
## alternative hypothesis: true difference in means between group FALSE and group TRUE is not equal to 0
## 95 percent confidence interval:
##  -29.22303 -15.43460
## sample estimates:
## mean in group FALSE  mean in group TRUE 
##            167.8624            190.1912
t.test(preciom ~ falta_piso, data = vivienda)
## 
##  Welch Two Sample t-test
## 
## data:  preciom by falta_piso
## t = -4.065, df = 4802.6, p-value = 4.88e-05
## alternative hypothesis: true difference in means between group FALSE and group TRUE is not equal to 0
## 95 percent confidence interval:
##  -47.91755 -16.73646
## sample estimates:
## mean in group FALSE  mean in group TRUE 
##             423.665             455.992

Las cuatro pruebas para verificar la asociación de variable con la ausencia de datos en Piso rechazan independencia, es decir, que los datos no faltan al azar, sino que dependen de otras variables observables (tipo, zona, área, precio), lo cual es coherente con un tipo de datos faltante MAR donde el mecanismo de faltante se explica completamente por variables disponibles en la base, sin necesidad de invocar el valor mismo de piso que falta. Por lo tanto, se propone hacer la imputación de los datos con KNN usando tipo, zona, areaconst, estrato como predictores, ya que es la elección más adecuada.

# =============================================================================
# PARQUEADEROS
# =============================================================================
vivienda <- vivienda %>%
  mutate(falta_parqueadero = is.na(parqueaderos))

chisq.test(table(vivienda$estrato, vivienda$falta_parqueadero))
## 
##  Pearson's Chi-squared test
## 
## data:  table(vivienda$estrato, vivienda$falta_parqueadero)
## X-squared = 1518.7, df = 3, p-value < 2.2e-16
chisq.test(table(vivienda$zona, vivienda$falta_parqueadero))
## 
##  Pearson's Chi-squared test
## 
## data:  table(vivienda$zona, vivienda$falta_parqueadero)
## X-squared = 770.91, df = 4, p-value < 2.2e-16
t.test(areaconst ~ falta_parqueadero, data = vivienda)
## 
##  Welch Two Sample t-test
## 
## data:  areaconst by falta_parqueadero
## t = 8.4626, df = 2543.4, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group FALSE and group TRUE is not equal to 0
## 95 percent confidence interval:
##  24.74156 39.66546
## sample estimates:
## mean in group FALSE  mean in group TRUE 
##            181.1364            148.9329
t.test(preciom ~ falta_parqueadero, data = vivienda)
## 
##  Welch Two Sample t-test
## 
## data:  preciom by falta_parqueadero
## t = 24.172, df = 3099.6, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group FALSE and group TRUE is not equal to 0
## 95 percent confidence interval:
##  166.8941 196.3602
## sample estimates:
## mean in group FALSE  mean in group TRUE 
##            468.8806            287.2534

En el caso de la variable Parqueaderos ocurre lo mismo y muestra una gran diferencia entre el precio promedio de las viviendas con dato (468.9 M) y sin dato (287.3 M).

Sin embargo, un punto a tener en cuenta es que con estas pruebas solo se puede comprobar si el dato es MAR, no distingue si es MNAR, pero se puede observar que el valor mínimo de parqueaderos para los datos que se tienen es 1, lo que podría sugerir que el formulario de origen probablemente solo registra el dato cuando la vivienda sí tiene parqueadero. Combinado con que las viviendas sin dato son sistemática y marcadamente más pequeñas y baratas, la interpretación más razonable es que el “NA” representa un valor real (0), no una casilla que se olvidó de diligenciar y por eso la imputación correcta será la regla de dominio (NA → 0), no un método estadístico.

Imputación de datos faltantes

Con los resultados obtenidos anteriormente, se procede entonces a realizar el tratamiento de los datos faltantes.

La variable Piso que cuenta con un 31,7% de datos faltantes mostró que se presentaba un mecanismo de datos faltantes al azar condicional (MAR), por lo tanto se opta por imputar mediante el algoritmo k-vecinos más cercanos (KNN, K=5), utilizando las variables tipo, zona, areaconst, estrato como predictoras.

Por otro lado, para la variable Parqueaderos se consideró que el tipo de dato faltante que presentaba era de tipo MNAR puesto que el valor mínimo observado en la variable es 1 (nunca 0) y las viviendas sin dato registrado presentan en general un promedio de precio menor (287.3 vs. 468.9 millones COP) y menor área (148.9 vs. 181.1 m²) que aquellas con dato disponible. Esto sugiere que la ausencia de registro corresponde a viviendas que efectivamente no cuentan con parqueadero, más que a un vacío de captura. Por tanto, se imputarán los valores faltantes como 0, en lugar de aplicar un método de imputación estadística genérico.

# 1. parqueaderos (MNAR): regla de dominio, NA -> 0
vivienda_clean <- vivienda %>%
  mutate(parqueaderos = ifelse(is.na(parqueaderos), 0, parqueaderos))

# 2. piso (MAR): KNN usando tipo, zona, areaconst, estrato como predictores
#    (ya no hay riesgo de que estos predictores tengan NA)
vivienda_clean <- kNN(vivienda_clean,
                       variable = "piso",
                       dist_var = c("tipo", "zona", "areaconst", "estrato"),
                       k = 5,
                       imp_var = FALSE)


# 3. Conversión final a factor 
vivienda_clean <- vivienda_clean %>%
  mutate(estrato    = factor(estrato, ordered = TRUE),
         piso       = factor(piso, ordered = TRUE),
         zona       = as.factor(zona),
         tipo       = as.factor(tipo),
         barrio_std = as.factor(barrio_std),
         barrio_agr = as.factor(barrio_agr))
#str(vivienda_clean)

#eliminar variables que no se necesitaran en análisis posterior 
vivienda_clean <- vivienda_clean %>%
  select(-barrio, -barrio_fix, -barrio_clave, -falta_piso, -falta_parqueadero)

# Verificación: ya no debería quedar ningún NA
colSums(is.na(vivienda_clean))
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0            0            0            0            0 
## parqueaderos       banios habitaciones         tipo     longitud      latitud 
##            0            0            0            0            0            0 
##    precio_m2   barrio_std   barrio_agr 
##            0            0            0

Análisis Multivariado

Una vez depurada y preparada la base de datos, se procede a aplicar un conjunto de técnicas de estadística multivariada orientadas a explorar la estructura conjunta de las variables que caracterizan la oferta de vivienda en la ciudad de Cali. A diferencia del análisis univariado y bivariado presentado en las secciones anteriores, estas técnicas permiten estudiar simultáneamente las relaciones entre múltiples variables, con el fin de identificar patrones, agrupaciones y asociaciones que no son evidentes al examinar las variables de forma aislada.

Se usarán técnicas como el Análisis de componentes principales (ACP), Análisis de conglomerados y Análisis de correspondencias, las cuales en conjunto permiten construir una visión integral y complementaria del mercado de vivienda analizado, combinando la reducción de dimensionalidad, la segmentación de propiedades y el análisis de asociaciones categóricas, como insumo para la toma de decisiones estratégicas de la empresa inmobiliaria.

Análisis de Componentes Principales

Se realiza el análisis de componentes principales (ACP) ya que permite sintetizar la información de múltiples variables cuantitativas correlacionadas entre sí en un número reducido de componentes no correlacionados, facilitando tanto la interpretación de los factores que explican la variación del mercado como la visualización conjunta de las características físicas, el precio y la ubicación de las viviendas.

En este caso, para el análisis se toman únicamente las variables numéricas preciom, areaconst, parqueaderos, banios, habitaciones, precio_m2 y se incluyeron las variables latitud y longitud como variables cuantitativas suplementarias, con el fin de examinar el patrón geográfico de los componentes sin que la ubicación influyera en la construcción de las componentes. Por otro lado, las variables zona, tipo, estrato y barrio_agr se incorporaron como variables cualitativas suplementarias, dado que el ACP clásico opera únicamente sobre variables cuantitativas; su proyección sobre el plano factorial permite interpretar la relación entre estas categorías y la estructura de componentes obtenida a partir de las variables activas de precio y tamaño.

vivienda_pca <- vivienda_clean %>%
  select(preciom, areaconst, precio_m2, parqueaderos, banios, habitaciones,
         latitud, longitud, zona, tipo, estrato, barrio_agr) %>%
  as.data.frame()
rownames(vivienda_pca) <- vivienda_clean$id

pos_quanti_sup <- which(names(vivienda_pca) %in% c("latitud", "longitud"))
pos_quali_sup  <- which(names(vivienda_pca) %in% c("zona", "tipo", "estrato", "barrio_agr"))

res.pca <- PCA(vivienda_pca,
               quanti.sup = pos_quanti_sup,
               quali.sup  = pos_quali_sup,
               scale.unit = TRUE,   # estandariza: las variables tienen escalas muy distintas
               ncp = 5,
               graph = FALSE)

Elección del número de componentes

El gráfico de “screeplot” muestra la varianza explicada por cada componente principal. Los primeros componentes suelen explicar la mayor parte de la varianza, por lo que se utiliza para identificar la varianza explicada por cada uno y seleccionar la cantidad de componentes a retener y así reducir la dimensionalidad del dataset.

eig_tab <- as.data.frame(res.pca$eig)
print(round(eig_tab, 2))
##        eigenvalue percentage of variance cumulative percentage of variance
## comp 1       3.13                  52.16                             52.16
## comp 2       1.53                  25.49                             77.65
## comp 3       0.58                   9.70                             87.35
## comp 4       0.43                   7.17                             94.53
## comp 5       0.25                   4.17                             98.70
g_scree <- fviz_eig(res.pca, addlabels = TRUE, barfill = "steelblue",
                     barcolor = "steelblue",
                     main = "Inercia explicada por componente (Scree plot)")
g_scree

El scree plot muestra que el primer componente explica el 52.2% de la varianza total y el segundo un 25.5% adicional, acumulando entre ambos un 77.7% de la inercia total con solo dos dimensiones. La marcada disminución en la varianza explicada a partir del tercer componente (9.7%, 7.2% y 4.2% para las dimensiones 3, 4 y 5, respectivamente) evidencia un punto de quiebre claro, consistente con el criterio de Kaiser (umbral de referencia: 100/6 ≈ 16.7% por componente dado el número de variables activas). Esto respalda la decisión de concentrar la interpretación del análisis en los dos primeros componentes principales, los cuales resumen adecuadamente la estructura de variación del mercado de vivienda analizado.

Contribuciones de las variables a los ejes

round(res.pca$var$contrib, 2) # % de contribución de cada variable a cada eje
##              Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
## preciom      23.21  9.98  0.32 16.68  4.85
## areaconst    23.15  4.73 15.03 18.76  2.88
## precio_m2     0.05 55.69 20.50  0.53  3.91
## parqueaderos 16.85  8.07 17.82 56.77  0.42
## banios       24.58  0.17 12.13  0.01 62.93
## habitaciones 12.15 21.36 34.20  7.26 25.00
g_contrib1 <- fviz_contrib(res.pca, choice = "var", axes = 1, top = 10,
                            fill = "darkorange") +
  labs(title = "Contribución variables al eje 1 (Dim 1)")
g_contrib2 <- fviz_contrib(res.pca, choice = "var", axes = 2, top = 10,
                            fill = "darkorange") +
  labs(title = "Contribución variables al eje 2 (Dim 2)")
g_contrib_panel <- arrangeGrob(g_contrib1, g_contrib2, ncol = 2)
grid::grid.draw(g_contrib_panel)

El eje 1 se define principalmente por las variables asociadas al tamaño y las comodidades de la vivienda (banios: 24.6%, preciom: 23.2%, areaconst: 23.2%, parqueaderos: 16.9%), pudiendo interpretarse como un componente general de ‘magnitud/valor de la vivienda’. En contraste, el eje 2 está dominado por precio_m2 (55.7%) y habitaciones (21.4%), configurando un componente de ‘valorización relativa por metro cuadrado’, prácticamente independiente del primero (precio_m2 contribuye solo 0.05% al eje 1 y banios apenas 0.2% al eje 2). Esta separación confirma que el precio absoluto y el precio por metro cuadrado capturan dimensiones distintas y complementarias del mercado inmobiliario analizado.

\(Cos^2\) de variables: calidad de representación

round(res.pca$var$cos2, 2)
##              Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
## preciom       0.73  0.15  0.00  0.07  0.01
## areaconst     0.72  0.07  0.09  0.08  0.01
## precio_m2     0.00  0.85  0.12  0.00  0.01
## parqueaderos  0.53  0.12  0.10  0.24  0.00
## banios        0.77  0.00  0.07  0.00  0.16
## habitaciones  0.38  0.33  0.20  0.03  0.06
corrplot(res.pca$var$cos2, is.corr = FALSE, method = "color",
         addCoef.col = "black", tl.col = "black", number.cex = 0.7,
         title = "Cos2 de las variables por componente", mar = c(0, 0, 2, 0))

g_var <- fviz_pca_var(res.pca, col.var = "cos2",
                       gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
                       repel = TRUE,
                       title = "Círculo de correlaciones - ACP (color = cos2)")
g_var

El \(Cos^2\) mide qué tan bien queda representada cada variable en el plano factorial, cuanto más cerca de 1, más fielmente se puede ver representada esa variable en el gráfico; por el contrario, entre más bajo sea, su representación se verá más distorsionada en las dos dimensiones específicas, aunque la variable pueda ser importante en otro eje.

El análisis de \(cos^2\) confirma que, calculando la calidad total de representación para cada variable en este primer plano factorial, se obtiene que preciom (0.88), precio_m2 (0.85), areaconst (0.79) y banios (0.77) presentan una calidad de representación alta en el plano formado por los dos primeros componentes, siendo fielmente interpretables en el círculo de correlaciones. En contraste, parqueaderos (0.65) y habitaciones (0.71) muestran una representación más moderada: parqueaderos concentra parte relevante de su varianza en la cuarta dimensión (\(cos^2\)=0.24), mientras que habitaciones se distribuye de forma casi equitativa entre los dos primeros ejes (0.38 y 0.33 respectivamente), lo que se refleja en la orientación diagonal de su vector en el círculo de correlaciones. Esto sugiere que, si bien estas dos variables contribuyen a la definición de los ejes, su posición en el plano (1,2) muestra que no capturan la totalidad de su variabilidad en estas dos dimensiones.

Análisis de los individuos (viviendas)

# Coordenadas, contribución y cos2 de cada vivienda en los primeros ejes
head(res.pca$ind$coord)
##           Dim.1       Dim.2      Dim.3       Dim.4      Dim.5
## 1147 -0.2304799 -0.29672641  1.7675086  0.63871410  0.7643510
## 1169 -1.0425630  0.04908300 -0.2047370 -0.09770840  0.2330312
## 1350 -0.1157530 -0.90423114 -0.8700345  0.42525745  0.5701116
## 5992  1.2888789 -0.59986181 -1.1178995  0.62903824 -1.3116019
## 1212 -1.2267759  0.19029529 -0.0200995  0.05276753  0.1978058
## 1724 -0.9217953  0.05724045  0.1808391  0.10056381 -0.3984639
head(res.pca$ind$contrib)
##             Dim.1        Dim.2        Dim.3        Dim.4       Dim.5
## 1147 2.040471e-04 6.919256e-04 6.449655e-02 1.139170e-02 0.028076750
## 1169 4.175119e-03 1.893255e-05 8.653785e-04 2.665873e-04 0.002609692
## 1350 5.146703e-05 6.425485e-03 1.562739e-02 5.049862e-03 0.015619997
## 5992 6.380996e-03 2.827805e-03 2.579996e-02 1.104917e-02 0.082673284
## 1212 5.780891e-03 2.845791e-04 8.340342e-06 7.775156e-05 0.001880352
## 1724 3.263873e-03 2.574856e-05 6.751468e-04 2.823964e-04 0.007630254
head(res.pca$ind$cos2)
##            Dim.1       Dim.2        Dim.3       Dim.4      Dim.5
## 1147 0.012307089 0.020398664 0.7237896909 0.094515344 0.13535522
## 1169 0.907120538 0.002010586 0.0349826838 0.007967540 0.04531986
## 1350 0.006350068 0.387500687 0.3587455174 0.085707224 0.15403996
## 5992 0.308047826 0.066726197 0.2317391869 0.073374988 0.31900539
## 1212 0.949798053 0.022853718 0.0002549595 0.001757253 0.02469329
## 1724 0.804678842 0.003102842 0.0309698044 0.009577167 0.15035972

El análisis de individuos evidencia que las viviendas con mayor contribución a los dos primeros componentes corresponden a los casos atípicos identificados previamente en el análisis exploratorio. Las propiedades de mayor precio y área (ids 4564, 3652) dominan la contribución al eje 1, mientras que los casos extremos de precio por metro cuadrado, tanto el mínimo (id 534, estrato 3) como el máximo observado (id 8020), dominan la contribución al eje 2, validando la coherencia entre los hallazgos exploratorios iniciales y la estructura factorial obtenida.

# Viviendas que más contribuyen a la formación del eje 1 y del eje 2
# (posibles atípicos / propiedades "premium" que tensionan la estructura)
top_contrib_dim1 <- res.pca$ind$contrib[order(-res.pca$ind$contrib[, 1]), ][1:10, 1]
top_contrib_dim2 <- res.pca$ind$contrib[order(-res.pca$ind$contrib[, 2]), ][1:10, 2]
top_contrib_dim1
##      5684      5396      3652      5004      6766      8298       673      5978 
## 0.3975061 0.2805041 0.2765774 0.2740874 0.2656938 0.2553888 0.2511394 0.2485029 
##      5902      4564 
## 0.2366920 0.2345307
top_contrib_dim2
##       534      7366      4112      5094      8020       921       684      4508 
## 0.2686535 0.2565874 0.2295120 0.2158579 0.1913831 0.1770036 0.1659491 0.1609315 
##      5151      5474 
## 0.1561168 0.1561038
g_ind_cos2 <- fviz_pca_ind(res.pca, geom = "point", col.ind = "cos2",
                            gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
                            alpha.ind = 0.6,
                            title = "Individuos - ACP (color = calidad de representación, cos2)")
g_ind_cos2

El gráfico de individuos coloreado según la calidad de representación muestra un conjunto de puntos azules concentrados cerca del origen, rodeado de una periferia de puntos naranjas, siendo los puntos azules viviendas promedio que no se destacan particularmente ni en tamaño, precio, ni en valorización, así que su varianza está repartida entre más ejes. Por otro lado, los puntos naranjas de la periferia, son las viviendas atípicas que están muy bien representadas por el plano (1,2), por lo que su comportamiento extremo queda capturado casi por completo con estas dos dimensiones.

g_ind_zona <- fviz_pca_ind(res.pca, geom = "point", habillage = "zona",
                            addEllipses = TRUE, ellipse.level = 0.95,
                            alpha.ind = 0.5,
                            title = "Individuos - ACP coloreados por zona (elipses 95%)")
g_ind_zona

Las elipses de zona se superponen bastante entre sí, especialmente cerca del origen debido a que zona se incluyó como una variable suplementaria. Sin embargo, la elipse de la zona Oeste es la que más resalta y está más desplazada hacia la derecha y hacia arriba respecto a las demás, es decir, hacia valores más altos tanto en Dim.1 (tamaño/precio) como en Dim.2 (precio_m2), lo cual es consistente con las conclusiones que se tenían para esta zona considerándola de un nivel superior. Las zonas Centro, Norte y Oriente quedan más concentradas cerca del origen, reflejo de que son zonas con oferta más homogénea (menos viviendas “extremas” en tamaño o valorización).

Interpretación de las componentes

g_biplot <- fviz_pca_biplot(res.pca, geom.ind = "point",
                             habillage = "tipo",
                             addEllipses = TRUE, alpha.ind = 0.4,
                             col.var = "black", repel = TRUE,
                             title = "Biplot ACP: individuos (por tipo) + variables activas") +
  theme_minimal()
g_biplot

La interpretación conjunta de los dos primeros componentes permite caracterizar el mercado de vivienda en dos dimensiones complementarias: el componente 1 refleja el tamaño y la capacidad física de la vivienda (precio, área, baños, habitaciones y parqueaderos), diferenciando parcialmente entre casas, las cuales se encuentran en la nube desplazadas hacia valores más altos, y apartamentos, concentrados hacia valores más bajos. El componente 2, dominado por precio_m2, captura la valorización relativa por metro cuadrado, independiente del tamaño.

plot(res.pca, choix = "ind", invisible = "ind", autoLab = "yes",
     title = "Categorías suplementarias (zona, tipo, estrato, barrio) en el plano (1,2)")
## Ignoring unknown labels:
## • colour : "none"

La proyección de las categorías suplementarias sobre este plano revela cuatro perfiles de mercado: un segmento premium de alta magnitud y alta valorización (estrato 6, barrios como Pance y Ciudad Jardín); un segmento de apartamentos compactos pero de alta valorización por metro (Normandía, Santa Teresita); viviendas de mayor tamaño con valorización moderada (tipo Casa); y un segmento de menor valor en ambas dimensiones, concentrado en estratos 3-4 y las zonas Oriente, Centro y Norte.

Análisis de Conglomerados

Con el objetivo de crear segmentos que agrupen las viviendas de tal forma que se puedan crear focos de diferentes clientes para la inmobiliaria, se procede a realizar una metodología de segmentación con el fin de que se tengan grupos muy homogéneos dentro de ellos (minimizar varianza intra-clase) y heterogéneos entre ellos (maximizar varianza inter-clase).

Se trabaja sobre las mismas variables estandarizadas usadas en el PCA (preciom,areaconst, precio_m2, parqueaderos, banios, habitaciones). Dado que la base de datos tiene más de 8.000 registros, se utiliza el método de k-means como método principal, ya que es menos costoso computacionalmente, además, cada grupo queda representado directamente por un ‘centroide’ (el perfil promedio del grupo), lo que facilita la creación de perfiles comerciales.

Determinación de k (enfoque 1: Método del codo con k-means)

Para elegir el número de cluster, se usa el Método del codo el cual consiste en ejecutar k-means para distintos valores de k (en este caso 2-8) y calcular, para cada uno, la suma de cuadrados intra-cluster (WSS, la misma varianza intra-clase), por lo tanto, mientras más clusters se usan, cada vivienda queda más cerca de su propio centroide, así que la WSS siempre disminuye a medida que k crece, pero no de forma uniforme, puesto que a partir de cierto punto los clusters adicionales solo separan grupos que ya eran bastante homogéneos entre sí.

Al graficar la WSS contra el número de clusters, esta transición se ve como un “codo”: una caída pronunciada seguida de una curva que se aplana. El número de clusters que corresponde a ese punto de quiebre se toma como el óptimo, porque representa el mejor equilibrio entre simplicidad (pocos grupos) y capacidad explicativa (baja variabilidad dentro de cada grupo), por lo que agregar más clusters después de ese punto complica la interpretación sin aportar una mejora proporcional en la calidad de la segmentación.

vars_cluster <- vivienda_clean %>%
  select(preciom, areaconst, precio_m2, parqueaderos, banios, habitaciones) %>%
  as.data.frame()
rownames(vars_cluster) <- vivienda_clean$id

vars_cluster_z <- scale(vars_cluster)  # estandarización obligatoria: las
                                        # variables tienen escalas muy distintas
set.seed(1234)
wss <- sapply(2:8, function(k) {
  km_k <- kmeans(vars_cluster_z, centers = k, nstart = 25)
  km_k$tot.withinss
})
 
codo_tab <- data.frame(k = 2:8, wss = round(wss, 1))
print(codo_tab)
##   k     wss
## 1 2 32574.1
## 2 3 26324.5
## 3 4 22058.8
## 4 5 19895.8
## 5 6 17925.2
## 6 7 16732.1
## 7 8 15633.2
x <- codo_tab$k; y <- codo_tab$wss
x1 <- x[1]; y1 <- y[1]; x2 <- x[length(x)]; y2 <- y[length(y)]
dist_perp <- abs((y2 - y1) * x - (x2 - x1) * y + x2 * y1 - y2 * x1) /
  sqrt((y2 - y1)^2 + (x2 - x1)^2)
k_optimo <- x[which.max(dist_perp)]
cat("k óptimo según el método del codo:", k_optimo, "\n")
## k óptimo según el método del codo: 4
g_codo <- ggplot(codo_tab, aes(x = k, y = wss)) +
  geom_line(color = "#034D94", linewidth = 1) +
  geom_point(size = 2, color = "#034D94") +
  geom_vline(xintercept = k_optimo, linetype = "dashed", color = "#EE6C4D") +
  theme_minimal() +
  labs(title = "Método del codo - variables originales estandarizadas",
       x = "Número de conglomerados (k)", y = "Suma de cuadrados intra-cluster (WSS)")+
  theme(
    plot.title  = element_text(size = 23, face = "bold"),  
    axis.title  = element_text(size = 16),                 
    axis.text   = element_text(size = 18)                  
  )
g_codo

El método del codo muestra una disminución pronunciada de la suma de cuadrados intra-cluster (WSS) hasta k=4, seguida de una reducción marginal y aproximadamente constante para valores superiores de k, evidenciando un punto de quiebre claro en k=4.

Cluster jerárquico para confirmar la estimación de \(K\)

Adicionalmente, para complementar la evaluación del método del codo se usa el dendrograma jerárquico para verificar la selección del número óptimo de conglomerados (\(k\)).

El dendrograma expone la estructura jerárquica natural y continua subyacente en los datos sin imponer una partición rígida a priori. De esta manera, confirmar el resultado numérico del Método del codo mediante la distancia de fusión y la prominencia de las ramas en el árbol jerárquico permite validar que el número de grupos seleccionado no responda únicamente a un óptimo local del algoritmo no jerárquico, sino que refleje divisiones estructuralmente significativas y coherentes en el mercado analizado.

set.seed(1234)
idx_dendro <- sample(seq_len(nrow(vars_cluster_z)), size = min(30, nrow(vars_cluster_z)))
muestra_dendro <- vars_cluster_z[idx_dendro, ]
rownames(muestra_dendro) <- paste0("V", seq_len(nrow(muestra_dendro)))

dist_dendro <- dist(muestra_dendro, method = "euclidean")
hc_muestra <- hclust(dist_dendro, method = "ward.D2")

plot(hc_muestra, main = "Dendrograma (muestra de 30 viviendas)", xlab = "", sub = "",
     cex.main = 2,   
     cex.axis = 1.5,   
     cex.lab  = 1.5,    
     cex      = 0.9)    
rect.hclust(hc_muestra, k = 4, border = "#034D94")

# Tabla de alturas de fusión: cuantifica el "salto" entre cortes sucesivos,
# como respaldo numérico al corte que se observa visualmente en el dendrograma
alturas <- sort(hc_muestra$height, decreasing = TRUE)[1:6]
alturas_tab <- data.frame(k_al_cortar = 2:7, altura_de_fusion = round(alturas, 2))
alturas_tab$salto_respecto_al_siguiente <- c(round(-diff(alturas_tab$altura_de_fusion), 2), NA)
alturas_tab
##   k_al_cortar altura_de_fusion salto_respecto_al_siguiente
## 1           2             9.18                        2.27
## 2           3             6.91                        2.13
## 3           4             4.78                        0.55
## 4           5             4.23                        0.77
## 5           6             3.46                        0.12
## 6           7             3.34                          NA

La tabla anterior muestra, para cada número de grupos \(k\) al cortar el árbol, la altura a la que ocurrió la fusión que redujo el número de clústeres a \(k-1\), junto con el salto respecto al siguiente corte.

La tabla de alturas de fusión del clustering jerárquico, confirma el número de clusters sugerido previamente. Los saltos más pronunciados se observan entre las particiones de 2 a 3 y de 3 a 4 grupos (2.27 y 2.13, respectivamente), mientras que las divisiones posteriores presentan saltos considerablemente menores. La coincidencia entre el \(k=4\) sugerido por el método del codo (sobre k-means y la base completa) y el \(k=4\) sugerido por el jerárquico (sobre una muestra independiente) constituye evidencia adicional a favor de este número de segmentos.

Segmentación con K-means

set.seed(1234)
res.kmeans <- kmeans(vars_cluster_z, centers = 4, nstart = 25)
table(res.kmeans$cluster)
## 
##    1    2    3    4 
##  661 4433 1558 1667
vivienda_clean$cluster <- factor(res.kmeans$cluster)
g_clusters <- fviz_cluster(res.kmeans, data = vars_cluster_z,
                            geom = "point", ellipse.type = "convex",
                            palette = "jco", alpha = 0.5,
                            main = "Conglomerados (k-means sobre variables originales,\nproyección 2D vía PCA solo para visualización)") +
  theme(
    plot.title   = element_text(size = 25, face = "bold"), 
    axis.title   = element_text(size = 20),                 
    axis.text    = element_text(size = 15),                 
    legend.title = element_text(size = 15),                 
    legend.text  = element_text(size = 15)                 
  )
g_clusters

La segmentación en cuatro conglomerados mediante k-means sobre las variables originales produjo grupos de tamaño equilibrado, en contraste con la partición desigual observada en el dendrograma sobre la muestra reducida. La proyección sobre el plano principal del ACP evidencia una correspondencia clara entre los clusters obtenidos y los cuatro perfiles de mercado identificados previamente en la interpretación de componentes. Viviendas de gran tamaño y precio absoluto (cluster 1), apartamentos compactos de alta valorización por metro cuadrado (cluster 4), el segmento de menor valor en ambas dimensiones (cluster 2), y viviendas de tamaño medio con valorización relativa más baja (cluster 3). Se observa, sin embargo, un solapamiento considerable entre los clusters en la región central del plano, reflejo de que las diferencias entre segmentos del mercado inmobiliario analizado son de naturaleza gradual más que categorías completamente discretas.

Perfil de los conglomerados

perfil_clusters <- vivienda_clean %>%
  group_by(cluster) %>%
  summarise(
    n_viviendas    = n(),
    precio_prom_M  = round(mean(preciom, na.rm = TRUE), 0),
    precio_m2_prom = round(mean(precio_m2, na.rm = TRUE), 2),
    area_prom_m2   = round(mean(areaconst, na.rm = TRUE), 0),
    parqueaderos_p = round(mean(parqueaderos, na.rm = TRUE), 2),
    banios_prom    = round(mean(banios, na.rm = TRUE), 2),
    habitaciones_p = round(mean(habitaciones, na.rm = TRUE), 2),
    estrato_moda   = names(sort(table(estrato), decreasing = TRUE))[1],
    zona_moda      = names(sort(table(zona), decreasing = TRUE))[1],
    tipo_moda      = names(sort(table(tipo), decreasing = TRUE))[1]
  )

kable(perfil_clusters,
      caption = "Perfil de los conglomerados",
      col.names = c("Cluster", "N° viviendas", "Precio prom. (M COP)",
                     "Precio/m² prom.", "Área prom. (m²)", "Parqueaderos prom.",
                     "Baños prom.", "Habitaciones prom.", "Estrato moda",
                     "Zona moda", "Tipo moda"),
      align = "c") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) %>%
  scroll_box(width = "100%", height = "auto")
Perfil de los conglomerados
Cluster N° viviendas Precio prom. (M COP) Precio/m² prom. Área prom. (m²) Parqueaderos prom. Baños prom. Habitaciones prom. Estrato moda Zona moda Tipo moda
1 661 1138 2.69 471 4.03 5.48 4.79 6 Zona Sur Casa
2 4433 236 2.60 95 0.89 2.16 2.89 4 Zona Sur Apartamento
3 1558 447 1.67 285 1.42 4.14 5.46 5 Zona Sur Casa
4 1667 670 4.04 168 2.10 3.75 3.30 6 Zona Sur Apartamento
# Tablas cruzadas: composición categórica de cada cluster
# =============================================================================
# Tabla 2: Cluster x Zona
# =============================================================================
tab_zona <- as.data.frame.matrix(table(Cluster = vivienda_clean$cluster,
                                        Zona = vivienda_clean$zona))
tab_zona <- cbind(Cluster = rownames(tab_zona), tab_zona)

kable(tab_zona, caption = "Distribución de zona por cluster", row.names = FALSE,
      align = "c") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) 
Distribución de zona por cluster
Cluster Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
1 2 71 113 1 474
2 59 1224 301 177 2672
3 59 386 111 172 830
4 4 239 673 1 750
# =============================================================================
# Tabla 3: Cluster x Tipo
# =============================================================================
tab_tipo <- as.data.frame.matrix(table(Cluster = vivienda_clean$cluster,
                                        Tipo = vivienda_clean$tipo))
tab_tipo <- cbind(Cluster = rownames(tab_tipo), tab_tipo)

kable(tab_tipo, caption = "Distribución de tipo de vivienda por cluster", row.names = FALSE,
      align = "c") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) 
Distribución de tipo de vivienda por cluster
Cluster Apartamento Casa
1 98 563
2 3553 880
3 144 1414
4 1305 362
# =============================================================================
# Tabla 4: Cluster x Estrato
# =============================================================================
tab_estrato <- as.data.frame.matrix(table(Cluster = vivienda_clean$cluster,
                                           Estrato = vivienda_clean$estrato))
tab_estrato <- cbind(Cluster = rownames(tab_estrato), tab_estrato)

kable(tab_estrato, caption = "Distribución de estrato por cluster", row.names = FALSE,
      align = "c") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) 
Distribución de estrato por cluster
Cluster 3 4 5 6
1 9 33 151 468
2 1014 1629 1547 243
3 419 407 584 148
4 11 60 468 1128
#--------------------------------------------------#
g_perfil_precio <- ggplot(vivienda_clean, aes(x = cluster, y = preciom, fill = cluster)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.2) +
  scale_y_continuous(labels = comma) +
  labs(title = "Distribución del precio por segmento (cluster)",
       x = "Segmento", y = "Precio (millones COP)") +
  theme_minimal() + 
  theme(legend.position = "none",
        plot.title   = element_text(size = 25, face = "bold"), 
    axis.title   = element_text(size = 20),                 
    axis.text    = element_text(size = 15),                 
    )
                
g_perfil_precio

g_perfil_area <- ggplot(vivienda_clean, aes(x = cluster, y = areaconst, fill = cluster)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.2) +
  labs(title = "Distribución del área construida por segmento",
       x = "Segmento", y = "Área construida (m2)") +
  theme_minimal() + 
  theme(legend.position = "none",
        plot.title   = element_text(size = 25, face = "bold"), 
    axis.title   = element_text(size = 20),                 
    axis.text    = element_text(size = 15)
    )
g_perfil_area

A partir del perfil promedio y del cruce con zona, tipo y estrato, los cuatro conglomerados podrian interpretarse de la siguiente manera:

  • Cluster 1: Es el segmento más pequeño (661 viviendas, 8%) pero el de mayor precio absoluto (1,138 millones) y mayor área (471 \(m^2\)), con más baños (5.48) y más parqueaderos (4.03) que cualquier otro cluster. Sin embargo, su precio_m2 (2.69) es prácticamente igual al del mercado masivo (cluster 2, 2.60) y muy por debajo del cluster 4 (4.04). Esto confirma directamente el patrón de economías de escala que se identificó anteriormente, donde se encontraban casas grandes, con costo alto en total, pero no necesariamente “caras por metro cuadrado”. Está fuertemente concentrado en Zona Sur (72% de sus casos) y en estrato 6 (71%).

  • Cluster 2: Con 4,433 viviendas (más de la mitad de la base), este es el segmento dominante conformado en su mayoría por apartamentos (80%), área pequeña (95 \(m^2\) promedio), el precio más bajo (236 millones), y muy pocos parqueaderos (0.89 en promedio — la mayoría con 0 o 1). Se concentra en estratos 4-5 y está geográficamente repartido de forma similar al mercado general (Sur y Norte). Son en esencia las viviendas más características y que pertenecen al mercado masivo de la ciudad.

  • Cluster 3: Tiene el precio_m2 más bajo de los cuatro segmentos (1.67), predominan las casas (91%), área intermedia (285 \(m^2\)), y su distribución de estrato está mucho más repartida hacia abajo que los demás (estratos 3-5 con peso similar, en vez de concentrarse en 6). Además, geográficamente, Zona Oriente está sobrerrepresentada casi 3 veces en este cluster (11% vs. 4.2% de participación general), por lo que coincide exactamente con el patrón de “casas grandes en zonas populares con bajo valor por metro” que se identificó como hallazgo particular del mercado, desde el inicio del informe.

  • Cluster 4: Con precio_m2 de 4.04 (el más alto, muy por encima de los demás), es el segmento que mejor representa “caro por metro cuadrado” más que “grande en total”. Consta de un área moderada (168 \(m^2\)), predominantemente apartamentos (78%), estrato 6 dominante (68%). Además, el 40% de este cluster está en Zona Oeste (673 de 1,667), muy por encima de la participación de esa zona en el mercado general (14.4%), lo cual indica una sobrerrepresentación de casi 3 veces. Esto es la confirmación cuantitativa, vía clustering, de lo que ya se había idnetificado en el biplot del ACP, donde se caracterizaba a la Zona Oeste como el motor geográfico del segmento de alta valorización por metro cuadrado.

Visualización geográfica de los conglomerados

g_mapa_clusters <- ggplot(vivienda_clean, aes(x = longitud, y = latitud, color = cluster)) +
  geom_point(alpha = 0.5, size = 1.2) +
  coord_fixed() +
  labs(title = "Distribución geográfica de los segmentos de vivienda",
       x = "Longitud", y = "Latitud", color = "Segmento") +
  theme_minimal() + 
  theme( plot.title   = element_text(size = 25, face = "bold"),  
    axis.title   = element_text(size = 20),                 
    axis.text    = element_text(size = 15),                
    legend.title = element_text(size = 20),                 
    legend.text  = element_text(size = 15))
g_mapa_clusters

La proyección geográfica de los segmentos confirma espacialmente los hallazgos de las tablas cruzadas. El cluster 4 (alta valorización por metro cuadrado) forma una concentración claramente delimitada en el sector correspondiente a Zona Oeste, mientras que el cluster 1 (casas de gran tamaño y precio absoluto) muestra mayor presencia en el extremo sur de la ciudad. El cluster 2, al concentrar más de la mitad de la oferta, se distribuye de manera generalizada por toda el área urbana analizada. Se observa también un entremezclado considerable entre los cuatro segmentos en la mayor parte del territorio, lo que indica que la segmentación obtenida responde primordialmente a características de tamaño y valorización de la vivienda, más que a una división estrictamente geográfica del mercado.

Análisis de Correspondencia

Como método final, se usa el análisis de correspondencias para representar posibles asociaciones entre variables categóricas, es decir, la asociación entre sus categorías, con el fin de establecer si existe, patrones o estructuras en los datos.

Se construye entonces la tabla cruzada con las variables invlucradas en el análisis:

  • Zona: Centro, Norte, Oeste, Oriente, Sur
  • Tipo: Apartamento, casa
tabla_tipo_zona <- table(vivienda_clean$tipo, vivienda_clean$zona)
tabla_tipo_zona
##              
##               Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
##   Apartamento          24       1198       1029           62     2787
##   Casa                100        722        169          289     1939

De antemano, en la tabla cruzada se puede observar que existe cierta asociación en la presencia de viviendas de tipo casa o apartamento con respecto a la zona que se analice. Sin embargo, para comprobar este resultado formalmente se realiza la prueba chi-cuadrado para verificar si existe asociacón significativa entre las variables de tipo y zona.

\[ H_0: \text{Las dos variables son independientes} \]

\[ H_1: \text{Las dos variables no son independientes} \]

chisq.test(tabla_tipo_zona)   # ¿existe asociación significativa entre tipo y zona?
## 
##  Pearson's Chi-squared test
## 
## data:  tabla_tipo_zona
## X-squared = 690.93, df = 4, p-value < 2.2e-16

El resultado de la prueba chi-cuadrado arroja un valor-p muy cercano a cero, por lo que se rechaza la hipótesis nula, indicando que las variables tipo y zona no son independientes y que por tanto existen relaciones entre sus categorías.

res.ca <- CA(tabla_tipo_zona, graph = FALSE)
res.ca$eig                      # inercia explicada por cada dimensión del AC
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.08305442                    100                               100

Dado que la variable tipo de vivienda cuenta con únicamente dos categorías (apartamento y casa), el Análisis de Correspondencias entre tipo y zona produce, por construcción, una única dimensión (rango = mín(2-1, 5-1) = 1), la cual explica el 100% de la inercia total. Por tanto, la relación entre ambas variables se representa mediante una proyección unidimensional en lugar del biplot bidimensional habitual, se decide realizar un Análisis de Correspondencias Múltiples (ACM), incluyendo variables suplementarias para poder graficar el mapa bidimensional

# Con 3 variables categóricas se usa Análisis de Correspondencias Múltiples
# (generalización del AC simple), incluyendo estrato como suplementaria.
vivienda_mca <- vivienda_clean %>%
  select(tipo, zona, barrio_agr, estrato) %>%
  as.data.frame()

res.mca <- MCA(vivienda_mca, quali.sup = 4, graph = FALSE)

res.mca$eig
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1  0.6256141               9.384212                          9.384212
## dim 2  0.5604926               8.407389                         17.791601
## dim 3  0.4665594               6.998391                         24.789992
## dim 4  0.3568515               5.352773                         30.142765
## dim 5  0.3354326               5.031488                         35.174253
g_mca_scree <- fviz_eig(res.mca, addlabels = TRUE,  labelsize = 12,
                         main = "Inercia explicada - ACM (tipo, zona, barrio)") +
  theme(
    plot.title = element_text(size = 25, face = "bold"), 
    axis.title = element_text(size = 20),                
    axis.text  = element_text(size = 20)                  
  )
g_mca_scree

La inercia explicada en el ACM por eje es baja acumulando solo el 17.8% entre los dos primeros ejes, lo cual parece muy poco comparado con el porcentaje acumulado que se lograba en el ACP con la misma cantidad de componentes, sin embargo, esto es una característica matemática esperada del ACM, no una señal de mala calidad de análisis.

El ACM trabaja sobre la tabla de Burt (todas las categorías cruzadas contra todas), lo que infla artificialmente el denominador de la inercia total y hace que los porcentajes por eje se vean sistemáticamente más bajos que en un ACP, incluso cuando la estructura subyacente es fuerte.

g_mca <- fviz_mca_var(res.mca, repel = TRUE, col.var = "cos2",
                       gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
                       title = "ACM: categorías de tipo, zona, barrio y estrato (supl.)")+
  theme(
    plot.title = element_text(size = 25, face = "bold"),  
    axis.title = element_text(size = 20),                
    axis.text  = element_text(size = 20),
    legend.title = element_text(size = 20),                 
    legend.text  = element_text(size = 15)
  )
g_mca

El gráfico muestra en la esquina derecha agrupados la zona Oeste, barrio Aguacatal, Los Cristales, Santa Teresita y Normandía, que son prácticamente los mismos barrios que dominaban el cluster 4 (alta valorización por \(m^2\), sobrerrepresentado en Zona Oeste) que se identificó en el clustering.

Por otro lado, en la esquina inferior izquierda se concentran Zona Centro, Zona Oriente, Zona Sur y varios barrios asociados (ciudad jardín, el refugio, el caney, pance, el ingenio) — el lado opuesto del mapa a Zona Oeste, coherente con el patrón de estrato bajo/valorización baja que se identificó como el cluster 3 del k-means.

# Contribución de cada categoría a las dos primeras dimensiones del ACM
round(res.mca$var$contrib, 2)
##                  Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
## Apartamento       4.39  0.14  8.01  3.27  0.00
## Casa              6.95  0.22 12.68  5.18  0.00
## Zona Centro       0.36  0.34  7.45  2.72 36.97
## Zona Norte        0.33 33.76  4.18  0.20  0.00
## Zona Oeste       37.25  0.24  2.83  0.72  0.00
## Zona Oriente      1.09  0.89 22.47  5.84 12.88
## Zona Sur          5.39 14.51  1.63  0.05  0.00
## acopi             0.06  5.94  1.64  6.08  1.42
## aguacatal         5.45  0.08  0.24  0.68  0.00
## ciudad jardín     1.61  3.12  0.00 25.69  0.87
## el caney          0.43  1.97  0.67  0.50  0.06
## el ingenio        0.28  1.36  0.54  0.14  0.03
## el limonar        0.39  0.82  0.00  5.80  0.21
## el refugio        0.14  0.81  0.36  0.03  0.01
## la flora          0.01 16.61  9.63  0.66  6.39
## la hacienda       0.20  1.12  0.55  0.00  0.01
## los cristales    11.72  0.15  0.62  2.17  0.01
## normandía         8.47  0.13  0.12  0.01  0.00
## pance             0.96  2.55  0.10  8.58  0.77
## prados del norte  0.00  4.54  2.69  0.00 40.06
## santa teresita   13.14  0.20  0.21  0.13  0.00
## valle del lili    0.38  7.22 10.76 25.84  0.25
## Otros             0.98  3.26 12.61  5.73  0.01

La Zona Oeste domina el eje 1 con 37.25% de contribución más que todas las demás categorías juntas. Además, se destaca que los barrios asociados (santa teresita 13.14%, los cristales 11.72%, normandía 8.47%, aguacatal 5.45%) suman, junto con Zona Oeste, más del 75% de la definición de este eje, por lo que la Dim 1 no es un eje genérico, sino que representa el contraste de la Zona Oeste con el resto de la ciudad.

Por su parte, la Zona Norte (33.76%) domina el eje 2, junto con el barrio la flora (16.61%) y prados del norte (4.54%) del mismo lado, contrastando con Zona Sur (14.51%) y sus barrios (valle del lili 7.22%) del lado opuesto.

Conclusiones y Recomendaciones

  • La oferta de vivienda analizada refleja un mercado fuertemente segmentado por zona geográfica y esta a su vez actúa como un indicador casi directo del nivel socioeconómico. La Zona Oeste concentra las viviendas de mayor estrato, mayor precio y mayor valorización por metro cuadrado, mientras que Zona Oriente y Zona Centro se caracterizan por estrato 3, predominio de casas y menor valorización relativa, lo cual es una asociación confirmada de forma independiente por el análisis bivariado, el ACP, el clustering y el ACM.

  • El precio de la vivienda no puede explicarse por una sola dimensión. El Análisis de Componentes Principales identificó dos componentes claramente diferenciados: uno de magnitud/tamaño (precio absoluto, área, baños, parqueaderos), que explica el 52.2% de la varianza, y otro de valorización relativa por metro cuadrado (precio_m2), con 25.5% adicional. Esta separación evidencia que “grande y caro” y “caro por metro cuadrado” son fenómenos distintos del mercado, lo cual confirma la existencia de economías de escala: las viviendas más grandes no son necesariamente las más eficientes en precio por metro.

  • La segmentación en cuatro conglomerados, validada de forma convergente mediante el método del codo y el clustering jerárquico, identifica perfiles de mercado con implicaciones comerciales claras. Muestra un segmento masivo de apartamentos de menor tamaño y precio (53% de la oferta), un segmento reducido de casas de gran tamaño y alto precio absoluto pero valorización moderada por metro, otro segmento premium de alta valorización por metro cuadrado fuertemente concentrado en Zona Oeste y un segmento de casas de menor valorización relativa, sobrerrepresentado en Zona Oriente y estratos medios-bajos.

  • El Análisis de Correspondencias Múltiples confirmó, con una técnica estadística independiente, la existencia de un ecosistema de mercado premium claramente diferenciado, anclado en Zona Oeste y barrios específicos (Santa Teresita, Los Cristales, Normandía, Aguacatal), replicando el mismo patrón detectado en el clustering, lo que evidencia que los hallazgos del estudio son robustos frente a distintas metodologías, no artefactos de una técnica en particular.

Con base en los hallazgos anteriores, se recomienda a la empresa inmobiliaria dirigir sus estrategias de valoración y comercialización de forma diferenciada por segmento de mercado, en lugar de aplicar criterios homogéneos a toda su cartera de propiedades. Para el segmento premium concentrado en Zona Oeste (cluster 4, alta valorización por metro cuadrado), la estrategia comercial debería enfatizar el precio por metro cuadrado como indicador de valor, dado que es la variable que mejor diferencia a este segmento del resto del mercado. Para el segmento de casas grandes en zonas de estrato medio-bajo (cluster 3, sobrerrepresentado en Zona Oriente), conviene evitar valoraciones basadas únicamente en el precio total, ya que estas propiedades muestran sistemáticamente un menor valor por metro cuadrado, y una estrategia de precio ajustada a esta realidad puede mejorar la rotación de este inventario.

Asimismo, dado que zona y estrato están altamente asociados en los datos analizados, se recomienda que futuros levantamientos de información recopilen ambas variables de forma independiente y verificada, para poder distinguir con mayor precisión el efecto de la ubicación del efecto puramente socioeconómico sobre el precio. Finalmente, se sugiere extender este análisis periódicamente conforme se actualice la base de datos, con el fin de monitorear si la estructura de segmentos identificada, especialmente la del cluster 1 (casas de gran tamaño y alto precio absoluto) y el cluster 2 (mercado masivo de apartamentos, más de la mitad de la oferta), se mantiene estable en el tiempo o si emergen nuevos patrones de oferta que ameriten ajustes en la estrategia comercial de la empresa.

Anexos

Anexo A: Diccionario de variables derivadas

Además de las variables originales de la base vivienda, se construyeron las siguientes variables durante el proceso de análisis:

Variable Tipo Descripción
precio_m2 Cuantitativa continua (derivada) Precio por metro cuadrado (preciom / areaconst), en millones COP/m²
barrio_std Cualitativa nominal (derivada) Nombre del barrio estandarizado (sin tildes, espacios extra ni duplicados de escritura)
barrio_agr Cualitativa nominal (derivada) Barrio agrupado en top 15 + categoría “Otros”, usado en el Análisis de Correspondencias Múltiples
cluster Cualitativa nominal (derivada) Segmento asignado a cada vivienda por el algoritmo k-means (1 a 4)

Anexo B: Contribuciones y cos² completos del ACP (Dim 1-5)

kable(round(res.pca$var$contrib, 2),
      caption = "Contribución de las variables activas a cada componente (%)") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) %>%
  scroll_box(width = "100%", height = "auto")
Contribución de las variables activas a cada componente (%)
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
preciom 23.21 9.98 0.32 16.68 4.85
areaconst 23.15 4.73 15.03 18.76 2.88
precio_m2 0.05 55.69 20.50 0.53 3.91
parqueaderos 16.85 8.07 17.82 56.77 0.42
banios 24.58 0.17 12.13 0.01 62.93
habitaciones 12.15 21.36 34.20 7.26 25.00
kable(round(res.pca$var$cos2, 2),
      caption = "Cos² de las variables activas por componente") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) %>%
  scroll_box(width = "100%", height = "auto")
Cos² de las variables activas por componente
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
preciom 0.73 0.15 0.00 0.07 0.01
areaconst 0.72 0.07 0.09 0.08 0.01
precio_m2 0.00 0.85 0.12 0.00 0.01
parqueaderos 0.53 0.12 0.10 0.24 0.00
banios 0.77 0.00 0.07 0.00 0.16
habitaciones 0.38 0.33 0.20 0.03 0.06
kable(round(res.pca$eig, 2),
      caption = "Eigenvalues y varianza explicada - ACP (5 dimensiones)") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) %>%
  scroll_box(width = "100%", height = "auto")
Eigenvalues y varianza explicada - ACP (5 dimensiones)
eigenvalue percentage of variance cumulative percentage of variance
comp 1 3.13 52.16 52.16
comp 2 1.53 25.49 77.65
comp 3 0.58 9.70 87.35
comp 4 0.43 7.17 94.53
comp 5 0.25 4.17 98.70

Adicionalmente, se presenta el listado de las viviendas con mayor contribución a la formación de los dos primeros componentes:

top20_dim1 <- res.pca$ind$contrib[order(-res.pca$ind$contrib[, 1]), ][1:20, 1:2]
top20_dim2 <- res.pca$ind$contrib[order(-res.pca$ind$contrib[, 2]), ][1:20, 1:2]

kable(round(top20_dim1, 4), caption = "Top 20 viviendas - mayor contribución al eje 1") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) %>%
  scroll_box(width = "100%", height = "300px")
Top 20 viviendas - mayor contribución al eje 1
Dim.1 Dim.2
5684 0.3975 0.0016
5396 0.2805 0.0585
3652 0.2766 0.0035
5004 0.2741 0.0015
6766 0.2657 0.0749
8298 0.2554 0.0009
673 0.2511 0.0012
5978 0.2485 0.0060
5902 0.2367 0.0139
4564 0.2345 0.0128
4308 0.2285 0.0012
4559 0.2269 0.0029
5467 0.2253 0.0120
5710 0.2240 0.0166
315 0.2190 0.0123
4238 0.2179 0.0026
5664 0.2143 0.0002
4340 0.2138 0.0201
5862 0.2133 0.0790
6433 0.2048 0.0000
kable(round(top20_dim2, 4), caption = "Top 20 viviendas - mayor contribución al eje 2") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) %>%
  scroll_box(width = "100%", height = "300px")
Top 20 viviendas - mayor contribución al eje 2
Dim.1 Dim.2
534 0.1287 0.2687
7366 0.0284 0.2566
4112 0.0172 0.2295
5094 0.0374 0.2159
8020 0.0394 0.1914
921 0.0231 0.1770
684 0.0248 0.1659
4508 0.0918 0.1609
5151 0.0243 0.1561
5474 0.1662 0.1561
7505 0.1205 0.1546
450 0.0264 0.1539
8249 0.0431 0.1530
5154 0.1364 0.1503
6928 0.0490 0.1424
4407 0.0103 0.1409
1017 0.0236 0.1396
8022 0.0492 0.1394
7871 0.0214 0.1392
7303 0.0074 0.1371

Anexo C: Listado de barrios originales

table(vivienda$barrio)
## 
##                             20 de julio                              3 de julio 
##                                       3                                       1 
##                                   acopi                             agua blanca 
##                                     158                                       1 
##                              aguablanca                               aguacatal 
##                                       2                                     109 
##                                 alameda                        alameda del río 
##                                      16                                       2 
##                         alameda del rio                                  alamos 
##                                       1                                      14 
##                                alborada                               alcazares 
##                                       1                                       2 
##              alfâ\u0088\u009a©rez real                            alferez real 
##                                       5                                       2 
##                          alfonso lópez                        alfonso lópez i 
##                                      21                                       1 
##                           alfonso lopez                            alto jordán 
##                                       1                                       1 
##                      altos de guadalupe                          altos de menga 
##                                       4                                       3 
##                          altos de santa                         antonio nariño 
##                                       1                                       2 
##                                aranjuez                                arboleda 
##                                      15                                       5 
##           arboleda campestre candelaria                               arboledas 
##                                       1                                      38 
##                       atanasio girardot                           autopista sur 
##                                       9                                       1 
##                          bajo aguacatal                            barranquilla 
##                                       1                                       6 
##                       barrio 7de agosto                      barrio el recuerdo 
##                                       1                                       1 
##                     barrio eucarístico                           barrio obrero 
##                                       1                                       1 
##                      barrio tranquilo y                base aâ\u0088\u009a©rea 
##                                       1                                       2 
##                              belalcazar                              Belalcazar 
##                                       3                                       1 
##                       belisario caicedo                             bella suiza 
##                                       2                                      18 
##                        bella suiza alta                              bellavista 
##                                       4                                      43 
##                       benjamín herrera                                  berlin 
##                                       8                                       1 
##                     bloques del limonar                               bochalema 
##                                       1                                      33 
##                             bolivariano                     bosques de alboleda 
##                                       1                                       1 
##                     bosques del limonar                                 boyacá 
##                                      21                                       1 
##                                bretaña                     brisas de guadalupe 
##                                      16                                       1 
##                           brisas de los                           Brisas De Los 
##                                      81                                       1 
##                      brisas del guabito                      brisas del limonar 
##                                       1                                       1 
##                            Bueno Madrid                            buenos aires 
##                                       1                                       7 
##                            cañasgordas                           cañaveralejo 
##                                       7                                      12 
##                            cañaverales                cañaverales los samanes 
##                                      21                                       1 
##                                  caldas                                    Cali 
##                                       1                                      37 
##                              cali bella                              cali canto 
##                                       1                                       1 
##                               calibella                               calicanto 
##                                       1                                       8 
##                          calicanto viii                                  calima 
##                                       1                                       6 
##                           calimio norte                                 calipso 
##                                       5                                      11 
##                                cambulos                             camino real 
##                                       3                                      35 
##                             Camino Real                               campestre 
##                                       1                                       1 
##                                   caney                          caney especial 
##                                      88                                       5 
##                                   capri                                cascajal 
##                                      56                                       1 
##                             cataya real                                  ceibas 
##                                       1                                       1 
##                                centelsa                              centenario 
##                                       1                                      15 
##                              Centenario                                  centro 
##                                       1                                       4 
##                         cerro cristales                     cerros de guadalupe 
##                                      22                                       1 
##                              champagnat                               chapinero 
##                                      14                                       7 
##                             chiminangos                             Chiminangos 
##                                      17                                       1 
##                     chiminangos 1 etapa                     chiminangos 2 etapa 
##                                       1                                       2 
##                              chipichape                             ciudad 2000 
##                                      30                                      95 
##                             Ciudad 2000                       ciudad antejardin 
##                                       1                                       1 
##                        ciudad bochalema                         ciudad córdoba 
##                                      48                                      15 
##               ciudad córdoba reservado                            ciudad capri 
##                                       1                                      13 
##                          ciudad cordoba                          ciudad country 
##                                      20                                       1 
##                        ciudad del campo                          ciudad jardín 
##                                       1                                     516 
##                          Ciudad Jardín                           ciudad jardin 
##                                       2                                      22 
##                     ciudad jardin pance                      ciudad los álamos 
##                                       1                                      25 
##                       ciudad los alamos           ciudad melâ\u0088\u009a©ndez 
##                                       1                                       1 
##                         ciudad melendez                           ciudad modelo 
##                                       1                                       7 
##                         ciudad pacifica                         Ciudad Pacifica 
##                                       2                                       1 
##                             ciudad real                          ciudad talanga 
##                                       3                                       1 
##                    ciudad universitaria                      ciudadela comfandi 
##                                       1                                      17 
##                      ciudadela del río                      ciudadela melendez 
##                                       1                                       1 
##                    ciudadela paso ancho                     ciudadela pasoancho 
##                                       1                                      21 
##                        colinas de menga                      colinas del bosque 
##                                       3                                       1 
##                         colinas del sur                                   colon 
##                                       8                                       1 
##                              colseguros                        colseguros andes 
##                                      44                                       4 
##                        Colseguros Andes                              comfenalco 
##                                       1                                       1 
##                               compartir                      conjunto gibraltar 
##                                       1                                       1 
##                       cristóbal colón                               cristales 
##                                       2                                      83 
##                        cristobal colón                         cuarto de legua 
##                                      14                                      44 
##                           departamental                     ed benjamin herrera 
##                                      29                                       1 
##                               el bosque                               El Bosque 
##                                      49                                       1 
##                                el caney                                El Caney 
##                                     208                                       1 
##                             el castillo                                el cedro 
##                                       6                                       8 
##                             el diamante                               el dorado 
##                                       2                                       6 
##                         el gran limonar                               el guabal 
##                                       8                                      19 
##                              el guabito                              el ingenio 
##                                       1                                     202 
##                              El Ingenio                            el ingenio 3 
##                                       1                                       1 
##                            el ingenio i                           el ingenio ii 
##                                      19                                      21 
##                          el ingenio iii                              el jardín 
##                                      20                                      15 
##                              el jordán                                 el lido 
##                                       1                                      59 
##                              el limonar                             el nacional 
##                                     135                                       1 
##                             el paraíso                               el peñon 
##                                       3                                      60 
##                                el prado                              el refugio 
##                                       2                                     120 
##                                el rodeo                                 el sena 
##                                       1                                       1 
##                 el trâ\u0088\u009a©bol                              el troncal 
##                                       5                                      19 
##                              el vallado                            eucarístico 
##                                       1                                       2 
##                        evaristo garcía                    farrallones de pance 
##                                       2                                       1 
##                         fenalco kennedy                                 fepicol 
##                                       1                                       1 
##                                   flora                        flora industrial 
##                                       1                                      16 
##                                floralia                            fonaviemcali 
##                                       6                                       1 
##                francisco eladio ramirez                           fuentes de la 
##                                       1                                       1 
##                                  gaitan                            gran limonar 
##                                       1                                      24 
##                                 granada                               guadalupe 
##                                      15                                      21 
##                          guadalupe alto                               guaduales 
##                                       1                                       2 
##                               guayaquil                   hacienda alferez real 
##                                      16                                       1 
##                                 ingenio                               ingenio i 
##                                       1                                       1 
##                              ingenio ii                                 jamundi 
##                                       1                                       4 
##                       jamundi alfaguara                   jorge eliecer gaitán 
##                                       1                                       1 
##                            jorge isaacs                  jose manuel marroquín 
##                                       1                                       1 
##            juanambâ\u0088\u009aâ\u0088«                                juanambu 
##                                      53                                       2 
##                                  junín                                   junin 
##                                       6                                      18 
##                             la alborada                              la alianza 
##                                       5                                       5 
##                             la arboleda                                 la base 
##                                      18                                      15 
##                             la buitrera                             la campiña 
##                                       3                                      13 
##                              la cascada                               la ceibas 
##                                       7                                       1 
##                            la esmeralda                                la flora 
##                                       1                                     366 
##                                La Flora                             la floresta 
##                                       2                                      18 
##                            la fortaleza                        la gran colombia 
##                                       4                                       1 
##                             la hacienda                             La Hacienda 
##                                     164                                       2 
##                        la independencia                             la libertad 
##                                      12                                       2 
##                                la luisa                               la merced 
##                                       1                                      26 
##                               la morada                           la nueva base 
##                                       1                                       8 
##                                la playa                           la portada al 
##                                       1                                       1 
##                            la primavera                              la reforma 
##                                       1                                       1 
##                               la rivera                             la rivera i 
##                                      11                                       2 
##                            la rivera ii                             la riverita 
##                                       2                                       1 
##                              la riviera                                la selva 
##                                       1                                      11 
##                            la villa del                                 laflora 
##                                       1                                       1 
##                     lares de comfenalco                             las acacias 
##                                       1                                      12 
##              las amâ\u0088\u009a©ricas                            las camelias 
##                                       3                                       1 
##                              las ceibas                            las delicias 
##                                      23                                       5 
##                             las granjas                          las quintas de 
##                                      10                                       1 
##                               las vegas                            las vegas de 
##                                       1                                       1 
##                            libertadores                              los alamos 
##                                       3                                       1 
##                          los alcázares                           los alcazares 
##                                       5                                      17 
##                               los andes                           los cámbulos 
##                                      21                                       6 
##                            los cambulos                           los cristales 
##                                      25                                     154 
##                      los cristales club                          los farallones 
##                                       1                                       4 
##                           los guaduales                           Los Guaduales 
##                                      25                                       1 
##                          los guayacanes                             los jockeys 
##                                       3                                       1 
##                        los libertadores                los parques barranquilla 
##                                       4                                       6 
##                              los robles                                 lourdes 
##                                       1                                       2 
##                                mamellan                              manzanares 
##                                       1                                       5 
##                           mariano ramos                          marroquín iii 
##                                       1                                       1 
##                       mayapan las vegas                  melâ\u0088\u009a©ndez 
##                                      46                                      23 
##                                melendez                                   menga 
##                                      52                                      23 
##                 metropolitano del norte                   miradol del aguacatal 
##                                      21                                       1 
##                              miraflores                              Miraflores 
##                                      25                                       1 
##                    morichal de comfandi                             multicentro 
##                                       3                                      27 
##                               municipal                                nápoles 
##                                       3                                      29 
##                                 napoles                              normandía 
##                                       2                                     154 
##                   normandía west point                               normandia 
##                                       1                                       5 
##                                   norte                          norte la flora 
##                                       9                                       1 
##                              nueva base                          nueva floresta 
##                                       1                                      15 
##                        nueva tequendama                       oasis de comfandi 
##                                      73                                       6 
##                      oasis de pasoancho                               occidente 
##                                       1                                      11 
##                                  pacara                                 pacará 
##                                      19                                       4 
##                      palmas del ingenio                             pampa linda 
##                                       1                                      26 
##                              pampalinda                            panamericano 
##                                      12                                       9 
##                                   pance                                   Pance 
##                                     409                                       3 
##                     parcelaciones pance                   parque residencial el 
##                                      61                                       1 
##                            paseo de los                       paso del comercio 
##                                       2                                       6 
##                               pasoancho                       poblado campestre 
##                                       6                                       2 
##                                   ponce                                 popular 
##                                       1                                       6 
##                     portada de comfandi                    portales de comfandi 
##                                       2                                       1 
##                                porvenir                       prados de oriente 
##                                       3                                       6 
##                      prados del limonar                      Prados Del Limonar 
##                                      20                                       1 
##                        prados del norte                        Prados Del Norte 
##                                     126                                       1 
##                          prados del sur                               primavera 
##                                       2                                       2 
##                         primero de mayo                        primitivo crespo 
##                                      37                                       3 
##                     puente del comercio                            puente palma 
##                                       6                                       1 
##                          quintas de don                          Quintas De Don 
##                                      72                                       1 
##                      quintas de salomia                      rafael uribe uribe 
##                                       4                                       1 
##                                 refugio repâ\u0088\u009aâ\u0088«blica de israel 
##                                       2                                       1 
##                      rincón de salomia                            rincon de la 
##                                       1                                       1 
##                       riveras del valle                           rozo la torre 
##                                       1                                       1 
##                        saavedra galindo                                 salomia 
##                                       4                                      40 
##                                 samanes                    samanes de guadalupe 
##                                       1                                       1 
##                                  sameco                             san antonio 
##                                       1                                      24 
##                               san bosco                              san carlos 
##                                       8                                       4 
##                            san cayetano                            san fernando 
##                                       9                                      54 
##                            San Fernando                      san fernando nuevo 
##                                       1                                      10 
##                      san fernando viejo                            san joaquín 
##                                      18                                      16 
##                             san joaquin                          san juan bosco 
##                                       4                                       7 
##                               san judas                         san judas tadeo 
##                                       1                                       2 
##                               san luís                                san luis 
##                                       1                                       2 
##                            san nicolás                             san nicolas 
##                                       1                                       1 
##                               san pedro                             san vicente 
##                                       3                                      48 
##                                   santa                             santa anita 
##                                       1                                      48 
##                             Santa Anita                         santa anita sur 
##                                       2                                       1 
##                          santa bárbara                             santa elena 
##                                       3                                      10 
##                                santa fe                         santa helena de 
##                                       8                                       1 
##                            santa isabel                            Santa Isabel 
##                                      63                                       1 
##                           santa mónica                      santa mónica alta 
##                                       3                                       1 
##                   santa mónica popular               santa mónica residencial 
##                                       7                                      39 
##                            santa monica                            Santa Monica 
##                                      51                                       1 
##                      santa monica norte                    santa monica popular 
##                                       2                                       2 
##                santa monica residencial                              santa rita 
##                                       5                                      45 
##                              santa rosa                          santa teresita 
##                                       1                                     262 
##                          Santa Teresita                                 Santafe 
##                                       1                                       1 
##                               santander                           santo domingo 
##                                       1                                       5 
##                           Santo Domingo                        sector aguacatal 
##                                       1                                       1 
##          sector cañaveralejo guadalupe                               seminario 
##                                       2                                      32 
##                   sierras de normandía                         siete de agosto 
##                                       1                                       8 
##                          simón bolivar                       tejares cristales 
##                                       1                                       4 
##                          tejares de san                                templete 
##                                      14                                       4 
##                              tequendama                              tequendema 
##                                      44                                       1 
##                        terrón colorado                      torres de comfandi 
##                                       1                                      57 
##                      unión de vivienda                          unicentro cali 
##                                       3                                       1 
##              urbanización barranquilla                   urbanización boyacá 
##                                       4                                       1 
##                urbanización colseguros                  urbanización la flora 
##                                       3                                      83 
##                 urbanización la merced                  urbanización la nueva 
##                                       4                                       4 
##              urbanización las cascadas             urbanización nueva granada 
##                                       1                                       3 
##                    urbanización pacara                 urbanización río lili 
##                                       1                                       5 
##               urbanización san joaquin                urbanización tequendama 
##                                       4                                       7 
##                   urbanizacion el saman                  urbanizacion gratamira 
##                                       1                                       1 
##                       urbanizacion lili                           valle de lili 
##                                       2                                       1 
##                          valle del lili                          Valle Del Lili 
##                                    1008                                       1 
##                            valle grande                               versalles 
##                                       1                                      71 
##                          villa colombia                       villa de veracruz 
##                                       6                                       6 
##                          villa del lago                        villa del parque 
##                                      10                                       1 
##                         villa del prado                         Villa Del Prado 
##                                      51                                       1 
##                           villa del sol                           villa del sur 
##                                      25                                       5 
##                      villas de veracruz                      Villas De Veracruz 
##                                       8                                       1 
##                                  vipasa                             zona centro 
##                                      32                                       1 
##                              zona norte                          zona norte los 
##                                      32                                       1 
##                              zona oeste                            zona oriente 
##                                      26                                      18 
##                        zona residencial                                zona sur 
##                                       1                                      74

Anexo D: Tabla de equivalencias de estandarización de barrios

tabla_equivalencias <- vivienda %>%
  distinct(barrio, barrio_clave, barrio_std) %>%
  arrange(barrio_clave) %>%
  group_by(barrio_clave) %>%
  filter(n() > 1)

kable(tabla_equivalencias, caption = "Equivalencia entre nombre original y nombre estandarizado de barrio") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 12) %>%
  scroll_box(width = "100%", height = "400px")
Equivalencia entre nombre original y nombre estandarizado de barrio
barrio barrio_clave barrio_std
agua blanca aguablanca aguablanca
aguablanca aguablanca aguablanca
alameda del río alamedadelrio alameda del río
alameda del rio alamedadelrio alameda del río
alamos alamos alamos
los alamos alamos alamos
alborada alborada la alborada
la alborada alborada la alborada
alcazares alcazares los alcazares
los alcázares alcazares los alcazares
los alcazares alcazares los alcazares
alfonso lópez alfonsolopez alfonso lópez
alfonso lopez alfonsolopez alfonso lópez
arboleda arboleda la arboleda
la arboleda arboleda la arboleda
barranquilla barranquilla barranquilla
urbanización barranquilla barranquilla barranquilla
belalcazar belalcazar belalcazar
Belalcazar belalcazar belalcazar
el bosque bosque el bosque
El Bosque bosque el bosque
boyacá boyaca boyacá
urbanización boyacá boyaca boyacá
brisas de los brisasdelos brisas de los
Brisas De Los brisasdelos brisas de los
cali bella calibella cali bella
calibella calibella cali bella
cali canto calicanto calicanto
calicanto calicanto calicanto
cambulos cambulos los cambulos
los cámbulos cambulos los cambulos
los cambulos cambulos los cambulos
camino real caminoreal camino real
Camino Real caminoreal camino real
caney caney el caney
el caney caney el caney
El Caney caney el caney
ceibas ceibas las ceibas
la ceibas ceibas las ceibas
las ceibas ceibas las ceibas
centenario centenario centenario
Centenario centenario centenario
chiminangos chiminangos chiminangos
Chiminangos chiminangos chiminangos
ciudad 2000 ciudad2000 ciudad 2000
Ciudad 2000 ciudad2000 ciudad 2000
ciudad córdoba ciudadcordoba ciudad cordoba
ciudad cordoba ciudadcordoba ciudad cordoba
ciudadela paso ancho ciudadelapasoancho ciudadela pasoancho
ciudadela pasoancho ciudadelapasoancho ciudadela pasoancho
ciudad jardín ciudadjardin ciudad jardín
Ciudad Jardín ciudadjardin ciudad jardín
ciudad jardin ciudadjardin ciudad jardín
ciudad los álamos ciudadlosalamos ciudad los álamos
ciudad los alamos ciudadlosalamos ciudad los álamos
ciudad pacifica ciudadpacifica ciudad pacifica
Ciudad Pacifica ciudadpacifica ciudad pacifica
colseguros colseguros colseguros
urbanización colseguros colseguros colseguros
colseguros andes colsegurosandes colseguros andes
Colseguros Andes colsegurosandes colseguros andes
cristales cristales los cristales
los cristales cristales los cristales
cristóbal colón cristobalcolon cristobal colón
cristobal colón cristobalcolon cristobal colón
flora flora la flora
la flora flora la flora
La Flora flora la flora
urbanización la flora flora la flora
el gran limonar granlimonar gran limonar
gran limonar granlimonar gran limonar
guaduales guaduales los guaduales
los guaduales guaduales los guaduales
Los Guaduales guaduales los guaduales
la hacienda hacienda la hacienda
La Hacienda hacienda la hacienda
el ingenio ingenio el ingenio
El Ingenio ingenio el ingenio
ingenio ingenio el ingenio
el ingenio i ingenioi el ingenio i
ingenio i ingenioi el ingenio i
el ingenio ii ingenioii el ingenio ii
ingenio ii ingenioii el ingenio ii
junín junin junin
junin junin junin
libertadores libertadores los libertadores
los libertadores libertadores los libertadores
la merced merced la merced
urbanización la merced merced la merced
miraflores miraflores miraflores
Miraflores miraflores miraflores
nápoles napoles nápoles
napoles napoles nápoles
normandía normandia normandía
normandia normandia normandía
la nueva base nuevabase la nueva base
nueva base nuevabase la nueva base
pacará pacara pacara
pacara pacara pacara
urbanización pacara pacara pacara
pampa linda pampalinda pampa linda
pampalinda pampalinda pampa linda
pance pance pance
Pance pance pance
prados del limonar pradosdellimonar prados del limonar
Prados Del Limonar pradosdellimonar prados del limonar
prados del norte pradosdelnorte prados del norte
Prados Del Norte pradosdelnorte prados del norte
la primavera primavera primavera
primavera primavera primavera
quintas de don quintasdedon quintas de don
Quintas De Don quintasdedon quintas de don
el refugio refugio el refugio
refugio refugio el refugio
san fernando sanfernando san fernando
San Fernando sanfernando san fernando
san joaquín sanjoaquin san joaquín
san joaquin sanjoaquin san joaquín
urbanización san joaquin sanjoaquin san joaquín
san luís sanluis san luis
san luis sanluis san luis
san nicolás sannicolas san nicolas
san nicolas sannicolas san nicolas
santa anita santaanita santa anita
Santa Anita santaanita santa anita
santa fe santafe santa fe
Santafe santafe santa fe
santa isabel santaisabel santa isabel
Santa Isabel santaisabel santa isabel
santa mónica santamonica santa monica
santa monica santamonica santa monica
Santa Monica santamonica santa monica
santa mónica popular santamonicapopular santa mónica popular
santa monica popular santamonicapopular santa mónica popular
santa mónica residencial santamonicaresidencial santa mónica residencial
santa monica residencial santamonicaresidencial santa mónica residencial
santa teresita santateresita santa teresita
Santa Teresita santateresita santa teresita
santo domingo santodomingo santo domingo
Santo Domingo santodomingo santo domingo
tequendama tequendama tequendama
urbanización tequendama tequendama tequendama
valle del lili valledellili valle del lili
Valle Del Lili valledellili valle del lili
villa del prado villadelprado villa del prado
Villa Del Prado villadelprado villa del prado
Villas De Veracruz villasdeveracruz villas de veracruz
villas de veracruz villasdeveracruz villas de veracruz

Anexo E: Contribuciones completas del ACM por categoría

kable(round(res.mca$var$contrib, 2),
      caption = "Contribución de cada categoría a las 5 dimensiones del ACM") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) %>%
  scroll_box(width = "100%", height = "400px")
Contribución de cada categoría a las 5 dimensiones del ACM
Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
Apartamento 4.39 0.14 8.01 3.27 0.00
Casa 6.95 0.22 12.68 5.18 0.00
Zona Centro 0.36 0.34 7.45 2.72 36.97
Zona Norte 0.33 33.76 4.18 0.20 0.00
Zona Oeste 37.25 0.24 2.83 0.72 0.00
Zona Oriente 1.09 0.89 22.47 5.84 12.88
Zona Sur 5.39 14.51 1.63 0.05 0.00
acopi 0.06 5.94 1.64 6.08 1.42
aguacatal 5.45 0.08 0.24 0.68 0.00
ciudad jardín 1.61 3.12 0.00 25.69 0.87
el caney 0.43 1.97 0.67 0.50 0.06
el ingenio 0.28 1.36 0.54 0.14 0.03
el limonar 0.39 0.82 0.00 5.80 0.21
el refugio 0.14 0.81 0.36 0.03 0.01
la flora 0.01 16.61 9.63 0.66 6.39
la hacienda 0.20 1.12 0.55 0.00 0.01
los cristales 11.72 0.15 0.62 2.17 0.01
normandía 8.47 0.13 0.12 0.01 0.00
pance 0.96 2.55 0.10 8.58 0.77
prados del norte 0.00 4.54 2.69 0.00 40.06
santa teresita 13.14 0.20 0.21 0.13 0.00
valle del lili 0.38 7.22 10.76 25.84 0.25
Otros 0.98 3.26 12.61 5.73 0.01
kable(round(res.mca$eig, 2),
      caption = "Eigenvalues y varianza explicada - ACM (5 dimensiones)") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE, font_size = 13) %>%
  scroll_box(width = "100%", height = "auto")
Eigenvalues y varianza explicada - ACM (5 dimensiones)
eigenvalue percentage of variance cumulative percentage of variance
dim 1 0.63 9.38 9.38
dim 2 0.56 8.41 17.79
dim 3 0.47 7.00 24.79
dim 4 0.36 5.35 30.14
dim 5 0.34 5.03 35.17

Anexo F: Razón de varianza inter/intra-clase del clustering final

prop_explicada <- res.kmeans$betweenss / res.kmeans$totss

cat("Suma de cuadrados total (totss):", round(res.kmeans$totss, 1), "\n")
## Suma de cuadrados total (totss): 49908
cat("Suma de cuadrados intra-cluster (tot.withinss):", round(res.kmeans$tot.withinss, 1), "\n")
## Suma de cuadrados intra-cluster (tot.withinss): 22058.8
cat("Suma de cuadrados inter-cluster (betweenss):", round(res.kmeans$betweenss, 1), "\n")
## Suma de cuadrados inter-cluster (betweenss): 27849.2
cat("Proporción de varianza explicada por la segmentación:", round(prop_explicada * 100, 1), "%\n")
## Proporción de varianza explicada por la segmentación: 55.8 %