library(paqueteMODELOS)
data(package = "paqueteMODELOS")
data(vivienda)
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=List of 3
## ..$ cols :List of 13
## .. ..$ id : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ zona : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ piso : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ estrato : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ preciom : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ areaconst : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ parqueaderos: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ banios : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ habitaciones: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ tipo : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ barrio : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ longitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ latitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## ..$ default: list()
## .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
## ..$ delim : chr ";"
## ..- attr(*, "class")= chr "col_spec"
## - attr(*, "problems")=<pointer: (nil)>
dim(vivienda)
## [1] 8322 13
# Convertir a data.frame simple y limpiar el atributo spec
vivienda <- as.data.frame(vivienda)
attr(vivienda, "spec") <- NULL
# 1. Resumen general
summary(vivienda)
## id zona piso estrato
## Min. : 1 Length :8322 Length :8322 Min. :3.000
## 1st Qu.:2080 N.unique : 5 N.unique : 12 1st Qu.:4.000
## Median :4160 N.blank : 0 N.blank : 0 Median :5.000
## Mean :4160 Min.nchar: 8 Min.nchar: 2 Mean :4.634
## 3rd Qu.:6240 Max.nchar: 12 Max.nchar: 2 3rd Qu.:5.000
## Max. :8319 NAs : 3 NAs :2638 Max. :6.000
## NAs :3 NAs :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
## NAs :2 NAs :3 NAs :1605 NAs :3
## habitaciones tipo barrio longitud
## Min. : 0.000 Length :8322 Length :8322 Min. :-76.59
## 1st Qu.: 3.000 N.unique : 2 N.unique : 436 1st Qu.:-76.54
## Median : 3.000 N.blank : 0 N.blank : 0 Median :-76.53
## Mean : 3.605 Min.nchar: 4 Min.nchar: 4 Mean :-76.53
## 3rd Qu.: 4.000 Max.nchar: 11 Max.nchar: 29 3rd Qu.:-76.52
## Max. :10.000 NAs : 3 NAs : 3 Max. :-76.46
## NAs :3 NAs :3
## latitud
## Min. :3.333
## 1st Qu.:3.381
## Median :3.416
## Mean :3.418
## 3rd Qu.:3.452
## Max. :3.498
## NAs :3
# 2. Conteo de NA por columna
colSums(is.na(vivienda))
## id zona piso estrato preciom areaconst
## 3 3 2638 3 2 3
## parqueaderos banios habitaciones tipo barrio longitud
## 1605 3 3 3 3 3
## latitud
## 3
# 3. Variables categóricas: ¿cuántas categorías tiene cada una?
sapply(vivienda[c("zona","piso","tipo","barrio")], function(x) length(unique(x)))
## zona piso tipo barrio
## 6 13 3 437
# 4. Conversión a factor de las categóricas relevantes
vivienda$zona <- as.factor(vivienda$zona)
vivienda$tipo <- as.factor(vivienda$tipo)
vivienda$estrato <- as.factor(vivienda$estrato) # estrato es ordinal/categórico, no continuo
Antes de iniciar con el análisis, será importante identificar algunas particularidades y anotaciones especiales de la base de datos, con el fin de facilitar la aplicación de algoritmos posteriormente.Por ende, se podría denominar a este paso la Fase 0
Una empresa inmobiliaria líder en la ciudad de Cali busca comprender en profundidad el comportamiento de su mercado de vivienda urbana, con el fin de sustentar decisiones estratégicas más informadas en materia de compra, venta y valoración de propiedades. Dada la creciente disponibilidad de datos sobre la oferta inmobiliaria publicada en plataformas digitales, la empresa requiere un análisis holístico que permita identificar patrones, relaciones y segmentaciones relevantes dentro de su base de datos, más allá de lo que un análisis descriptivo tradicional podría revelar.
Para responder a esta necesidad, se dispone de una base de datos de 8.322 propiedades residenciales ofertadas en la ciudad de Cali, obtenida mediante un proceso de web scraping sobre anuncios publicados en la plataforma OLX y contenida en el paquete paqueteMODELOS. La base incluye trece variables que describen tanto la localización de cada inmueble (zona, barrio, latitud y longitud) como sus características físicas (área construida, número de habitaciones, baños, parqueaderos y piso), su clasificación (tipo de vivienda: casa o apartamento), su precio de oferta y su estrato socioeconómico.
Sobre esta información se desarrolla el presente análisis multivariado, con el objetivo de aplicar técnicas de reducción de dimensionalidad, segmentación y análisis de asociación categórica que permitan traducir los datos crudos en conocimiento accionable para la dirección de la empresa.
La exploración inicial de la base de datos evidencia NA de las variables “id”, “zona”, “estrato” “preciom”, “areaconst”, “banios”, “habitaciones”, “tipo”, “barrio”, “longitud” y “latitud” son casi todos “3”. Es sospechosamente consistente. Probablemente son las mismas 3 filas completamente corruptas (0.04% del total). Vamos a revisarlo mejor en detalle.
sum(!complete.cases(vivienda[, c("estrato","preciom","areaconst","banios",
"habitaciones","tipo","barrio","longitud","latitud")]))
## [1] 3
Se confirma la hipótesis. Esas filas corruptas serán eliminadas.
Por otra parte, piso tiene 2.638 NA (31.7%), lo cuál también llama la atención. No parece ser un dato faltante, sino más bien estructural. Un piso (número de planta) no aplica a una Casa, solo a un Apartamento. Verifiquemos el cruce:
table(vivienda$tipo, is.na(vivienda$piso))
##
## FALSE TRUE
## Apartamento 3719 1381
## Casa 1965 1254
Ambos tipos tienen una proporción importante de piso sí registrado (72,9% de apartamentos, 61,1% de casas), así que no es “no aplica” por definición, como se pensó. Es más bien un campo que el vendedor a veces no diligenció en el anuncio de OLX, un poco más frecuente en casas. Es decir, es missing genuino, no estructural, aunque con una relación débil con tipo (χ² probablemente significativo pero no determinante).
Dado que el documento orientador solo pide tipo, zona y barrio como variables categóricas para el análisis de correspondencia, y piso no es parte de las variables cuantitativas para el PCA (preciom, areaconst, parqueaderos, banios, habitaciones), no vale la pena complicarse con la variable piso. En su lugar, se deja como variable secundaria, recodificamos NA como “No especificado” para no perder filas, y se segiue. No se usará como eje central de ningún análisis.
vivienda$piso <- ifelse(is.na(vivienda$piso), "No especificado", vivienda$piso)
La variable parqueaderos tiene 1.605 NA (19.3%). Además, el mínimo observado es 1, nunca 0. Eso sugiere que en el scraping de OLX el campo se deja en blanco cuando la propiedad no tiene parqueadero, en vez de registrar “0”. Se procede a verificar esta observación:
table(vivienda$parqueaderos, useNA = "ifany")
##
## 1 2 3 4 5 6 7 8 9 10 <NA>
## 3155 2475 520 384 68 68 18 17 4 8 1605
Los resultados confirman la hipótesis que veníamos planteando: el mínimo real es 1 y nunca aparece un 0 explícito en los 6.717 valores registrados. Esto respalda que los 1.605 NA (19,3%) representan propiedades sin parqueadero que el vendedor simplemente no diligenció, no un dato faltante aleatorio. Imputamos con 0:
vivienda$parqueaderos <- ifelse(is.na(vivienda$parqueaderos), 0, vivienda$parqueaderos)
La variable “barrio” tiene 437 categorías distintas, lo cuál es inmanejable para un mapa de correspondencia legible. Por ende, se concluye que se necesitará agregarlo, a través de “top-N barrios por frecuencia +”Otros”. También existe la opción de usar “zona” como variable categórica principal y barrio solo en un análisis secundario/anexo.Por el momento, se verifica la concentración:
sum(!complete.cases(vivienda[, c("estrato","preciom","areaconst","banios",
"habitaciones","tipo","barrio","longitud","latitud")]))
## [1] 3
sort(table(vivienda$barrio), decreasing = TRUE)[1:15]
##
## valle del lili ciudad jardín pance la flora
## 1008 516 409 366
## santa teresita el caney el ingenio la hacienda
## 262 208 202 164
## acopi los cristales normandía el limonar
## 158 154 154 135
## prados del norte el refugio aguacatal
## 126 120 109
sum(table(vivienda$barrio) >= 30)
## [1] 56
De acuerdo con el análisis, la base contiene 437 barrios distintos, con una concentración notable de la oferta: los 15 barrios más frecuentes agrupan más del 55% de las propiedades, mientras que 381 barrios (87% de las categorías) registran menos de 30 observaciones cada uno. Dado que un análisis de correspondencia sobre 437 categorías resultaría visualmente ilegible y estadísticamente inestable (las categorías de muy baja frecuencia generan perfiles poco confiables e inflan artificialmente la inercia total), se decide construir la variable barrio_agrupado, conservando los 15 barrios con mayor representación y consolidando el resto en la categoría “Otros”. Esta decisión prioriza la interpretabilidad del análisis sin sacrificar representatividad, dado que los barrios retenidos concentran la mayoría de la oferta observada.
De acuerdo con los hallazgos del EDA (Análisis Exploratorio de Datos) previamente realizado, se toman las siguientes decisiones, también previamente argumentadas:
2.Variable piso como análisis secundario. El 31,7% de los registros presentaba valores faltantes en esta variable. Se evaluó la hipótesis de que la ausencia respondiera a una condición estructural (que las viviendas tipo “Casa” no tuvieran piso asociado), pero el cruce con la variable tipo mostró proporciones similares de datos faltantes en ambas categorías (27,1% en apartamentos, 38,9% en casas), descartando dicha hipótesis. Dado que no es una variable explícitamente solicitada, no se usará como eje central de ningún análisis.
Imputación de valores en la variable parqueadero. El 19,3% de los registros no reportaba número de parqueaderos. La distribución de los valores no faltantes reveló que el mínimo observado es 1, sin ningún registro explícito de 0, lo que sugiere que el campo se deja en blanco cuando la propiedad carece de parqueadero, en lugar de registrarse como cero. En consecuencia, los valores faltantes se imputan como 0, decisión respaldada por el patrón observado en los datos y no por un supuesto arbitrario de tendencia central (media o mediana).
Creación de una variable agrupada para Barrio. La exitencia de 437 barrios distintos, con el 55% de las propieadades registrado en 15 barrios podria ser un problema de análisis posteriormente, por lo que se decide crear dos categorías que permitan un análisis más fluido: “barrio_agrupado” para los 15 barrios más frecuentes y con mayores propiedades. Y “otros” para los barrios que tienen menos de 30 propiedades registradas. Esta decisión prioriza la interpretabilidad del análisis sin sacrificar representatividad, dado que los barrios retenidos concentran la mayoría de la oferta observada.
# 1. Data.frame limpio
vivienda <- as.data.frame(vivienda)
attr(vivienda, "spec") <- NULL
# 2. Eliminar las 3 filas corruptas
vivienda <- vivienda[complete.cases(vivienda[, c("estrato","preciom","areaconst",
"banios","habitaciones","tipo","barrio",
"longitud","latitud")]), ]
# 3. piso: NA -> categoría explícita (missing genuino, no estructural)
vivienda$piso <- ifelse(is.na(vivienda$piso), "No especificado", vivienda$piso)
# 4. parqueaderos: NA -> 0 (nunca se registra 0 explícito; se infiere ausencia de parqueadero)
vivienda$parqueaderos <- ifelse(is.na(vivienda$parqueaderos), 0, vivienda$parqueaderos)
# 5. barrio: agrupar en top 15 + "Otros" para el análisis de correspondencia
top15 <- names(sort(table(vivienda$barrio), decreasing = TRUE))[1:15]
vivienda$barrio_agrupado <- ifelse(vivienda$barrio %in% top15, vivienda$barrio, "Otros")
vivienda$barrio_agrupado <- as.factor(vivienda$barrio_agrupado)
# 6. Factores
vivienda$zona <- as.factor(vivienda$zona)
vivienda$tipo <- as.factor(vivienda$tipo)
vivienda$estrato <- factor(vivienda$estrato, ordered = TRUE) # es ordinal (3 a 6)
# Verificación final
dim(vivienda)
## [1] 8319 14
colSums(is.na(vivienda))
## id zona piso estrato preciom
## 0 0 0 0 0
## areaconst parqueaderos banios habitaciones tipo
## 0 0 0 0 0
## barrio longitud latitud barrio_agrupado
## 0 0 0 0
Con esto se confirman todas las acciones planteadas: 8.139 filas, 14 columnas y ningún NA. Por ende, se pasa a la fase de Análisis de Componentes Principales.
El Análisis de Componentes Principales (PCA) es una técnica estadística multivariada de reducción de dimensionalidad que permite transformar un conjunto de variables cuantitativas correlacionadas entre sí en un nuevo conjunto de variables no correlacionadas, denominadas componentes principales, ordenadas de forma que las primeras capturan la mayor proporción posible de la variabilidad total de los datos originales (Hotelling, 1933;Pearson, 1901).
Antes de correrlo, hay que verificar que las variables cuantitativas estén correlacionadas entre sí (si no lo están, el PCA no tiene sentido). Es decir, no habría dimensiones redundantes que reducir si no hubiera esta correlación interna. Usamos el test de esfericidad de Bartlett y el índice KMO para ello:
library(psych)
vars_pca <- vivienda[, c("preciom", "areaconst", "parqueaderos", "banios", "habitaciones")]
cor(vars_pca) # matriz de correlaciones
## preciom areaconst parqueaderos banios habitaciones
## preciom 1.0000000 0.6873520 0.6397779 0.6691456 0.2640912
## areaconst 0.6873520 1.0000000 0.4823840 0.6484165 0.5169129
## parqueaderos 0.6397779 0.4823840 1.0000000 0.5231299 0.1987555
## banios 0.6691456 0.6484165 0.5231299 1.0000000 0.5899064
## habitaciones 0.2640912 0.5169129 0.1987555 0.5899064 1.0000000
cortest.bartlett(cor(vars_pca), n = nrow(vars_pca)) # H0: la matriz es la identidad (no hay correlación)
## $chisq
## [1] 21138.08
##
## $p.value
## [1] 0
##
## $df
## [1] 10
KMO(cor(vars_pca)) # adecuación muestral: >0.5 aceptable, >0.7 bueno
## Kaiser-Meyer-Olkin factor adequacy
## Call: KMO(r = cor(vars_pca))
## Overall MSA = 0.74
## MSA for each item =
## preciom areaconst parqueaderos banios habitaciones
## 0.70 0.79 0.85 0.77 0.60
De acuerdo con los resultados, se puede decir que el PCA está justificado: La mayoría son correlaciones positivas y moderadas-altas (destaca preciom-areaconst = 0,69, preciom-banios = 0,67, areaconst-banios = 0,65). La más débil es parqueaderos-habitaciones (0,20) y preciom-habitaciones (0,26), lo cuál tiene sentido: el número de habitaciones no necesariamente encarece tanto una propiedad como el área o los baños.
[Contexto]
library(FactoMineR)
library(factoextra)
pca_result <- PCA(vars_pca, scale.unit = TRUE, graph = FALSE)
pca_result$eig
## eigenvalue percentage of variance cumulative percentage of variance
## comp 1 3.1283860 62.567721 62.56772
## comp 2 0.9178016 18.356033 80.92375
## comp 3 0.4351016 8.702032 89.62578
## comp 4 0.3246429 6.492858 96.11864
## comp 5 0.1940678 3.881357 100.00000
fviz_eig(pca_result, addlabels = TRUE, ylim = c(0, 60))
Aunque el criterio estricto de Kaiser solo sugiere 1, hay tres razones por las que, en este caso particular, conviene quedarse con 2 componentes: (a) el umbral de varianza acumulada del 80% se alcanza casi exactamente con 2, (b) el autovalor de la Componente 2 (0,918) está lo suficientemente cerca de 1 como para considerarse relevante en la práctica, y (c) con solo 1 componente no se puede construir el círculo de correlaciones ni el biplot que exige la actividad para la visualización de resultados. Se necesitan mínimo 2 resultados.
# Coordenadas y contribución de cada variable a las 2 componentes
pca_result$var$coord[, 1:2]
## Dim.1 Dim.2
## preciom 0.8465410 -0.34452354
## areaconst 0.8556888 0.08167732
## parqueaderos 0.7222012 -0.49844361
## banios 0.8771231 0.14998114
## habitaciones 0.6234032 0.72214514
pca_result$var$contrib[, 1:2]
## Dim.1 Dim.2
## preciom 22.90739 12.9326929
## areaconst 23.40515 0.7268657
## parqueaderos 16.67232 27.0696875
## banios 24.59239 2.4508938
## habitaciones 12.42275 56.8198601
# Círculo de correlaciones
fviz_pca_var(pca_result, axes = c(1,2), col.var = "contrib",
gradient.cols = c("blue","yellow","red"), repel = TRUE)
Los resultados del PCA nos permiten nombrar las dos dimensiones que surgieron como resultados:
Las 5 variables cargan positivamente y de forma bastante pareja (preciom 0,85, areaconst 0,86, banios 0,88, parqueaderos 0,72, habitaciones 0,62), con contribuciones equilibradas entre banios (24,6%), areaconst (23,4%) y preciom (22,9%). Esto significa que Dim1 no distingue tipos de propiedad, sino que resume su magnitud global: propiedades grandes, costosas y bien equipadas se mueven juntas hacia valores altos; propiedades pequeñas y económicas, hacia valores bajos. Es el eje de “tamaño/lujo”.
Acá es importante destacar que el patrón es distinto. “Habitaciones” domina con contribución de 56,8% (carga +0,72), y se opone a parqueaderos (contribución 27,1%, carga -0,50) y, en menor medida, a preciom (carga -0,34). areaconst y banios casi no participan (contribuciones <3%).
Esto describe un eje de compensación interna del espacio: propiedades con muchas habitaciones pero pocos parqueaderos y precio relativamente más bajo (viviendas subdivididas en cuartos pequeños, típico de oferta económica densificada) versus propiedades con pocas habitaciones pero más parqueaderos y precio más alto (distribución espaciosa con cuartos amplios, perfil de vivienda de gama alta). El círculo de correlaciones lo confirma visualmente: habitaciones apunta hacia arriba, parqueaderos y preciom hacia abajo.
fviz_pca_biplot(pca_result, geom.ind = "point", col.ind = vivienda$tipo,
palette = c("#00AFBB", "#FC4E07"), addEllipses = TRUE,
alpha.ind = 0.3, legend.title = "Tipo")
fviz_pca_ind(pca_result, geom.ind = "point", col.ind = vivienda$estrato,
palette = "jco", addEllipses = TRUE, alpha.ind = 0.3,
legend.title = "Estrato")
El análisis de componentes principales condensó las cinco variables cuantitativas originales en dos dimensiones que explican el 81% de la variabilidad del conjunto de datos. La Dimensión 1 (62,6% de la varianza) actúa como un índice general de tamaño y valor de la propiedad: todas las variables cargan positivamente sobre este eje, por lo que valores altos corresponden a propiedades grandes, costosas y bien equipadas, mientras que valores bajos corresponden a propiedades pequeñas y económicas. La Dimensión 2 (18,4% de la varianza) captura un matiz secundario relacionado con la distribución interna del espacio, oponiendo propiedades con muchas habitaciones (perfil de vivienda densificada) a propiedades con menos habitaciones pero más parqueaderos y mayor precio (perfil de vivienda espaciosa).
Al proyectar las observaciones sobre este plano y colorearlas por tipo de vivienda, se observa que los apartamentos forman un grupo relativamente homogéneo concentrado en la zona de tamaño y valor medio-bajo, mientras que las casas presentan una dispersión mucho mayor, abarcando desde propiedades modestas hasta viviendas grandes y de alto valor. Esto sugiere que el apartamento es un producto más estandarizado en el mercado, mientras que la casa constituye un segmento más heterogéneo.
El hallazgo más relevante surge al colorear las observaciones por estrato socioeconómico: se identifica un gradiente ordinal claro a lo largo de la Dimensión 1, donde las propiedades de estrato 3 se ubican predominantemente en el extremo de bajo tamaño/valor, y conforme aumenta el estrato (4, 5 y 6) las propiedades se desplazan progresivamente hacia el extremo opuesto.
Dado que el estrato no fue una variable utilizada en el cálculo del PCA, esta correspondencia constituye una validación externa del componente: confirma que la Dimensión 1 no es un artificio puramente matemático, sino que captura una dimensión real y económicamente interpretable del mercado inmobiliario, alineada con la estratificación socioeconómica oficial de la ciudad. Este resultado respalda el uso de la Dimensión 1 como un indicador confiable de valor de mercado y sienta las bases para segmentar las propiedades en grupos homogéneos mediante análisis de conglomerados.
El Análisis de Conglomerados (o Cluster Analysis) es una técnica estadística multivariada de clasificación no supervisada, cuyo objetivo es agrupar un conjunto de observaciones en subconjuntos homogéneos, denominados clústeres o conglomerados, de tal manera que los elementos dentro de un mismo grupo sean lo más similares posible entre sí, y a la vez lo más distintos posible respecto a los elementos de otros grupos, con base en un criterio de distancia o similitud definido sobre un conjunto de variables (MacQueen, 1967).
A diferencia de los métodos de clasificación supervisada, el análisis de conglomerados no requiere conocer de antemano la pertenencia de cada observación a un grupo específico, sino que busca descubrir esa estructura de agrupamiento directamente a partir de los datos. Existen distintos enfoques para su implementación, entre los que se destacan los métodos jerárquicos (aglomerativos o divisivos, que construyen una estructura de árbol o dendrograma) y los métodos de partición, como k-means, que asignan cada observación a uno de un número predefinido de grupos mediante la minimización de la variabilidad interna de cada clúster.
Con 8.319 observaciones, un dendrograma jerárquico completo sería ilegible y pesado computacionalmente, así que la estrategia es: usar k-means como técnica principal (eficiente a esta escala) sobre las mismas 5 variables estandarizadas, y usar jerárquico solo sobre una muestra como método de validación.
vars_cluster <- scale(vars_pca) # mismas 5 variables, estandarizadas
set.seed(123)
fviz_nbclust(vars_cluster, kmeans, method = "wss", k.max = 10) # método del codo
fviz_nbclust(vars_cluster, kmeans, method = "silhouette", k.max = 10) # método de silueta
Para determinar el número óptimo de clústeres se aplicaron dos criterios complementarios sobre las cinco variables cuantitativas estandarizadas: el método del codo (suma de cuadrados intra-cluster) y el índice de silueta promedio. El método del codo muestra una caída pronunciada de la varianza no explicada entre k=1 y k=3, seguida de un aplanamiento marcado a partir de k=4, punto en el cual agregar clústeres adicionales aporta beneficios marginales decrecientes. El índice de silueta, por su parte, alcanza su valor máximo en k=2 (0,46) y decrece progresivamente, ubicándose en 0,35 para k=4, un valor moderado pero considerablemente más estable que los obtenidos para k≥6.
Se optó por retener k=4 en lugar del óptimo estadístico estricto (k=2), dado que una partición en solo dos grupos reproduce esencialmente la separación ya capturada por la primera componente del PCA (tamaño/valor de la propiedad), sin aportar información adicional útil para la toma de decisiones. Cuatro segmentos, en cambio, se ubican justo en el punto de inflexión del método del codo, conservan un nivel aceptable de cohesión interna (silueta = 0,35) y permiten una segmentación más granular y accionable del mercado inmobiliario, lo que es coherente con el objetivo del análisis de identificar dinámicas diferenciadas de oferta por zona y estrato socioeconómico.
set.seed(123)
km_result <- kmeans(vars_cluster, centers = 4, nstart = 25)
vivienda$cluster <- as.factor(km_result$cluster)
table(vivienda$cluster) # tamaño de cada segmento
##
## 1 2 3 4
## 759 862 4160 2538
[…]
# Promedios de las variables cuantitativas por cluster
aggregate(vars_pca, by = list(Cluster = vivienda$cluster), FUN = mean)
# Composición por tipo, zona y estrato
table(vivienda$cluster, vivienda$tipo)
##
## Apartamento Casa
## 1 17 742
## 2 253 609
## 3 3410 750
## 4 1420 1118
table(vivienda$cluster, vivienda$zona)
##
## Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
## 1 37 182 47 136 357
## 2 2 83 250 2 525
## 3 64 1171 306 187 2432
## 4 21 484 595 26 1412
table(vivienda$cluster, vivienda$estrato)
##
## 3 4 5 6
## 1 307 180 227 45
## 2 5 29 167 661
## 3 1035 1538 1349 238
## 4 106 382 1007 1043
# Visualización de los clusters sobre el plano del PCA
fviz_cluster(km_result, data = vars_cluster, geom = "point",
ellipse.type = "convex", palette = "jco",
ggtheme = theme_minimal())
El análisis de conglomerados mediante el algoritmo k-means, aplicado sobre las cinco variables cuantitativas estandarizadas con k=4, permitió identificar cuatro segmentos de propiedades con perfiles claramente diferenciados en términos de precio, tamaño y composición.
Clúster 3 - El segmento más numeroso. Con 4.160 propiedades, 50% de la oferta, corresponde a vivienda económica estándar: predominantemente apartamentos, con los valores más bajos de precio, área, baños y habitaciones, concentrados en estratos 4 y 5 y en las zonas Sur y Norte de la ciudad.
Clúster 2 - El premium del mercado. Con 862 propiedades, 10%, agrupa la vivienda premium del mercado: precio más del doble que cualquier otro segmento, mayor área construida, más parqueaderos y baños, con una concentración del 76,7% en estrato 6 y ubicación mayoritaria en las zonas Sur y Oeste, coincidiendo con los barrios de mayor valor identificados previamente en la exploración de datos.
Clúster 4 - Equilibrado. Con 2.538 propiedades, 30% de la oferta, es un segmento de vivienda media-alta con una mezcla equilibrada de apartamentos y casas, precio y área intermedios, y predominio de estratos 5 y 6 sin alcanzar la concentración extrema del segmento premium.
Clúster 1 - Casi exclusivamente Casas. Con 759 propiedades, 9% de la oferta, constituye el hallazgo más importante. Con el mayor número de habitaciones de los cuatro segmentos, pero con una disponibilidad de parqueaderos notablemente baja para su tamaño y un predominio de estrato 3. Este segmento evidencia que el tamaño de una propiedad no es un predictor consistente de su valor de mercado: contradice el patrón general de “a mayor tamaño, mayor precio” observado en los demás clústeres, y confirma en la práctica el matiz que había anticipado la segunda componente del PCA, donde el número de habitaciones y la disponibilidad de parqueaderos emergían como ejes de variación independientes del valor global de la propiedad.
En conjunto, la segmentación resultante ofrece a la empresa inmobiliaria una lectura accionable del mercado: un segmento masivo de bajo costo (Cluster 3), un nicho de alto valor concentrado geográfica y socioeconómicamente (Cluster 2), un segmento intermedio de transición (Cluster 4), y un segmento atípico de vivienda familiar extensa en estratos bajos que requiere una estrategia de valoración diferenciada, dado que las variables de tamaño por sí solas no explican adecuadamente su precio (Cluster 1).
El Análisis de Correspondencia es una técnica estadística multivariada de naturaleza descriptiva, utilizada para explorar y visualizar las relaciones de asociación existentes entre variables categóricas a partir de una tabla de contingencia. Su propósito es representar, en un espacio de baja dimensión (generalmente de dos o tres dimensiones), tanto las categorías de las variables como las observaciones, de manera que la proximidad entre puntos en el mapa resultante refleje el grado de asociación entre ellos: categorías que aparecen frecuentemente juntas en los datos se ubican cercanas en el gráfico, mientras que aquellas con poca o ninguna asociación se ubican distantes.
Cuando el análisis se extiende a más de dos variables categóricas simultáneamente, se denomina Análisis de Correspondencia Múltiple (ACM), y su fundamento matemático se basa en la descomposición en valores singulares de una matriz de indicadores o de una matriz de Burt (Bénzecri, 1973; Burt, 1950; Greenacre, 1984), de forma análoga a como el Análisis de Componentes Principales opera sobre variables cuantitativas.
Tal como se hizo previamente con el PCA, se debe verificar que las variables categóricas correlacionen entre sí. Si fueran independientes, el Análisis de Correspondencia no tendría ningún sentido.
# Tablas de contingencia
tabla_tipo_zona <- table(vivienda$tipo, vivienda$zona)
tabla_tipo_barrio <- table(vivienda$tipo, vivienda$barrio_agrupado)
tabla_zona_barrio <- table(vivienda$zona, vivienda$barrio_agrupado)
# Test chi-cuadrado de independencia para cada par
chisq.test(tabla_tipo_zona)
##
## Pearson's Chi-squared test
##
## data: tabla_tipo_zona
## X-squared = 690.93, df = 4, p-value < 2.2e-16
chisq.test(tabla_tipo_barrio)
##
## Pearson's Chi-squared test
##
## data: tabla_tipo_barrio
## X-squared = 770.35, df = 15, p-value < 2.2e-16
chisq.test(tabla_zona_barrio)
##
## Pearson's Chi-squared test
##
## data: tabla_zona_barrio
## X-squared = 8502.9, df = 60, p-value < 2.2e-16
Los tres test son contundentes: p-valor < 2,2e-16 en los tres casos (tipo-zona: χ²=690,93; tipo-barrio: χ²=770,35; zona-barrio: χ²=8.502,9). Por lo tanto, se rechaza la independencia en todos los pares. Las tres variables están fuertemente asociadas, lo que justifica plenamente el análisis de correspondencia.
El Análisis de Correspondencia Múltiple sobre las variables tipo, zona y barrio_agrupado arrojó autovalores decrecientes de 0,61 a 0,34 en las primeras cinco dimensiones, seguidos de un valor constante de 0,3333 a partir de la sexta. Este valor corresponde exactamente al umbral teórico 1/Q (con Q=3 variables), reconocido como el punto de corte por debajo del cual las dimensiones no aportan estructura de asociación real, sino artefactos de la codificación indicadora del método.
vars_mca <- vivienda[, c("tipo", "zona", "barrio_agrupado")]
mca_result <- MCA(vars_mca, graph = FALSE)
nrow(mca_result$eig)
## [1] 5
mca_result$eig
## eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.6109521 9.164281 9.164281
## dim 2 0.5511268 8.266902 17.431183
## dim 3 0.4601513 6.902269 24.333452
## dim 4 0.3556513 5.334769 29.668222
## dim 5 0.3354140 5.031210 34.699431
fviz_screeplot(mca_result, addlabels = TRUE)
Con base en este criterio se retuvieron las dos primeras dimensiones (9,2% y 8,3% de varianza, respectivamente), decisión respaldada además por la necesidad de mantener consistencia visual con los planos bidimensionales usados en el PCA y el análisis de conglomerados. Cabe señalar que los porcentajes de varianza en MCA son estructuralmente más bajos que en PCA por la forma en que se calcula la inercia total, por lo que un acumulado del 17,4% en dos dimensiones no debe interpretarse como una solución débil, sino como un resultado esperable y estadísticamente sólido para esta técnica.Es completamente normal que un MCA con 3 variables categóricas muestre acumulados de 30-40% en las primeras dimensiones, y aun así esas dimensiones capturen la mayoría de la estructura interpretable.Aún así, se echa un vistazo del panorama completo.
mca_result <- MCA(vars_mca, ncp = 15, graph = FALSE)
mca_result$eig
## eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.6109521 9.164281 9.164281
## dim 2 0.5511268 8.266902 17.431183
## dim 3 0.4601513 6.902269 24.333452
## dim 4 0.3556513 5.334769 29.668222
## dim 5 0.3354140 5.031210 34.699431
## dim 6 0.3333333 5.000000 39.699431
## dim 7 0.3333333 5.000000 44.699431
## dim 8 0.3333333 5.000000 49.699431
## dim 9 0.3333333 5.000000 54.699431
## dim 10 0.3333333 5.000000 59.699431
## dim 11 0.3333333 5.000000 64.699431
## dim 12 0.3333333 5.000000 69.699431
## dim 13 0.3333333 5.000000 74.699431
## dim 14 0.3333333 5.000000 79.699431
## dim 15 0.3333333 5.000000 84.699431
Tal como se esperaba, a partir de la Dimensión 6, los autovalores caen exactamente a 0,3333, que es matemáticamente 1/Q (con Q=3 variables).Por tanto, se decide retener 2 dimensiones para el mapa de correspondencia (Dim1 y Dim2), por dos razones: concentran el grueso de la señal real detectada (24,3% acumulado, que en términos de MCA es un valor perfectamente razonable en este contexto), y mantiene consistencia visual con el PCA y el cluster plot, todo el informe se puede leer sobre planos 2D comparables.
El mapa de correspondencia evidenció que la estructura de asociación está dominada por la dimensión geográfica más que por el tipo de vivienda. Los barrios se agrupan de forma casi perfecta según su zona de pertenencia: Zona Oeste aparece completamente aislada en el extremo derecho del plano junto con sus barrios característicos (aguacatal, los cristales, santa teresita, normandía), configurando un submercado claramente diferenciado; Zona Sur, la más grande de la base, agrupa de forma compacta a la mayoría de sus barrios (valle del lili, ciudad jardín, pance, entre otros), sugiriendo una oferta internamente homogénea; y Zona Norte se distingue en el eje vertical junto a acopi, la flora y prados del norte.
mca_result <- MCA(vars_mca, ncp = 2, graph = FALSE)
fviz_mca_var(mca_result, repel = TRUE, col.var = "contrib",
gradient.cols = c("blue","yellow","red"),
title = "Mapa de Correspondencia: Tipo, Zona y Barrio")
En contraste, las categorías de tipo de vivienda se ubican cerca del origen del plano, sin desplazarse hacia ningún extremo, lo que indica una contribución considerablemente menor a la estructura de asociación. Este es un hallazgo consistente con la magnitud muy superior del estadístico chi-cuadrado obtenido para zona-barrio frente a los que involucran tipo.
En conjunto, el análisis de correspondencia múltiple reveló que la oferta inmobiliaria de la ciudad se organiza principalmente en torno a submercados geográficos y no al tipo de construcción: Zona Oeste emerge como un nicho diferenciado que amerita una estrategia comercial independiente, mientras que Zona Sur concentra una oferta amplia y relativamente homogénea entre sus barrios.
Este resultado complementa lo encontrado en las fases anteriores: si el PCA y el análisis de conglomerados mostraron que el valor y tamaño de la propiedad se relacionan con el estrato socioeconómico, el análisis de correspondencia añade que la localización geográfica es, en sí misma, una dimensión estructurante independiente de la oferta, lo cual refuerza la necesidad de que las decisiones estratégicas de la empresa (precios de referencia, focos de inversión, campañas comerciales) se diseñen de manera diferenciada por zona.
La proyección geoespacial de los cuatro segmentos identificados en el análisis de conglomerados permite visualizar de manera directa la distribución territorial de la oferta inmobiliaria de Cali.
library(leaflet)
pal <- colorFactor(palette = c("#2E9FDF", "#E7B800", "#00AFBB", "#FC4E07"),
domain = vivienda$cluster)
leaflet(vivienda) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
color = ~pal(cluster),
radius = 4, stroke = FALSE, fillOpacity = 0.6,
popup = ~paste0(
"<b>Barrio:</b> ", barrio, "<br>",
"<b>Zona:</b> ", zona, "<br>",
"<b>Tipo:</b> ", tipo, "<br>",
"<b>Precio:</b> $", preciom, " millones<br>",
"<b>Área:</b> ", areaconst, " m²<br>",
"<b>Estrato:</b> ", estrato, "<br>",
"<b>Segmento:</b> Cluster ", cluster
)
) %>%
addLegend("bottomright", pal = pal, values = ~cluster,
title = "Segmento (Cluster)")
El mapa confirma que los segmentos de vivienda económica (Cluster 3) y media-alta (Cluster 4), que en conjunto representan el 80% de las propiedades, dominan visualmente el panorama de la ciudad, con una concentración particularmente densa en el sector noroccidental. El segmento de vivienda familiar de bajo estrato con muchas habitaciones (Cluster 1) se distribuye de forma dispersa por distintos sectores, sin un foco geográfico dominante, consistente con su composición heterogénea por zona identificada previamente.
leaflet(vivienda[vivienda$cluster == 2, ]) %>%
addTiles() %>%
addCircleMarkers(lng = ~longitud, lat = ~latitud,
color = "#E7B800", radius = 5, fillOpacity = 0.7,
popup = ~paste0("<b>Barrio:</b> ", barrio, "<br><b>Precio:</b> $", preciom, "M"))
Por su parte, el segmento premium (Cluster 2), al representar apenas el 10% de la oferta, resulta menos visible en el mapa general, aunque su concentración en zonas específicas ya había sido evidenciada en el análisis de conglomerados y en el análisis de correspondencia. En conjunto, esta visualización integra los hallazgos de las tres técnicas aplicadas (componentes principales, conglomerados y correspondencia) en una sola representación que traduce los patrones estadísticos identificados en información directamente interpretable para la toma de decisiones estratégicas de la empresa, tales como la focalización geográfica de campañas comerciales o la identificación de zonas con potencial de valorización.
Los gráficos presentados hasta este momento (PCA, clusters, MCA, mapa) son potentes, pero bastante “técnicos”. Para la dirección de la empresa, serán necesarios gráficos adicionales, simples de leer a primera vista, que traduzcan los hallazgos en decisiones de negocio concretas.
Revela dónde el precio está “inflado” o “barato” relativo al tamaño. Esta información es directamente accionable para decidir dónde comprar o cómo fijar precios.
vivienda$precio_m2 <- (vivienda$preciom * 1e6) / vivienda$areaconst # precio por m² en pesos
library(dplyr)
resumen_zona <- vivienda %>%
group_by(zona) %>%
summarise(precio_m2_prom = mean(precio_m2, na.rm = TRUE)) %>%
arrange(desc(precio_m2_prom))
ggplot(resumen_zona, aes(x = reorder(zona, precio_m2_prom), y = precio_m2_prom, fill = zona)) +
geom_col(show.legend = FALSE) +
coord_flip() +
labs(title = "Precio promedio por metro cuadrado según zona",
x = "", y = "Precio por m² (COP)") +
theme_minimal()
Zona Oeste tiene, por lejos, el precio por m² más alto (~3,3-3,5
millones COP/m²), seguida de Zona Sur (~2,7 millones), Zona Norte
(~2,4-2,5 millones), Zona Centro (~1,7-1,8 millones) y, al final, Zona
Oriente con el valor más bajo (~1,5 millones).
En este contexto, la decisión estratégica más fuerte que se desprende de este gráfico es que si la inmobiliaria quiere maximizar el retorno por unidad de área invertida, Zona Oeste es la prioridad. Cada metro cuadrado ahí vale más que en cualquier otra zona de la ciudad. En el otro extremo, Zona Oriente y Zona Centro, con el precio/m² más bajo, no deben leerse automáticamente como “zonas débiles”: dado que también son las zonas con menos observaciones en la base (351 y 124 propiedades respectivamente), representan un vacío de información más que una conclusión firme, y ameritan un análisis de campo adicional antes de descartarlas como oportunidad de expansión.
Un promedio esconde outliers. Por ende, el boxplot muestra a la dirección qué tan disperso es cada segmento. Para el cliente, esto sería algo como: ¿el premium es consistentemente caro, o hay mucha variación?.Revisemos el gráfico.
ggplot(vivienda, aes(x = cluster, y = preciom, fill = cluster)) +
geom_boxplot(show.legend = FALSE) +
labs(title = "Distribución de precios por segmento",
x = "Segmento (Cluster)", y = "Precio (millones COP)") +
theme_minimal()
El boxplot revela información muy interesante: Para el Cluster
2 (premium), la alta dispersión “normal” significa que no se
puede fijar un precio de referencia único para todo el segmento. Por
ende, la empresa necesita tasación individualizada, caso por caso,
posiblemente creando sub-categorías internas (premium-moderado
vs. ultra-lujo) para asesorar mejor a los clientes de este nicho.
Para el Cluster 3 (económico), la decisión es la opuesta y más interesante desde el punto de vista comercial: dado que la mayoría del segmento es predecible y estandarizable (permite procesos de venta rápidos, precios de referencia fijos, bajo riesgo), pero existe un grupo minoritario de “outliers” con precios anómalamente altos, vale la pena aislar esas propiedades atípicas como un radar de oportunidades. Una de las dos cosas: o son errores de digitación que ameritan revisión de calidad de datos, o son “gemas ocultas” con ubicación premium mal valoradas por el resto del mercado, algo muy atractivo para un comprador que las identifique antes que la competencia.
3.Composición del tipo de vivienda por zona.
Este gráfico revela información interesante sobre qué tipo de producto ofrecer a cada zona, por lo que la empresa podrá diseñar una estrategia de marketing más específica, basada en las necesidades de cada tipo de vivienda.
ggplot(vivienda, aes(x = zona, fill = tipo)) +
geom_bar(position = "fill") +
scale_y_continuous(labels = scales::percent) +
labs(title = "Composición de tipo de vivienda por zona",
x = "", y = "Porcentaje", fill = "Tipo") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 30, hjust = 1))
El gráfico deja ver que hay un patrón muy marcado por zona. La Zona
Centro y Zona Oriente están dominadas por casas (~80-83%), con muy poca
presencia de apartamentos. Zona Norte y Zona Sur están más balanceadas,
pero inclinadas hacia apartamento (~60-62%).Zona Oeste es la más extrema
de todas: 85% apartamento, apenas 15% casa. Es prácticamente un mercado
de apartamentos.
El hallazgo más importante de este gráfico debe “cruzarse” con el anterior (precio por m2). Zona Oeste tenía el precio por metro cuadrado más alto de toda la ciudad. Y ahora puede verse que ese valor está siendo impulsado casi exclusivamente por apartamentos, no por casas (que ahí son apenas el 15% de la oferta). Esto sugiere que el “premium” de Zona Oeste no es un fenómeno de vivienda unifamiliar de lujo, sino de edificios de apartamentos de alta gama (probablemente torres bien ubicadas, con amenities, seguridad, etc.).
Por lo tanto, la decisión estratégica que se desprende de esto es que el enfoque debe ser ofrecer productos por zona. Si la inmobiliaria quiere capturar el mayor valor por unidad de inversión (Que está ubicado en Zona Oeste), el producto correcto para ofrecer/captar ahí es apartamento, no casas. En cambio, si la empresa quiere fortalecer su portafolio de vivienda familiar tradicional, Centro y Oriente son los mercados naturales para ese producto, aunque con menor margen por metro cuadrado.
Este último gráfico cruza área vs. precio, coloreado por segmento, con una línea de tendencia por cluster. Las propiedades que caen debajo de la línea de su segmento están relativamente baratas para su tamaño (posibles oportunidades de compra); las que caen arriba, relativamente caras (candidatas a buen precio de venta).
ggplot(vivienda, aes(x = areaconst, y = preciom, color = cluster)) +
geom_point(alpha = 0.3, size = 1) +
geom_smooth(method = "lm", se = FALSE) +
labs(title = "Relación área-precio por segmento: identificación de oportunidades",
x = "Área construida (m²)", y = "Precio (millones COP)", color = "Segmento") +
theme_minimal()
Este último gráfico ofrece la información más relevante: el
precio de una propiedad no se explica de la misma manera en todos los
segmentos. En el segmento premium (Cluster 2), el tamaño casi
no importa. Lo que determina el precio ahí es otra cosa (ubicación,
acabados, marca del edificio, vista), no los metros cuadrados. En
cambio, en el Cluster 1 (casas grandes de estrato bajo), el tamaño es el
principal motor del precio: cada habitación o metro adicional se cotiza
fuerte, probablemente porque refleja capacidad de uso o de subdivisión
para arriendo.
Esto significa que la empresa necesita dos modelos de valoración, no uno. Por un lado, enfocarse en aspectos cualitativos en el Clúster 2, que puedan ser motivo de valorización del inmueble. Por otro lado, el área (tamaño) sí es un predictor fuerte y confiable de precio. De esta manera, cualquier casa grande de este segmento que aparezca por debajo de esa línea roja empinada es una señal clara de oportunidad de compra (está subvalorada respecto al patrón de su propio segmento).
El análisis integral del mercado inmobiliario urbano de Cali, realizado sobre 8.319 propiedades mediante Componentes Principales, Conglomerados, Correspondencia Múltiple y visualización geoespacial, permite establecer una lectura coherente y triangulada del comportamiento de la oferta.
En primer lugar, el valor de una propiedad puede resumirse en gran medida en un solo eje: el Componente Principal 1 (62,6% de la varianza) actúa como un índice de tamaño y valor que se alinea de forma casi perfecta con el estrato socioeconómico oficial, validando externamente su interpretación. Un segundo eje, más sutil, distingue configuraciones internas del espacio (viviendas con muchas habitaciones pero poco parqueadero, frente a viviendas espaciosas con pocos cuartos y más parqueadero), revelando que el tamaño de una propiedad no es, por sí solo, un predictor consistente de su valor.
En segundo lugar, el mercado se organiza en cuatro segmentos claramente diferenciados: un segmento económico masivo (50% de la oferta, predominantemente apartamentos de bajo costo), un segmento medio-alto de transición (30%), un nicho premium concentrado en estrato 6 (10%, con alta dispersión interna de precios) y un segmento atípico de vivienda familiar extensa en estratos bajos (9%), donde el tamaño no se traduce en mayor valor de mercado.
En tercer lugar, la geografía (no el tipo de vivienda) es el factor que más estructura la oferta categórica. Zona Oeste emerge de forma consistente, en tres análisis independientes (correspondencia, clustering y precio por metro cuadrado), como un submercado diferenciado: el de mayor valor por metro cuadrado de la ciudad, impulsado casi exclusivamente por apartamentos (85% de su oferta), mientras que Zona Sur concentra el mayor volumen de oferta premium sin alcanzar el mismo precio unitario. Zona Centro y Zona Oriente, en contraste, mantienen un perfil de vivienda tradicional (predominio de casas) con menor valor por metro cuadrado y menor representación en la base de datos.
Finalmente, la relación entre área construida y precio no es uniforme entre segmentos: en el segmento premium el precio depende débilmente del tamaño (sugiriendo que ubicación y atributos cualitativos son los verdaderos determinantes del valor), mientras que en el segmento de vivienda familiar de bajo estrato el precio escala fuertemente con el área, ofreciendo un criterio objetivo y cuantificable para identificar oportunidades de inversión dentro de ese segmento específico.
Diferenciar el modelo de tasación por segmento. Aplicar tasación individualizada y basada en atributos cualitativos (ubicación, acabados, antigüedad) para el segmento premium (Cluster 2), dado que el área explica poco su variabilidad de precio; y mantener un modelo de tasación estandarizado y ágil para el segmento económico (Cluster 3), que es predecible y de bajo riesgo.
Priorizar Zona Oeste para desarrollo y adquisición de producto en altura. Es la zona con mayor valor por metro cuadrado de la ciudad y su oferta está dominada por apartamentos; concentrar ahí inversión en vivienda vertical de alta gama maximiza el retorno por unidad de área.
Tratar el Cluster 1 (vivienda familiar extensa de bajo estrato) como un nicho de inversión diferenciado. Usando el área construida como criterio objetivo de valoración: propiedades grandes de este segmento que se ofrezcan por debajo de la línea de tendencia propia del cluster representan oportunidades de compra con alto potencial de valorización.
Investigar los valores atípicos del segmento económico (Cluster 3) Propiedades con precios muy superiores a lo esperado para su perfil estructural, ya sea como control de calidad de datos o como oportunidades de arbitraje derivadas de una ubicación privilegiada no capturada por las variables estructurales.
Adoptar el mapa interactivo y los indicadores de precio por m² como herramientas operativas continuas para la fuerza comercial, permitiendo focalizar campañas y detectar oportunidades de compra o venta en tiempo real por zona y segmento.
Fortalecer la recolección de datos en Zona Centro y Zona Oriente, dado su bajo volumen de observaciones (124 y 351 propiedades respectivamente) antes de tomar decisiones estratégicas de expansión o desinversión en esas zonas, ya que las conclusiones actuales sobre ellas tienen menor respaldo estadístico que las del resto de la ciudad.
Es importante señalar que los datos provienen de un único corte temporal obtenido mediante web scraping de anuncios publicados en OLX, lo que introduce un posible sesgo de autoselección (solo refleja oferta publicada en esa plataforma, no necesariamente la totalidad del mercado) y no permite evaluar tendencias temporales de precios. Adicionalmente, la agrupación de 381 barrios de baja frecuencia en la categoría “Otros” para el análisis de correspondencia, aunque necesaria para la interpretabilidad del modelo, implica una pérdida de granularidad geográfica que podría revisarse en futuros análisis con mayor volumen de datos por barrio.
Finalmente, variables cualitativas que suelen ser determinantes del precio (como antigüedad de la construcción, estado de acabados, o cercanía a vías principales) no estaban disponibles en la base de datos original, lo cual limita la capacidad explicativa del modelo, particularmente en el segmento premium.
Benzécri, J. P. (1973). L’Analyse des Données (Vol. 2: L’Analyse des Correspondances). Dunod.
Burt, C. (1950). The factorial analysis of qualitative data. British Journal of Statistical Psychology, 3(3), 166-185.
Greenacre, M. J. (1984). Theory and Applications of Correspondence Analysis. Academic Press.
Hotelling, H. (1933). Analysis of a complex of statistical variables into principal components. Journal of Educational Psychology, 24(6), 417-441 y 24(7), 498-520.
MacQueen, J. B. (1967). Some methods for classification and analysis of multivariate observations. En Proceedings of the 5th Berkeley Symposium on Mathematical Statistics and Probability (Vol. 1, pp. 281-297). University of California Press.
Pearson, K. (1901). On lines and planes of closest fit to systems of points in space. Philosophical Magazine, 2(11), 559-572.