1 Descripción del problema

Una empresa inmobiliaria líder en una gran ciudad está buscando comprender en profundidad el mercado de viviendas urbanas para tomar decisiones estratégicas más informadas. La empresa posee una base de datos extensa que contiene información detallada sobre diversas propiedades residenciales disponibles en el mercado. Se requiere realizar un análisis holístico de estos datos para identificar patrones, relaciones y segmentaciones relevantes que permitan mejorar la toma de decisiones en cuanto a la compra, venta y valoración de propiedades.

2 Retos

El reto principal consisten en realizar un análisis integral y multidimensional de la base de datos para obtener una comprensión del mercado inmobiliario urbano. Se requiere aplicar diversas técnicas de análisis de datos, incluyendo:

  1. Análisis de Componentes Principales: Reducir la dimensionalidad del conjunto de datos y visualizar la estructura de las variables en componentes principales para identificar características clave que influyen en la variación de precios y oferta del mercado.

  2. Análisis de Conglomerados: Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas de las ofertas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.

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

  4. Visualización de resultados: Presentar gráficos, mapas y otros recursos visuales para comunicar los hallazgos de manera clara y efectiva a la dirección de la empresa.

El informe final debe incluir análisis detallados de los resultados obtenidos, las conclusiones clave y las recomendaciones específicas para guiar las decisiones estratégicas de la empresa inmobiliaria. Se espera que este análisis de datos proporcione ventajas competitivas en el mercado, optimizando la inversión y maximizando los beneficios en un entorno altamente competitivo y en constante cambio.

3 Codigo

3.1 Importacion de librerias

library(paqueteMODELOS)
library(stringr)
library(stringi)
library(e1071)
library(mice)
library(naniar)
library(ggplot2)
library(factoextra)
library(tidyverse)
library(cluster)
library(FactoMineR)
library(factoextra)
library(knitr)
library(cluster)
library(gt)

3.2 Importacion de los datos

3.3 Analisis exploratorio de datos

3.3.1 Datos repetidos

duplicados <- duplicated(data)
sum(duplicados)
data1 <- data[!duplicados, ]

3.3.2 Inconsistencias variables cualitativas

Con el siguiente codigo se encontro en la columna barrio valores incoherentes que fueron sustituidos:

3.3.3 Estadistica descriptiva datos ‘crudos’

Con el siguiente codigo, lo que se busca es una tabla (Tabla 3.1) que muestre todo tipo de indicadores estadisticos relevantes de los datos.

descriptiva_cuantitativas <- function(data, vars,
                                      digits = 3,
                                      caption = "3.1. Indicadores estadisticos descriptivos de cada variable cuantitativa",
                                      imprimir = TRUE) {
  # Chequeo: solo variables existentes
  vars_ok <- vars[vars %in% names(data)]
  if (length(vars_ok) == 0) stop("Ninguna variable de 'vars' existe en el data.")
  if (length(vars_ok) < length(vars)) {
    warning("Estas variables no existen y se ignoraron: ",
            paste(setdiff(vars, vars_ok), collapse = ", "))
  }

  X <- data[, vars_ok, drop = FALSE]

  # Estadísticos (con NA-safe)
  N <- colSums(!is.na(X))

  Promedio <- sapply(X, mean, na.rm = TRUE)
  DesvEstandar <- sapply(X, sd, na.rm = TRUE)
  IQRv <- sapply(X, IQR, na.rm = TRUE)

  Q1 <- sapply(X, quantile, probs = 0.25, na.rm = TRUE, names = FALSE)
  Q3 <- sapply(X, quantile, probs = 0.75, na.rm = TRUE, names = FALSE)

  Minimo <- sapply(X, min, na.rm = TRUE)
  Maximo <- sapply(X, max, na.rm = TRUE)

  CV <- sapply(X, function(x) {
    m <- mean(x, na.rm = TRUE)
    s <- sd(x, na.rm = TRUE)
    if (is.na(m) || m == 0) NA else (s / m) * 100
  })

  # Asimetría y curtosis (si e1071 está disponible)
  if (!requireNamespace("e1071", quietly = TRUE)) {
    warning("No está instalado 'e1071'. Asimetria y Curtosis se dejarán como NA.")
    Asimetria <- rep(NA, length(vars_ok))
    Curtosis  <- rep(NA, length(vars_ok))
    names(Asimetria) <- vars_ok
    names(Curtosis)  <- vars_ok
  } else {
    Asimetria <- sapply(X, function(x) e1071::skewness(x, na.rm = TRUE, type = 2))
    Curtosis  <- sapply(X, function(x) e1071::kurtosis(x,  na.rm = TRUE, type = 2))
  }

  # Tabla final
  tabla <- data.frame(
    "Variables cuantitativas" = vars_ok,
    N = N,
    Promedio = round(Promedio, digits),
    "Desv. Estandar" = round(DesvEstandar, digits),
    IQR = round(IQRv, digits),
    Q1 = round(Q1, digits),
    Q3 = round(Q3, digits),
    Minimo = round(Minimo, digits),
    Maximo = round(Maximo, digits),
    "CV (%)" = round(CV),
    Asimetria = round(Asimetria, digits),
    Curtosis = round(Curtosis, digits),
    row.names = NULL
  )

  if (imprimir) {
    knitr::kable(tabla, caption = caption)
  } else {
    return(tabla)
  }
}

nombre_cuantitativas <- c(
  "estrato", "preciom", "areaconst", "parqueaderos", "banios", "habitaciones",
  "longitud", "latitud"
)

descriptiva_cuantitativas(data1, nombre_cuantitativas)
3.1. Indicadores estadisticos descriptivos de cada variable cuantitativa
Variables.cuantitativas N Promedio Desv..Estandar IQR Q1 Q3 Minimo Maximo CV…. Asimetria Curtosis
estrato 8309 4.634 1.029 1.000 4.000 5.000 3.000 6.000 22 -0.184 -1.107
preciom 8309 433.840 328.386 320.000 220.000 540.000 58.000 1999.000 76 1.846 3.653
areaconst 8309 174.950 142.989 149.000 80.000 229.000 30.000 1745.000 82 2.695 12.931
parqueaderos 6716 1.835 1.125 1.000 1.000 2.000 1.000 10.000 61 2.329 8.333
banios 8309 3.112 1.428 2.000 2.000 4.000 0.000 10.000 46 0.926 1.131
habitaciones 8309 3.607 1.460 1.000 3.000 4.000 0.000 10.000 40 1.637 3.986
longitud 8309 -76.529 0.017 0.023 -76.542 -76.519 -76.589 -76.463 0 0.648 0.586
latitud 8309 3.418 0.043 0.071 3.381 3.452 3.333 3.498 1 0.032 -1.148

3.3.4 Datos faltantes

Se mira con la libreria mice que datos faltantes tiene la base de datos.

invisible(capture.output({
  mice::md.pattern(data1)
  title(main = "Figura 3.1. Patron de datos faltantes")
}, file = NULL))

En la Fig 3.1., se encontro que hay 1593 datos faltantes para la variable parqueadero y 2626 para piso por lo que se procede a calcular el porcentaje de datos faltantes que hay respecto al total.

# Conteo y % de faltantes por variable
tabla_faltantes <- data.frame(
  Variable = names(data1),
  Faltantes = colSums(is.na(data1)),
  Porcentaje = round(sapply(data1, function(x) mean(is.na(x)) * 100), 2),
  row.names = NULL
)

knitr::kable(tabla_faltantes, caption = "Tabla 3.2. Datos faltantes por variable")
Tabla 3.2. Datos faltantes por variable
Variable Faltantes Porcentaje
id 0 0.00
zona 0 0.00
piso 2626 31.60
estrato 0 0.00
preciom 0 0.00
areaconst 0 0.00
parqueaderos 1593 19.17
banios 0 0.00
habitaciones 0 0.00
tipo 0 0.00
barrio 0 0.00
longitud 0 0.00
latitud 0 0.00

A partir de la Tabla 3.2., se halló que parqueaderos tiene aprox. 19% de datos faltantes mientras que a piso le corresponde un aprox. 32%. Por lo cual se procede a hacer el test de Little y decidir que tipo de imputación utilizar.

3.3.5 Imputacion de datos faltantes

data1_num <- data1[, sapply(data1, is.numeric), drop = FALSE]

tab_mcar <- mcar_test(data1_num)

knitr::kable(tab_mcar, caption = "Tabla 3.3. Prueba MCAR (Little) para variables numéricas")
Tabla 3.3. Prueba MCAR (Little) para variables numéricas
statistic df p.value missing.patterns
1379.886 8 0 2

Como en la Tabla 3.3., el \(p-value\) no corresponde a MCAR (\(p-value < 0.05\)), se procede a mirar la relacion de piso y parqueadero con el resto de las variables.

# Variables numéricas
num_vars <- names(data1)[sapply(data1, is.numeric)]

# --- Tabla 1: medias según falta de piso ---
medias_por_falta_piso <- sapply(
  data1[, num_vars, drop = FALSE],
  function(x) tapply(x, is.na(data1$piso), mean, na.rm = TRUE)
)

tabla_piso <- as.data.frame(t(medias_por_falta_piso))
colnames(tabla_piso) <- c("No faltante", "Faltante")
tabla_piso <- cbind(Variable = rownames(tabla_piso), tabla_piso)
rownames(tabla_piso) <- NULL

knitr::kable(
  tabla_piso,
  digits = 3,
  caption = "Tabla 3.4. Media de variables numéricas según si falta el dato en 'piso'"
)
Tabla 3.4. Media de variables numéricas según si falta el dato en ‘piso’
Variable No faltante Faltante
id 4209.098 4058.001
estrato 4.659 4.580
preciom 423.650 455.893
areaconst 167.870 190.271
parqueaderos 1.815 1.885
banios 3.087 3.166
habitaciones 3.555 3.719
longitud -76.529 -76.528
latitud 3.416 3.420

La Tabla 3.4. compara, para cada variable numérica, el promedio entre dos grupos: propiedades donde sí se conoce piso (FALSE) y propiedades donde piso está faltante (TRUE). Lo importante es que los promedios no son iguales entre ambos grupos: cuando falta piso, en promedio el precio (preciom) y el área construida (areaconst) son mayores, y también suben ligeramente otras características (como habitaciones, baños y parqueaderos). Esto sugiere que la ausencia de piso no ocurre al azar, sino que está relacionada con información observada (precio/área), lo cual es justamente la idea detrás de MAR (Missing At Random). Por lo que para imputar piso, tiene sentido usar predictores como precio y área, porque los faltantes siguen un patrón observable.

# --- Tabla 2: medias según falta de parqueaderos ---
medias_por_falta_parq <- sapply(
  data1[, num_vars, drop = FALSE],
  function(x) tapply(x, is.na(data1$parqueaderos), mean, na.rm = TRUE)
)

tabla_parq <- as.data.frame(t(medias_por_falta_parq))
colnames(tabla_parq) <- c("No faltante", "Faltante")
tabla_parq <- cbind(Variable = rownames(tabla_parq), tabla_parq)
rownames(tabla_parq) <- NULL

knitr::kable(
  tabla_parq,
  digits = 3,
  caption = "Tabla 3.5. Media de variables numéricas según si falta el dato en 'parqueaderos'"
)
Tabla 3.5. Media de variables numéricas según si falta el dato en ‘parqueaderos’
Variable No faltante Faltante
id 4413.042 3100.205
estrato 4.830 3.805
preciom 468.660 287.040
areaconst 181.096 149.036
parqueaderos 1.835 NaN
banios 3.255 2.507
habitaciones 3.611 3.589
longitud -76.531 -76.521
latitud 3.415 3.428

Por otro lado, la Tabla 3.5. compara el promedio de cada variable numérica entre dos grupos: registros donde parqueaderos está observado (FALSE) y registros donde parqueaderos está faltante (TRUE). Las diferencias son marcadas: cuando falta parqueaderos, en promedio las viviendas tienen estrato más bajo (aprox. 3.80 vs 4.83), precio mucho menor (aprox. 287 vs 469) y menor área construida (aprox. 149 vs 181), además de menos baños (aprox. 2.51 vs 3.26). Esto indica que los faltantes en parqueaderos siguen un patrón asociado a características observadas (nivel socioeconómico y tamaño/valor del inmueble), por lo que no parecen aleatorios; esa evidencia es útil para justificar imputación usando estas variables como predictores.

Teniendo en cuenta lo anterior, se procede a hacer imputacion multiple para piso y parqueaderos:

A partir de la imputacion se obtiene la Figura 3.2 la cual compara la distribución de parqueaderos antes (azul) y después (rojo) de la imputación. Como las dos curvas casi se superponen en todo el rango, significa que la imputación no cambió de forma importante la forma general de la distribución en lugar de distorsionarlo.

ggplot() +
  geom_density(data = data1, aes(x = parqueaderos, color = "Antes"), na.rm = TRUE) +
  geom_density(data = data2, aes(x = parqueaderos, color = "Después"), na.rm = TRUE) +
  labs(
    title = "Figura 3.2. Densidad: antes vs después",
    x = "parqueaderos", y = "densidad",
    color = "Base"
  ) +
  scale_color_manual(values = c("Antes" = "blue", "Después" = "red"))

3.3.6 Estadistica descriptiva despues de imputación

A partir de la grafica 3.6. y comparandola con la Tabla 3.1. se observa que casi todos los estadísticos se mantienen exactamente iguales para estrato, preciom, areaconst, banios, habitaciones, longitud y latitud, lo cual indica que la imputación no alteró la distribución de esas variables (o no tenían faltantes relevantes). El cambio está concentrado en parqueaderos: antes tenía N = 6716 (había faltantes), y después pasa a N = 8309 (se completaron los registros). Además, sus medidas cambian ligeramente: el promedio baja (de 1.835 a 1.755) y la desviación estándar baja (de 1.125 a 1.093), mientras que el IQR, Q1, Q3, mínimo y máximo se mantienen (IQR=1; Q1=1; Q3=2; min=1; max=10), lo que sugiere que los valores imputados se asignaron principalmente dentro del rango típico (1–2) sin introducir extremos nuevos. En forma práctica: la imputación recuperó información (más filas completas) y ajustó suavemente parqueaderos hacia valores más comunes, sin distorsionar el resto de variables.

descriptiva_cuantitativas(data2, nombre_cuantitativas, caption = "Tabla 3.6. Estadísticos descriptivos (despues de imputación)")
Tabla 3.6. Estadísticos descriptivos (despues de imputación)
Variables.cuantitativas N Promedio Desv..Estandar IQR Q1 Q3 Minimo Maximo CV…. Asimetria Curtosis
estrato 8309 4.634 1.029 1.000 4.000 5.000 3.000 6.000 22 -0.184 -1.107
preciom 8309 433.840 328.386 320.000 220.000 540.000 58.000 1999.000 76 1.846 3.653
areaconst 8309 174.950 142.989 149.000 80.000 229.000 30.000 1745.000 82 2.695 12.931
parqueaderos 8309 1.755 1.093 1.000 1.000 2.000 1.000 10.000 62 2.499 9.652
banios 8309 3.112 1.428 2.000 2.000 4.000 0.000 10.000 46 0.926 1.131
habitaciones 8309 3.607 1.460 1.000 3.000 4.000 0.000 10.000 40 1.637 3.986
longitud 8309 -76.529 0.017 0.023 -76.542 -76.519 -76.589 -76.463 0 0.648 0.586
latitud 8309 3.418 0.043 0.071 3.381 3.452 3.333 3.498 1 0.032 -1.148

3.4 Analisis de componentes principales

Se procede a hacer analisis de componentes principales (PCA: Principal Component Analysis)

Lo que se obtuvo fue la Figura 4.1. que muestra cuánta variabilidad explica cada componente principal del PCA. Aquí, el CP1 explica 45.8% de la variación total, lo que indica que una sola combinación lineal de las variables ya resume gran parte de la información. El CP2 aporta 18.6% adicional, y juntos CP1 + CP2 explican aproximadamente 64.4%, una proporción alta para representar los datos en 2 dimensiones

fviz_eig(pca, addlabels = TRUE) +
  ggtitle("Figura 4.1 Varianza explicada por componente")

La Figura 4.2 (círculo de correlaciones) muestra cómo se relacionan las variables originales con los dos primeros componentes del PCA: Dim1 (45.8%) y Dim2 (18.6%). En Dim1, las flechas de preciom, areaconst, banios y parqueaderos apuntan hacia la derecha y son relativamente largas, lo que indica que este componente resume principalmente un eje de “tamaño/valor del inmueble” (propiedades más grandes y caras, con más baños y parqueaderos, tienden a tener puntuaciones altas en Dim1). En contraste, latitud y longitud apuntan hacia la izquierda, sugiriendo que la ubicación geográfica se asocia en sentido opuesto a ese eje. En Dim2, la variable que más marca la dirección es habitaciones (hacia arriba), mientras que estrato se ubica hacia abajo, mostrando que este segundo componente captura una dimensión distinta relacionada con la composición del inmueble y diferencias socioeconómicas, separando propiedades con más habitaciones de aquellas asociadas a mayor estrato (según la dirección observada).

fviz_pca_var(
  pca,
  col.var = "contrib",
  gradient.cols = c("#FF7F00", "#034D94"),
  repel = TRUE
) + 
  ggtitle("Figura 4.2. Variables en el PCA") +
  theme(plot.title = element_text(hjust = 0.5))

Adicionalmente, se hizo la Figura 4.3, qué muestra cuanto aporta cada variable a la construcción del Componente 1 (Dim-1) del PCA (en porcentaje). Las barras más altas indican variables que “pesan” más en ese componente: aquí destacan preciom, banios, areaconst y parqueaderos, todas por encima (o cerca) de la línea roja punteada, que representa la contribución promedio esperada si todas las variables aportaran igual. Por eso, Dim-1 puede interpretarse como un eje de “valor/tamaño del inmueble”: propiedades más caras, con más área, más baños y más parqueaderos tienden a ubicarse con puntuaciones altas en este componente. En cambio, variables como latitud (y en menor medida longitud y habitaciones) aportan poco a Dim-1, lo que sugiere que la ubicación y algunas características secundarias no son las que más definen esta primera dimensión principal.

fviz_contrib(pca, choice = "var", axes = 1) +
  ggtitle("Figura 4.3. Contribución de variables al Componente 1 (Dim-1)") +
  theme(plot.title = element_text(hjust = 0.5))

Para la Figura 4.4. se muestra qué variables más aportan a construir el Componente 2 (Dim-2) del PCA. Las barras representan el porcentaje de contribución y la línea roja punteada es la contribución promedio: las variables por encima de esa línea son las que realmente “definen” esta dimensión. Aquí, la mayor contribución viene de habitaciones (la más alta), seguida por longitud, estrato y latitud, lo que indica que Dim-2 está capturando principalmente una combinación entre características de distribución interna del inmueble (número de habitaciones) y un componente fuerte de ubicación/geografía (latitud y longitud), además de un componente socioeconómico (estrato). En cambio, variables como preciom, parqueaderos y banios aportan muy poco a Dim-2, por lo que esta segunda dimensión no se interpreta como “precio/tamaño”, sino más bien como un eje complementario que separa propiedades según habitaciones–ubicación–estrato.

fviz_contrib(pca, choice = "var", axes = 2) +
  ggtitle("Figura 4.4. Contribución de variables al Componente 2 (Dim-2)") +
  theme(plot.title = element_text(hjust = 0.5))

Guardamos los \(scores\) para utilizarlos en el siguiente analisis

3.5 Analisis de conglomerados

En este paso para mayor facilidad para el informe se utilizo el metodo no jerarquico, k-means, debido a que es mas eficiente computacionalmente por medio de los \(scores\) del procedimiento anterior y definimos 3 clusters, como se puede ver en la Figura 5.1.

set.seed(123)

X <- as.matrix(scale(scores_2))  # CP1, CP2 estandarizados

k <- 3
km <- kmeans(X, centers = k, nstart = 25)

data2_cluster_km <- data_pca2 %>%
  mutate(cluster = as.factor(km$cluster))

ggplot(data2_cluster_km, aes(CP1, CP2, color = cluster)) +
  geom_point(alpha = 0.7) +
  theme_classic() +
  labs(title = paste("Figura 5.1. k-means sobre CP1–CP2, k =", k))

Se utilizo el coeficiente de Silhouette que nos da la Tabla 5.1 y el valor mas alto es k = 3.

ks <- 2:8
sil <- sapply(ks, function(k){
  km <- kmeans(X, centers = k, nstart = 25)
  mean(silhouette(km$cluster, dist(X))[, 3])
})

tabla_sil <- data.frame(k = ks, silhouette = sil)

tabla_sil %>%
  gt() %>%
  tab_header(
    title = "Tabla 5.1. Silhouette promedio para distintos k (k-means)"
  )
Tabla 5.1. Silhouette promedio para distintos k (k-means)
k silhouette
2 0.3853002
3 0.4084263
4 0.3840304
5 0.3601695
6 0.3900782
7 0.3801797
8 0.3584682

Se utiliza el siguiente codigo para una mejor caracterizacion de los tres clusters y se obtiene la Tabla 5.2. en la que el clúster 1 (n=4522) representa el mercado “estándar”, con viviendas de tamaño medio (mediana 93 m²), estrato medio-alto (mediana 5) y características típicas (3 habitaciones, 2 baños y 1 parqueadero). El clúster 2 (n=1981) agrupa propiedades familiares más amplias (mediana 150 m²) con mayor número de habitaciones y baños (4 y 3 respectivamente), ubicadas en estratos más bajos (mediana 3) y con menor precio por m² (mediana 270). Finalmente, el clúster 3 (n=1806) corresponde a un segmento premium, con estrato alto (mediana 6), propiedades muy grandes (mediana 300 m²), mayor dotación (3 parqueaderos, 5 baños) y un precio por m² marcadamente superior (mediana 850), evidenciando una diferenciación clara frente a los otros segmentos.

resumen <- data2_cluster_km %>% 
  group_by(cluster) %>%
  summarise(
    n = n(),
    across(all_of(nombre_cuantitativas),
           list(media = ~mean(.x, na.rm = TRUE),
                mediana = ~median(.x, na.rm = TRUE)),
           .names = "{col}_{fn}"),
    .groups = "drop"
  )

# Pasar a formato vertical
resumen_vertical <- resumen %>%
  pivot_longer(
    cols = -c(cluster, n),
    names_to = c("Variable", "Estadistico"),
    names_sep = "_",
    values_to = "Valor"
  ) %>%
  arrange(cluster, Variable, Estadistico)

# Tabla vertical en gt
resumen_vertical %>%
  gt(groupname_col = "cluster") %>%   # agrupa visualmente por clúster
  tab_header(
    title = "Tabla 5.2. Resumen estadístico por clúster (k-means)"
  ) %>%
  fmt_number(columns = "Valor", decimals = 3)
Tabla 5.2. Resumen estadístico por clúster (k-means)
n Variable Estadistico Valor
1
4522 areaconst media 107.754
4522 areaconst mediana 93.000
4522 banios media 2.481
4522 banios mediana 2.000
4522 estrato media 4.690
4522 estrato mediana 5.000
4522 habitaciones media 2.913
4522 habitaciones mediana 3.000
4522 latitud media 3.407
4522 latitud mediana 3.398
4522 longitud media −76.532
4522 longitud mediana −76.531
4522 parqueaderos media 1.385
4522 parqueaderos mediana 1.000
4522 preciom media 308.524
4522 preciom mediana 285.000
2
1981 areaconst media 178.928
1981 areaconst mediana 150.000
1981 banios media 2.975
1981 banios mediana 3.000
1981 estrato media 3.638
1981 estrato mediana 3.000
1981 habitaciones media 4.479
1981 habitaciones mediana 4.000
1981 latitud media 3.452
1981 latitud mediana 3.461
1981 longitud media −76.511
1981 longitud mediana −76.510
1981 parqueaderos media 1.413
1981 parqueaderos mediana 1.000
1981 preciom media 289.458
1981 preciom mediana 270.000
3
1806 areaconst media 338.836
1806 areaconst mediana 300.000
1806 banios media 4.841
1806 banios mediana 5.000
1806 estrato media 5.586
1806 estrato mediana 6.000
1806 habitaciones media 4.387
1806 habitaciones mediana 4.000
1806 latitud media 3.406
1806 latitud mediana 3.405
1806 longitud media −76.539
1806 longitud mediana −76.540
1806 parqueaderos media 3.058
1806 parqueaderos mediana 3.000
1806 preciom media 905.989
1806 preciom mediana 850.000

3.6 Analisis de correspondencia

Este analisis se hace entre variables categóricas, es decir la asociación entre sus categorías, con el fin establecer si existe, patrones o estructuras en los datos.

Para ello se hace el siguiente codigo

3.6.1 Zona-piso

3.6.1.1 Scree plot

Primero se hace la tabla de contingencia, luego se evalua con la prueba chi-cuadrado:

# Tabla de contingencia zona x piso
tabla1 <- table(data2$zona, data2$piso)

# Prueba chi-cuadrado
chisq.test(tabla1)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla1
## X-squared = 476.26, df = 44, p-value < 2.2e-16

El \(p-value\) dio cercano a cero por lo que si es valido hacer analisis de correspondencia

Elaboramos la Figura 6.1., muestra cuánta “inercia” (variabilidad/asociación) explica cada eje del análisis. El Eje 1 concentra la mayor parte de la información con 73.6%, lo que indica que la estructura principal de relación entre categorías está dominada por una sola dimensión. El Eje 2 aporta 16% adicional y, juntos, Ejes 1 y 2 explican 89.6%, por lo que un mapa factorial en dos dimensiones representa muy bien el patrón global. A partir del Eje 3 (9.8%) la ganancia ya es menor, y el Eje 4 (0.7%) es prácticamente despreciable, así que lo más razonable es interpretar principalmente el plano (Eje 1–Eje 2) y usar ejes posteriores solo si se necesita afinar detalles muy específicos.

# Screeplot
fviz_screeplot(resultados_ac1, addlabels = TRUE, ylim = c(0, 80)) +
  ggtitle("Figura 6.1. varianza explicada por eje (Análisis de Correspondencia)") +
  ylab("Porcentaje de varianza explicado") +
  xlab("Ejes") +
  theme(plot.title = element_text(hjust = 0.5))

##### Gráficos de Contribuciones

La Figura 6.2. muestra qué tanto contribuye cada zona (filas) a construir la Dimensión 1 del Análisis de Correspondencia. La línea roja punteada marca la contribución promedio esperada; por encima de esa línea están las categorías que realmente “definen” el eje. Aquí, Zona Oeste es la que más aporta (muy por encima del promedio), seguida por Zona Oriente, lo que indica que la oposición principal capturada por Dim-1 está dominada por el contraste asociado a estas dos zonas. Zona Centro contribuye de forma moderada y Zona Sur aporta poco, mientras que Zona Norte es prácticamente nula, lo que sugiere que su perfil es más cercano al promedio o no es clave para diferenciarse en este eje.

# Contribuciones (zonas y pisos) a Dim 1 y Dim 2
fviz_contrib(resultados_ac1, choice = "row", axes = 1, top = 10) +
  ggtitle("Figura 6.2. Contribución de zonas a la Dimensión 1") +
  theme(plot.title = element_text(hjust = 0.5))

En la Figura 6.3 se presentan las categorías 06, 01 y 07 que muestran las contribuciones más altas, lo que indica que son las que más definen la Dimensión 1; por tanto, la interpretación de este eje debe enfocarse en cómo estos pisos se diferencian y se asocian con las categorías de la variable cruzada (por ejemplo, tipo de inmueble, zona o estrato).

fviz_contrib(resultados_ac1, choice = "col", axes = 1, top = 10)  +
  ggtitle("Figura 6.3. Contribución de piso a la Dimensión 1") +
  theme(plot.title = element_text(hjust = 0.5))

La Figura 6.2. muestra qué tanto contribuye cada zona (filas) a construir la Dimensión 2 del Análisis de Correspondencia. Aquí, Zona Centro es la que más aporta (muy por encima del promedio), seguida por Zona Sur, lo que indica que la oposición principal capturada por Dim-2 está dominada por el contraste asociado a estas dos zonas.

fviz_contrib(resultados_ac1, choice = "row", axes = 2, top = 10)  +
  ggtitle("Figura 6.4. Contribución de zonas a la Dimensión 2") +
  theme(plot.title = element_text(hjust = 0.5))

La Figura 6.5. muestra qué piso 01, 11, 02 son las variables que mejor explican la mayor parte de la estructura del segundo componente.

fviz_contrib(resultados_ac1, choice = "col", axes = 2, top = 10)  +
  ggtitle("Figura 6.5. Contribución de piso a la Dimensión 2") +
  theme(plot.title = element_text(hjust = 0.5))

##### Mapa factorial

La Figura 6.6. muestra la relación entre Zona (azul) y Piso (rojo) en el plano formado por Dim1 (73.6%) y Dim2 (16%), por lo que el mapa resume muy bien la estructura de asociación. En el eje horizontal (Dim1) se observa el contraste principal: Zona Oeste se ubica claramente a la derecha y aparece próxima a pisos como 06, 07, 09 y 12, lo que sugiere una mayor asociación relativa de esta zona con esas categorías de piso; en cambio, Zona Oriente y Zona Centro quedan a la izquierda y se aproximan al piso 01, indicando un perfil distinto y más relacionado con esa categoría. Zona Norte se mantiene cerca del origen, lo que refleja un comportamiento más promedio y sin asociación fuerte con un piso específico en estas dos dimensiones, mientras que Zona Sur se sitúa levemente hacia la parte inferior y cercana a pisos como 02, 03 y 05, sugiriendo una relación más moderada con estas categorías. En el eje vertical (Dim2) destacan pisos como 11 (más arriba) y 08 (más abajo), que aportan diferenciación adicional; en conjunto, el resultado evidencia que las asociaciones más relevantes se explican principalmente por el contraste Oeste vs Oriente/Centro y por los pisos que caracterizan cada lado del mapa.

#Mapa
fviz_ca_biplot(resultados_ac1, repel = TRUE)+
  ggtitle("Figura 6.6. Mapa factorial zona-piso") +
  theme(plot.title = element_text(hjust = 0.5))

3.6.2 Zona-barrio

3.6.2.1 Scree plot

Se crea una columna que tome los 10 barrios mas frecuentes, se hace tabla de contingencia y chi-cuadrado

# 3) Chi-cuadrado
chisq.test(tabla_2)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla_2
## X-squared = 6373, df = 40, p-value < 2.2e-16

Rechazamos hipotesis nula asi que procedemos a hacer el analisis. Para la Figura 6.7, el Eje 1 explica 54.7% y el Eje 2 explica 40.4%; en conjunto, los dos primeros ejes concentran aprox. 95.1%** de la información, lo que indica que el patrón de asociación entre las categorías se puede representar de forma muy fiel en un plano bidimensional. Por lo que la interpretación debe centrarse en el plano Eje 1–Eje 2, ya que captura casi toda la estructura relevante de la relación analizada.

# 4) CA
resultados_ac_barrio <- CA(tabla_2, graph = FALSE)
# 5) Autovalores
valores_prop_barrio <- resultados_ac_barrio$eig

# 7) Screeplot
fviz_screeplot(resultados_ac_barrio, addlabels = TRUE, ylim = c(0, 80)) +
  ggtitle("Figura 6.7. varianza explicada por eje (Análisis de Correspondencia") +
  ylab("Porcentaje de varianza explicado") +
  xlab("Ejes")

3.6.2.2 Graficos de contribuciones

La Figura 6.8. muestra que las variables zona Sur, oeste y norte, son las que mejor explican la mayor parte de la estructura del primer componente.

# 6) Contribuciones (si existe Dim 2)
fviz_contrib(resultados_ac_barrio, choice = "row", axes = 1, top = 10) +
  ggtitle("Figura 6.8. Contribución de zona a la Dimensión 1") +
  theme(plot.title = element_text(hjust = 0.5))

La Figura 6.9. muestra que las variables valle de lili, santa teresita, normandia, ciudad jardin, la flora y pance son las que mejor explican la mayor parte de la estructura del primer componente.

fviz_contrib(resultados_ac_barrio, choice = "col", axes = 1, top = 10)+
  ggtitle("Figura 6.9. Contribución de 10 barrios a la Dimensión 1") +
  theme(plot.title = element_text(hjust = 0.5))

La Figura 6.10. muestra que las variables zona norte y zona oeste son las que mejor explican la mayor parte de la estructura del segundo componente.

fviz_contrib(resultados_ac_barrio, choice = "row", axes = 2, top = 10)+
  ggtitle("Figura 6.10. Contribución de zonas a la Dimensión 2") +
  theme(plot.title = element_text(hjust = 0.5))

La Figura 6.11. muestra que las variables santa teresita, la flora, normandia, acopi son las que mejor explican la mayor parte de la estructura del segundo componente.

fviz_contrib(resultados_ac_barrio, choice = "col", axes = 2, top = 10)+
  ggtitle("Figura 6.11. Contribución de 10 barrios a la Dimensión 2") +
  theme(plot.title = element_text(hjust = 0.5))

3.6.2.3 Mapa factorial

La Figura 6.12 muestra que en la Dim1 se observa un contraste claro: hacia la derecha se ubica Zona Sur, cercana a barrios como Valle del Lili, Ciudad Jardín y Pance, lo que sugiere que estos barrios caracterizan de forma más marcada la oferta asociada a esa zona; además, barrios como La Hacienda, El Caney y El Ingenio aparecen muy alejados, indicando perfiles particularmente diferenciados dentro del mapa (categorías con comportamiento menos “promedio”). Hacia la izquierda se sitúan Zona Oeste y Zona Norte, alineadas con barrios como Normandía y Santa Teresita (más cercanos a Oeste) y con La Flora, Acopi y El Ingenio (más alineados con Norte, según su posición). En contraste, Zona Centro y Zona Oriente quedan cerca del origen, lo que sugiere un perfil más general o mixto, sin un barrio dominante que las defina con tanta fuerza como en el caso de Zona Sur.

# 8) Mapa
fviz_ca_biplot(resultados_ac_barrio, repel = TRUE)+
  ggtitle("Figura 6.12. Mapa factorial zona barrio") +
  theme(plot.title = element_text(hjust = 0.5))

3.6.3 piso-barrio

3.6.3.1 Scree plot

Se hace tabla de contingencia y chi-cuadrado

# Tabla de contingencia zona x piso
tabla3 <- table(data2$piso, data2$barrio10)
# Prueba chi-cuadata2# Prueba chi-cuadrado
chisq.test(tabla3)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla3
## X-squared = 892.52, df = 110, p-value < 2.2e-16

Se rechaza la hipotesis nula y se procede a hacer el screeplot. En la Figura 6.13 se muestra como el Eje 1 se concentra la mayor parte con 61.6%, lo que indica que el patrón principal de asociación entre categorías se organiza principalmente en una sola dimensión. El Eje 2 aporta 17.7% adicional y, juntos, los dos primeros ejes explican aproximadamente 79.3%, por lo que el plano bidimensional (Eje 1–Eje 2) ya permite una interpretación sólida del mapa factorial. A partir del Eje 3 (7.4%) la ganancia de información disminuye notablemente y los ejes siguientes aportan porcentajes pequeños (menores al 5% y luego cercanos a 1% o menos), lo que sugiere que su contribución es marginal.

# Análisis de Correspondencia
resultados_ac3 <- CA(tabla3, graph = FALSE)

# Screeplot
fviz_screeplot(resultados_ac3, addlabels = TRUE, ylim = c(0, 80)) +
  ggtitle("Figura 6.13. Varianza explicada por eje (Análisis de Correspondencia)") +
  ylab("Porcentaje de varianza explicado") +
  xlab("Ejes")

3.6.3.2 Gráficos de Contribuciones

La Figura 6.14. muestra que las variables 02, 06, 07, 08, 09 son las que mejor explican la mayor parte de la estructura el segundo primer componente.

# Contribuciones (zonas y pisos) a Dim 1 y Dim 2
fviz_contrib(resultados_ac3, choice = "row", axes = 1, top = 10)+
  ggtitle("Figura 6.14. Contribución de pisos a la Dimensión 1") +
  theme(plot.title = element_text(hjust = 0.5))

La Figura 6.15. muestra que las variables valle de lili, santa teresita, normandia y otros son las que mejor explican la mayor parte de la estructura del primer. componente.

fviz_contrib(resultados_ac3, choice = "col", axes = 1, top = 10)+
  ggtitle("Figura 6.15. Contribución de 10 barrios a la Dimensión 1") +
  theme(plot.title = element_text(hjust = 0.5))

La Figura 6.16. muestra que las variables 12, 11, 05, 01 son las que mejor explican la mayor parte de la estructura del segundo componente.

fviz_contrib(resultados_ac3, choice = "row", axes = 2, top = 10) +
  ggtitle("Figura 6.16. Contribución de pisos a la Dimensión 2") +
  theme(plot.title = element_text(hjust = 0.5))

La Figura 6.17. muestra que las variables la flora, valle de lili y ciudad jardin son las que mejor explican la mayor parte de la estructura del segundo componente.

fviz_contrib(resultados_ac3, choice = "col", axes = 2, top = 10)+
  ggtitle("Figura 6.17. Contribución de 10 barrios a la Dimensión 2") +
  theme(plot.title = element_text(hjust = 0.5))

##### Mapa factorial

La Figura 6.18 muestra que Dim1 explica 61.6% y Dim2 17.7%; por tanto, la estructura principal se lee sobre todo en el eje horizontal. En Dim1, se observa una separación clara: hacia la derecha quedan pisos como 06–10 (y especialmente 11–12, muy alejados), asociados a barrios ubicados también a la derecha como Santa Teresita y Normandía; esto sugiere que en esos barrios es relativamente más frecuente encontrar publicaciones en esos pisos, destacándose que Normandía se alinea con valores más extremos del lado derecho. En contraste, hacia la izquierda se agrupan pisos 01–04 cerca de barrios como Pance y Ciudad Jardín, lo que indica un perfil diferente donde estos pisos son más representativos. En Dim2, los pisos 11–12 aparecen en la parte superior (asociados con La Flora), mientras que en la parte inferior se ubican categorías cercanas a Valle del Lili y algunos pisos medios (por ejemplo 07–10), aportando un matiz adicional dentro del patrón general.

fviz_ca_biplot(resultados_ac3, repel = TRUE)+
  ggtitle("Figura 6.18. Mapa factorial piso-barrio") +
  theme(plot.title = element_text(hjust = 0.5))

4 Analisis de resultados y recomendaciones

4.1 Variables cuantitativas

4.1.1 Analisis de componentes principales + Analisis de conglomerados

Segmentos y decisiones recomendadas (k=3)

Clúster 1 (n aprox. 4522): “Entrada / estándar” Promedios: área aprox. 108 m2, baños aprox. 2.5, parqueaderos aprox. 1.4, precio aprox. 309, estrato medio-alto (aprox. 4.7). Recomendación: es tu segmento de volumen. Optimiza aquí la inversión en captación masiva, procesos rápidos (fotos/recorridos/agenda) y campañas de alto alcance. Para maximizar beneficios: trabaja rotación (más cierres), paquetes de servicios (promoción destacada, crédito/asesoría) y pricing competitivo por m2.

Clúster 2 (n aprox. 1981): “Familiar / más habitaciones, precio contenido” Promedios: área aprox. 179 m2, habitaciones aprox. 4.5 (alto), baños aprox. 3.0, precio similar o incluso menor (aprox. 289), estrato más bajo (aprox. 3.6) y latitud algo distinta (señal de zona). Recomendación: aquí hay una oportunidad clara de posicionamiento por necesidad (familias): campañas enfocadas en “más habitaciones por presupuesto”, alianzas con colegios/servicios del sector y mensajes de valor (espacio/funcionalidad). Para inversión: prioriza captar inventario con 4+ habitaciones y valida márgenes usando precio por m2 (puede ser atractivo si el precio total no crece tanto).

Clúster 3 (n aprox. 1806): “Premium / alto valor” Promedios: área aprox. 339 m2, baños aprox. 4.8, parqueaderos aprox. 3.1, precio aprox. 906, estrato alto (aprox. 5.6). Recomendación: es tu clúster de margen. Menos volumen, pero más rentabilidad por operación. Enfoca inversión en captación selectiva (propietarios premium), marketing de calidad (video, staging, pauta segmentada) y gestión comercial especializada. Aquí conviene una estrategia de precio ancla (comparables premium) y servicios diferenciales (home staging, tour 360, asesoría legal/tributaria).

4.2 Variables cualitativas

4.2.1 Analisis de correspondencia

4.2.1.1 Zona-piso

A partir del análisis Zona–Piso, se recomienda utilizar este patrón para ordenar los resultados y las recomendaciones comerciales sin excluir alternativas. En particular, la Figura 6.1 (Varianza explicada por eje) muestra que las dos primeras dimensiones resumen la mayor parte de la estructura Zona–Piso, mientras que las Figuras 6.2 y 6.3 (Contribución de zonas y de piso a la Dimensión 1) y las Figuras 6.4 y 6.5 (Contribución de zonas y de piso a la Dimensión 2) permiten identificar las categorías más influyentes que explican el patrón observado. Con base en el biplot Zona–Piso (Figura 6.6), cuando un cliente filtre por Zona Oeste conviene priorizar primero inmuebles ubicados en pisos típicamente asociados a esa zona (por ejemplo, 06, 07, 09 y 12); si el cliente filtra por Zona Centro o Zona Oriente, se recomienda mostrar primero opciones de piso 01; y si filtra por Zona Sur, priorizar pisos como 02, 03 y 05. Esta estrategia funciona porque esas combinaciones aparecen como las más representativas de cada zona en el mapa factorial (Figura 6.6) y, además, están respaldadas por las categorías que más “empujan” las dimensiones (Figuras 6.2–6.5), lo que aumenta la relevancia de los resultados, acelera la búsqueda del cliente y mejora la probabilidad de contacto y cierre, manteniendo disponibles alternativas menos comunes para necesidades específicas.

Con base en el biplot (Figura 6.6), se propone ajustar el discurso comercial, el filtrado y la recomendación de inmuebles según el patrón de asociación: para Zona Oeste, promover y priorizar pisos 06–07–09–12; para Zona Centro y Zona Oriente, priorizar piso 01; y para Zona Sur, reforzar la oferta asociada a 02–03–05. Además, dado que Zona Centro y Zona Sur son las que más contribuyen a Dimensión 2 (Figura 6.4), se recomienda usar esta segunda dimensión como criterio adicional de segmentación fina para campañas y recomendaciones (por ejemplo, diferenciar subperfiles dentro de zonas).

4.2.1.2 Zona-barrio

A partir del análisis Zona–Barrio, se recomienda utilizar este patrón para ordenar los resultados y las recomendaciones comerciales sin excluir alternativas. En particular, según el Mapa factorial Zona–Barrio (Figura 6.12) y las contribuciones por dimensión (Figura 6.8 para zonas y Figura 6.9 para barrios en Dimensión 1; Figura 6.10 para zonas y Figura 6.11 para barrios en Dimensión 2), cuando un cliente filtre por Zona Sur conviene mostrar primero inmuebles ubicados en Valle del Lili, Ciudad Jardín y Pance; si filtra por Zona Oeste, priorizar Santa Teresita y Normandía; y si filtra por Zona Norte, resaltar La Flora y Acopi. Esta estrategia es útil porque estos barrios aparecen como los más representativos y diferenciadores del perfil de cada zona en el mapa factorial, por lo que presentar primero esas combinaciones aumenta la relevancia de las opciones mostradas, acelera la búsqueda y mejora la probabilidad de contacto y cierre, manteniendo disponibles las opciones menos frecuentes para necesidades específicas.

4.2.1.3 Piso-barrio

En función del Análisis de Correspondencia piso–barrio (Figuras 6.13 a 6.18), se recomienda incorporar reglas de ordenamiento de resultados para mejorar la relevancia de las recomendaciones sin excluir alternativas. Si el cliente busca por barrio, el orden sugerido es: para Normandía, priorizar inmuebles en pisos 12 y 11, seguido de piso 06 y luego pisos 07–09–08–10 como alternativas; para Santa Teresita, priorizar piso 09, luego 08 y 07, seguido de 10 y 06; para Valle del Lili, priorizar piso 10, luego 07, 08 y 09, con 06 como alternativa; para La Flora, priorizar pisos 11 y 12, con 06 como alternativa; para Ciudad Jardín, priorizar pisos 01 y 02, y luego 03–04; para Pance, priorizar 01 y 02, seguido de 03–04; para El Caney, priorizar piso 05, seguido de 03–04 y luego 02; para El Ingenio y La Hacienda, priorizar piso 05, seguido de 01–02 y luego 03–04; y para Acopi, priorizar pisos 03–04, seguido de 05 y luego 02. Si el cliente busca por piso, el orden sugerido de barrios “más probables” es: para piso 12, priorizar Normandía y La Flora, con Santa Teresita como alternativa; para piso 11, priorizar La Flora y Normandía, con Santa Teresita como alternativa; para piso 09, priorizar Santa Teresita, luego Valle del Lili y después Normandía; para piso 08, priorizar Santa Teresita, luego Valle del Lili y después Normandía; para piso 07, priorizar Valle del Lili, luego Santa Teresita y después Normandía; para piso 10, priorizar Valle del Lili, luego Santa Teresita y después Normandía; para piso 06, priorizar Normandía, luego Santa Teresita y después Valle del Lili; para pisos 01–02, priorizar Ciudad Jardín y Pance; para piso 05, priorizar El Caney, luego La Hacienda y El Ingenio, con Acopi como alternativa; y para pisos 03–04, priorizar Acopi y la categoría Otros, dejando como alternativas cercanas barrios como Ciudad Jardín y Pance.

5 Conclusion

En conjunto, el Análisis de Componentes Principales (ACP), el Análisis de Conglomerados y el Análisis de Correspondencia ofrecen una lectura integral y accionable del mercado inmobiliario. El ACP permitió sintetizar las variables cuantitativas en pocos ejes interpretables (por ejemplo, un eje asociado al valor/tamaño del inmueble y otro relacionado con perfil/ubicación/entorno), reduciendo colinealidad y facilitando comparaciones más limpias entre propiedades. A partir de esa representación, el Análisis de Conglomerados segmentó el inventario en grupos homogéneos con perfiles diferenciados (por ejemplo, un segmento de volumen, uno familiar y uno premium), lo que habilita decisiones concretas de captación, precios, marketing y priorización comercial según el potencial de rotación o margen. Finalmente, el Análisis de Correspondencia confirmó que las variables categóricas no se distribuyen al azar y reveló patrones claros de asociación (por ejemplo, combinaciones Zona–Piso, Zona–Barrio y Piso–Barrio), útiles para segmentación operativa, ordenamiento de resultados y focalización geográfica de campañas. En síntesis, estos tres métodos se complementan: el ACP estructura y simplifica la información cuantitativa, los conglomerados convierten esa estructura en segmentos de negocio, y la correspondencia traduce la dinámica categórica del mercado en reglas prácticas de recomendación y posicionamiento, aportando ventajas competitivas para optimizar la inversión y maximizar beneficios en un entorno cambiante.