1 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 AnƔlisis exploratorio

2.1 Tipo de datos de las variables

data("vivienda")
df <- vivienda

#dplyr::glimpse(df)

tabla_glimpse <- data.frame(
  Variable = names(df),
  Tipo = sapply(df, function(x) class(x)[1]),
  Ejemplo = sapply(df, function(x) {
    paste(head(x, 3), collapse = ", ")
  }),
  row.names = NULL
)
tabla_glimpse %>%
  knitr::kable("html", booktabs = TRUE,
               caption = "<span style='font-size:13pt; font-weight:bold;'>Tabla 1. Resumen del tipo de dato</span>") %>%
  kable_styling(full_width = FALSE,
                position = "center",
                bootstrap_options = c("striped", "hover")) %>%
  column_spec(1, bold = TRUE, width = "8cm") %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2")
Tabla 1. Resumen del tipo de dato
Variable Tipo Ejemplo
id numeric 1147, 1169, 1350
zona character Zona Oriente, Zona Oriente, Zona Oriente
piso character NA, NA, NA
estrato numeric 3, 3, 3
preciom numeric 250, 320, 350
areaconst numeric 70, 120, 220
parqueaderos numeric 1, 1, 2
banios numeric 3, 2, 2
habitaciones numeric 6, 3, 4
tipo character Casa, Casa, Casa
barrio character 20 de julio, 20 de julio, 20 de julio
longitud numeric -76.51168, -76.51237, -76.51537
latitud numeric 3.43382, 3.43369, 3.43566

2.2 Resumen del set de datos

tabla_summary <- df %>%
  select(-id, -longitud, -latitud) %>%        # eliminar id si existe
  select(where(is.numeric)) %>%    # SOLO numƩricas
  summarise(
    across(
      everything(),
      list(
        N = ~sum(!is.na(.x)),
        Min = ~min(.x, na.rm = TRUE),
        `1st Qu.` = ~quantile(.x, 0.25, na.rm = TRUE),
        Median = ~median(.x, na.rm = TRUE),
        Mean = ~mean(.x, na.rm = TRUE),
        `3rd Qu.` = ~quantile(.x, 0.75, na.rm = TRUE),
        Max = ~max(.x, na.rm = TRUE)
      ),
      .names = "{.col}__{.fn}"     # separador seguro
    )
  ) %>%
  pivot_longer(
    cols = everything(),
    names_to = c("Variable", ".value"),
    names_pattern = "(.*)__(.*)"
  ) %>%
  select(Variable, N, Min, `1st Qu.`, Median, Mean, `3rd Qu.`, Max)
# Ordenar columnas (Variable, N, resto)
tabla_summary <- tabla_summary %>%
  select(Variable, N, Min, `1st Qu.`, Median, Mean, `3rd Qu.`, Max)

tabla_summary %>%
  knitr::kable("html", booktabs = TRUE,
               caption = "<span style='font-size:13pt; font-weight:bold;'>Tabla 2. Resumen de estadƭsticas descriptivas de variables numƩricas</span>") %>%
  kable_styling(full_width = FALSE,
                position = "center",
                bootstrap_options = c("striped", "hover")) %>%
  column_spec(1, bold = TRUE, width = "8cm") %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2")
Tabla 2. Resumen de estadƭsticas descriptivas de variables numƩricas
Variable N Min 1st Qu. Median Mean 3rd Qu. Max
estrato 8319 3 4 5 4.633610 5 6
preciom 8320 58 220 330 433.891947 540 1999
areaconst 8319 30 80 123 174.934938 229 1745
parqueaderos 6717 1 1 2 1.835194 2 10
banios 8319 0 2 3 3.111311 4 10
habitaciones 8319 0 3 3 3.605361 4 10

2.3 Valores faltantes

tabla_na <- df %>%
  select(-any_of("id")) %>%
  summarise(
    across(
      everything(),
      ~sum(is.na(.x))
    )
  ) %>%
  t() %>%
  as.data.frame()

tabla_na <- tabla_na %>%
  tibble::rownames_to_column("Variable") %>%
  rename(N_Faltantes = V1) %>%   # <- aquĆ­ el cambio
  mutate(
    Total = nrow(df),
    Porcentaje_NA = round((N_Faltantes / Total) * 100, 2)
  )


tabla_na %>%
  kable("html", booktabs = TRUE,
        caption = "<span style='font-size:13pt; font-weight:bold;'>Tabla 3. Valores faltantes por variable</span>",
        digits = 2) %>%
  kable_styling(full_width = FALSE,
                position = "center",
                bootstrap_options = c("striped", "hover")) %>%
  column_spec(1, bold = TRUE, width = "5cm") %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2")
Tabla 3. Valores faltantes por variable
Variable N_Faltantes Total Porcentaje_NA
zona 3 8322 0.04
piso 2638 8322 31.70
estrato 3 8322 0.04
preciom 2 8322 0.02
areaconst 3 8322 0.04
parqueaderos 1605 8322 19.29
banios 3 8322 0.04
habitaciones 3 8322 0.04
tipo 3 8322 0.04
barrio 3 8322 0.04
longitud 3 8322 0.04
latitud 3 8322 0.04

De acuerdo con la tabla 3, las variables con mÔs valores faltantes son: piso y parqueaderos. La variable piso no se considerarÔ para el presente estudio ya que presenta 31.70 % de valores faltantes frente al total de registros, y no se tiene una idea clara de qué tipo de técnica de imputación se podría utilizar.

2.4 Matriz de Correlaciones

#Elimino valores faltantes en la columna zona (3)
df_sin_zona <- df %>%
  filter(!is.na(zona))

df_num <- df_sin_zona %>%
  select(where(is.numeric), -latitud, -longitud,-id, -estrato)

matriz_cor <- cor(df_num, use = "complete.obs", method = "pearson")

# Ajustar mƔrgenes (mƔs espacio abajo)
par(mar = c(3, 1, 2, 1))

corrplot(
  matriz_cor,
  method = "color",        # colores
  type = "upper",          # solo triƔngulo superior (mƔs limpio)
  addCoef.col = "black",   # nĆŗmeros dentro de las celdas
  tl.col = "black",        # color de etiquetas
  tl.srt = 45,             # rotar nombres de variables
  number.cex = 0.7,        # tamaño de los números
  col = colorRampPalette(c("blue", "white", "red"))(200), # paleta
  diag = FALSE
)

Figura 1.0 Correlaciones de Pearson. Azul = relación negativa, rojo = positiva. Solo variables numéricas

De acuerdo con la figura 1, la variable preciom presenta correlaciones cercanas al 70 % con las variables: Ɣrea construida, parqueaderos y baƱos, por lo que se vislumbran como variables influyentes en el precio de la vivienda, y por tanto deben tenerse en cuenta dentro del presente estudio.

2.5 Histograma de precios

ggplot(df, aes(x = preciom)) +
  geom_histogram(bins = 30, fill = "steelblue", color = "white") +
  labs(
    title = "Distribución del precio de las viviendas",
    x = "Precio",
    y = "Frecuencia",
    caption = "Figura 2.0 Distribución del precio de la oferta inmobiliaria."
  ) +
  theme_minimal() +
  theme(
    plot.caption = element_text(
      hjust = 0.5,
      face = "italic",
      size = 10
    )
  )

La figura 2 muestra la distribución de los precios de las viviendas. En esta se observa una distribución asimétrica con cola hacia la derecha, evidencia de precios muy altos que podrían considerarse como atípicos estadísticamente, pero plausibles en lo que respecta a este tipo de estudios inmobiliarios. La mayor concentración de observaciones se localiza en el rango de 100 a 400 unidades monetarias, con una frecuencia mÔxima superior a 1,200 viviendas.

2.6 Precio vs Zona

ggplot(df, aes(x = zona, y = preciom)) +
  geom_boxplot(fill = "skyblue") +
  labs(
    title = "Distribución del precio de las viviendas por zonas",
    x = "Zona",
    y = "Precio",
    caption = "Figura 3.0 Distribución del precio de acuerdo con la zona"
  ) +
  theme_minimal() +
  theme(
    plot.caption = element_text(
      hjust = 0.5,
      face = "italic",
      size = 10
    )
  )

De acuerdo con la figura 3, se observa lo siguiente:

  • la Zona Oeste exhibe la mediana mĆ”s alta (aproximadamente 600 unidades) y el rango intercuartĆ­lico (IQR) mĆ”s amplio, indicando mayor heterogeneidad en la oferta y precios generalmente superiores.

  • Zona Oriente presenta la mediana mĆ”s baja (alrededor de 200 unidades) y la menor dispersión, sugiriendo un mercado mĆ”s homogĆ©neo y accesible.

  • Zona Centro, Norte y Sur muestran medianas similares (200-300 unidades) con dispersiones comparables.

Lo anterior permite vislumbrar una fuerte influencia de la variable zona respecto del precio de las viviendas, por eso serĆ” incluida.

2.7 Precio vs Ɓrea Construida por tipo de viviendas

ggplot(df, aes(x = areaconst, y = preciom, color = tipo)) +
  geom_point(alpha = 0.5) +
   labs(
    title = "Precio vs Ɓrea Construida por tipo de vivienda",
    x = "Ɓrea (m2)",
    y = "Precio",
    caption = "Figura 4.0. Diagrama de dispersión: Precio vs Área construida por tipo de vivienda"
  ) +
  theme_minimal() +
  theme(
    plot.caption = element_text(
      hjust = 0.5,
      face = "italic",
      size = 10
    )
  )

La figura 4.0 evidencia una relación positiva entre el Ôrea construida y el precio, aunque con una dispersión creciente a medida que aumenta el tamaño del inmueble, lo que sugiere la influencia de factores adicionales como el estrato y la ubicación. Se observa una clara segmentación por tipo de vivienda: los apartamentos se concentran en Ôreas menores y precios medios, mientras que las casas dominan el segmento de mayor tamaño y presentan mayor heterogeneidad de precios. Asimismo, se identifican valores atípicos que podrían corresponder a propiedades de lujo (precios muy altos con Ôreas reducidas) o inconsistencias en los datos (precios bajos para viviendas con Ôreas muy grandes), lo que justifica la aplicación de técnicas de detección de outliers.

2.8 Precio vs NĆŗmero de habitaciones

ggplot(df, aes(x = factor(habitaciones), y = preciom)) +
  geom_boxplot(outlier.alpha = 0.3, fill = "skyblue") +
  labs(
    title = "Precio vs NĆŗmero de habitaciones",
    x = "habitaciones",
    y = "Precio",
    caption = "Figura 5.0. Boxplot: Precio vs NĆŗmero de habitaciones"
  ) +
  theme_minimal() +
  theme(
    plot.caption = element_text(
      hjust = 0.5,
      face = "italic",
      size = 10
    )
  )

Al revisar los precios de viviendas de acuerdo con el nĆŗmero de habitaciones (figura 5.0), es preciso afirmar que las viviendas con 1 y 2 habitaciones son las de menor valor de la precio (mediana), sin embargo, se observan muchos valores extremos entre 2 y 7 habitaciones. Esto se podrĆ­a explicar por:

  • Mayor variedad de calidad y ubicación.

  • Influencia de estrato y Ć”rea construida.

  • Segmento de lujo mĆ”s diverso.

2.9 Precio vs Estrato

ggplot(df, aes(x = factor(estrato), y = preciom)) +
  geom_boxplot(outlier.alpha = 0.3, fill = "skyblue") +
 labs(
    title = "Precio vs Estrato",
    x = "Estrato",
    y = "Precio",
    caption = "Figura 6.0. Boxplot: Precio vs Estrato"
  ) +
  theme_minimal() +
  theme(
    plot.caption = element_text(
      hjust = 0.5,
      face = "italic",
      size = 10
    )
  )

La figura 6.0 refleja la influencia importante del estrato en el precio de la vivienda. Los estratos 5 y 6 presentan los precios mƔs altos. Es preciso mencionar que en todos los estratos se evidencian valores atƭpicos que pueden ser plausibles por la heterogeneidad de viviendas.

2.10 Precio por ubicación geogrÔfica y estrato

ggplot(df, aes(x = longitud, y = latitud,
               color = estrato,
               size = preciom)) +
  geom_point(alpha = 0.6) +
  scale_size_continuous(
    range = c(1, 6),          # puntos pequeƱos → grandes bien diferenciados
    name = "Precio"
  ) +
  labs(
    title = "Precio por ubicación geogrÔfica",
    x = "Latitud",
    y = "Longitud",
    caption = "Figura 7.0. Precio por ubicación geogrÔfica y estrato"
  ) +
  theme_minimal() +
  theme(
    plot.caption = element_text(
      hjust = 0.5,
      face = "italic",
      size = 10
    )
  )

La figura 7.0 muestra que las viviendas de mayor precio (estratos: 5 y 6) se encuentran en el sur, oriente y occidente. En la zona centro se observa mayor heterogenidad de precios, esto se puede justificar por la variedad del tipo de vivienda: edificios, casas y apartamentos.

3 Transformación de datos

Se decide eliminar los registros 8320, 8321 y 8322, ya que no se tiene suficiente información.

Figura 8.0. Registros eliminados del dataset
Figura 8.0. Registros eliminados del dataset

Adicionalmente, se transforman a tipo factor las siguientes variables: parqueaderos, piso, zona, tipo y barrio. Finalmente, los valores faltantes de estas variables categóricas, se llenan como ā€œNo informadoā€.

#df_sin_zona

df_piso_parq <- df_sin_zona %>%
  mutate(
    piso = ifelse(is.na(piso), "No informado", piso),
    parqueaderos = ifelse(is.na(parqueaderos), "No informado", parqueaderos),
    piso = as.factor(piso),
    parqueaderos = as.factor(parqueaderos),
    zona   = as.factor(zona),
    tipo   = as.factor(tipo),
    barrio = as.factor(barrio)
    )

4 AnƔlisis de Componentes Principales (ACP)

4.1 Cƭrculo de correlaciones del AnƔlisis de Componentes Principales (PCA)

id_vector <- df_piso_parq$id

df_sin_coord <- df_piso_parq %>%
  select(-longitud, -latitud)

pca_model_FactorM <- PCA(
  df_sin_coord %>% select(-id), 
  ncp = 5,
  quali.sup = which(sapply(df_sin_coord %>% select(-id), is.factor)),
  scale.unit = TRUE,
  graph = FALSE
)

var <- get_pca_var(pca_model_FactorM)

corrplot::corrplot(var$cos2, is.corr=FALSE)

fviz_pca_var(pca_model_FactorM, col.var = "cos2",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), 
             repel = TRUE # Avoid text overlapping
)

Figura 8.0. Cƭrculo de correlaciones del AnƔlisis de Componentes Principales (PCA)

La figura 8 muestra que el primer componente principal estÔ asociado al nivel general del inmueble, integrando variables de tamaño (Ôrea construida, número de baños y habitaciones), precio y estrato socioeconómico. El segundo componente diferencia entre viviendas de mayor número de habitaciones y aquellas de mayor estrato, lo que sugiere la existencia de tipologías distintas dentro del mercado inmobiliario, como viviendas familiares amplias y propiedades de alto valor en estratos superiores con menor número de habitaciones. La proximidad entre las variables de Ôrea construida y número de baños evidencia una alta correlación positiva, indicando que los inmuebles de mayor tamaño tienden a contar con mÔs servicios.

4.2 Explícación de la varianza total

fviz_eig(pca_model_FactorM, addlabels = TRUE)

Figura 9.0. Explicación de la varianza

La figura 9 muestra que el 82.5 % de la varianza, se explica a travƩs de las dos primeras dimensiones, por lo que solo se tendrƔn en cuenta estas para el anƔlisis.

4.3 Contribuciones individuales de la dimensión 1

fviz_contrib(pca_model_FactorM,choice = "ind", axes=1, top = 10)

Figura 10. Contribuciones individuales de la dimensión 1

4.4 Contribuciones individuales de la dimensión 2

fviz_contrib(pca_model_FactorM,choice = "ind", axes=2, top = 10)

Figura 11. Contribuciones individuales de la dimensión 2

En las figuras 11 y 12 se observan las contribuciones individuales (10) para las dimensiones 1 y 2.

5 AnƔlisis de Conglomerados

5.1 ClĆŗster

Para este apartado se usa la función: HCPC (Hierarchical Clustering on Principal Components), de la librería FactoMineR, la cual combina reducción de dimensionalidad mediante PCA con clustering jerÔrquico y una optimización posterior por partición. El número de clusters se determinó automÔticamente (nb.clust = -1) con base en la ganancia de inercia, permitiendo identificar segmentos homogéneos del mercado inmobiliario sin imponer una estructura previa.

Cluster_viviendas <- HCPC(pca_model_FactorM,nb.clust=-1)

fviz_cluster(Cluster_viviendas,respel = T)#para generar grƔfico de cluster.

Figura 12. ClĆŗster generados por la librerĆ­a FactoMineR

5.2 ClĆŗster por variables cuantitativas

Tabla 4. Descripción de cada clúster por variables cuantitativas

Cluster_viviendas$desc.var$quanti
## $`1`
##                 v.test Mean in category Overall mean sd in category Overall sd
## estrato      -43.44906         4.162000     4.633610      0.8549785   1.029160
## habitaciones -48.30433         2.861838     3.605361      0.7381741   1.459449
## areaconst    -55.11171        91.841900   174.934938     43.7281648 142.955533
## preciom      -57.59277       234.279333   433.904436    100.0212103 328.645270
## banios       -67.65133         2.092340     3.111311      0.6168498   1.428124
##              p.value
## estrato            0
## habitaciones       0
## areaconst          0
## preciom            0
## banios             0
## 
## $`2`
##                v.test Mean in category Overall mean sd in category Overall sd
## banios       32.27378         3.805623     3.111311      0.8878737   1.428124
## habitaciones 30.42291         4.274210     3.605361      1.5358014   1.459449
## estrato      21.77490         4.971191     4.633610      0.9863013   1.029160
## areaconst    13.55570       204.126768   174.934938     83.3716172 142.955533
## preciom      10.73560       487.053107   433.904436    168.5907294 328.645270
##                    p.value
## banios       1.632046e-228
## habitaciones 2.734945e-203
## estrato      4.013585e-105
## areaconst     7.331275e-42
## preciom       6.926408e-27
## 
## $`3`
##                v.test Mean in category Overall mean sd in category Overall sd
## preciom      69.41544      1069.051030   433.904436    357.1253452 328.645270
## areaconst    61.84414       421.079391   174.934938    193.3465913 142.955533
## banios       54.09829         5.262310     3.111311      1.3408209   1.428124
## estrato      33.28343         5.587287     4.633610      0.6983415   1.029160
## habitaciones 28.32988         4.756491     3.605361      1.7476843   1.459449
##                    p.value
## preciom       0.000000e+00
## areaconst     0.000000e+00
## banios        0.000000e+00
## estrato      6.707168e-243
## habitaciones 1.481562e-176

El anÔlisis de conglomerados (Figura 12, tabla 4) permitió identificar tres segmentos claramente diferenciados en el mercado inmobiliario. El primer cluster corresponde a viviendas de bajo valor, caracterizadas por menor Ôrea construida, menor número de baños y habitaciones y ubicadas en estratos socioeconómicos bajos. El segundo cluster representa el mercado medio, con viviendas de tamaño y precio moderado, orientadas a hogares familiares. El tercer cluster agrupa propiedades de alta gama, con mayor Ôrea construida, mÔs servicios y ubicadas en estratos altos, presentando precios significativamente superiores al promedio. Las diferencias entre los clusters son estadísticamente significativas, lo que confirma la existencia de una estructura segmentada en la oferta inmobiliaria urbana.

5.3 AnƔlisis de Correspondencia

Al realizar el anÔlisis entre zona y tipo, solo surge una dimensión, por lo que se decide realizar un anÔlisis tridimensional entre: zona, tipo y estrato.

df_cuali <- df_sin_coord %>%
  mutate(estrato = factor(estrato))%>%
  select(zona, tipo, estrato)

res_MCA <- MCA(df_cuali, graph = FALSE)

fviz_mca_biplot(
  res_MCA,
  repel = TRUE,
  invisible = "ind",   # oculta los 8319 puntos
  col.var = "red",     # categorĆ­as en rojo
  pointsize = 3,
  labelsize = 4,
  title = "Mapa factorial - MCA: Zona, Tipo y Estrato"
) +
  theme_minimal()

Figura 13. AnÔlisis de correspondencias múltiples

El anÔlisis de correspondencias múltiples (figura 13) evidencia una asociación entre el tipo de inmueble, la zona y el estrato socioeconómico. Se observa que los apartamentos se concentran principalmente en zonas del sur con estratos medios (4 y 5), mientras que las casas presentan mayor presencia en las zonas norte, centro y oriente, asociadas a estratos medios y bajos. La zona oeste se relaciona con el estrato 6, lo que sugiere una concentración de viviendas de alto nivel socioeconómico en esta Ôrea. Estos resultados confirman la existencia de una especialización territorial de la oferta inmobiliaria y complementan la segmentación identificada mediante el anÔlisis de conglomerados.

6 Conclusiones

  1. El mercado estÔ claramente segmentado en tres niveles: económico, medio y premium.

  2. El tamaƱo y los servicios explican mƔs el precio que el estrato solo. El estrato influye, pero el valor real lo define el producto fƭsico.

  3. El mercado medio es el mÔs relevante en volumen. Es el segmento con mayor número de propiedades de perfil familiar.

  4. El segmento premium es pequeño pero de alto margen. Ideal para inversión exclusiva y proyectos diferenciados.

  5. Existe zonificación del valor inmobiliario. Las zonas no son intercambiables, Oriente y Centro, precios altos. Sur y norte, mercado medio bajo. Esto impacta en la decisión de comprar viviendas o lotes.

7 Recomendaciones para la empresa inmobiliaria

  1. Priorizar proyectos en segmento medio, mayor liquidez.

  2. Mantener portafolio premium para rentabilidad.

  3. Evitar sobreoferta en segmento bajo sin estrategia de volumen.

8 Conclusión final

El anÔlisis multivariado evidenció una estructura segmentada del mercado inmobiliario urbano en tres niveles claramente diferenciados: económico, medio y premium. El valor de los inmuebles estÔ determinado principalmente por el tamaño y la dotación (baños y habitaciones), mÔs que por el estrato de forma aislada. Asimismo, se identificaron patrones espaciales que vinculan zonas específicas con determinados niveles socioeconómicos y tipologías de vivienda.

Estos hallazgos permiten a la empresa optimizar su portafolio, focalizar la inversión en el segmento medio como motor de liquidez, desarrollar proyectos premium en zonas de alto valor y estructurar modelos de valoración basados en atributos físicos del inmueble, generando una ventaja competitiva en la toma de decisiones estratégicas.

9 Anexos

9.1 Dataset depurado

El dataset depurado contiene 8.319 registros y variables estructurales del inmueble, incluyendo atributos físicos, socioeconómicos y espaciales. La tabla 5 permite explorar de forma interactiva la información utilizada en los anÔlisis multivariados.