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.
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")=<externalptr>
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:
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.
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.
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.
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.
La base de datos vivienda contiene 8.322 registros y 13 variables asociadas a inmuebles residenciales. Cada observación corresponde a una vivienda identificada por un id y caracterizada por su ubicación (zona y barrio, además de coordenadas geográficas longitud y latitud), por rasgos físicos de la vivienda (por ejemplo, piso, área construida y tipo de inmueble), y por variables habitacionales como número de habitaciones, baños y parqueaderos. También incluye información socioeconómica y de mercado, como el estrato y el precio (variable preciom). En general, la base integra variables categóricas (zona, piso, tipo, barrio) y numéricas (estrato, preciom, areaconst, parqueaderos, baños, habitaciones, longitud y latitud). La información presente en la base de datos se expone en la Tabla 1.
reactable(vivienda, rownames = TRUE)
Para el análisis descriptivo, se analiza primero que tipos de variables hay presente en la base de datos (Tabla 2).
tipos <- sapply(vivienda, class)
tabla_tipos <- data.frame(
Nombre = names(tipos),
Tipo = as.character(tipos),
row.names = NULL
)
tagList(
h4("Tabla 2: Tipos de datos"),
reactable(tabla_tipos,
columns = list(
Nombre = colDef(name = "Nombre de la variable"),
Tipo = colDef(name = "Tipo de dato")
)))
En particular, las variables zona, piso, tipo y barrio corresponden a etiquetas cualitativas sin significado numérico directo, por lo que se transformaron a factores. Asimismo, variables como estrato, número de parqueaderos, baños y habitaciones, aunque registradas numéricamente, representan conteos o niveles ordinales más que magnitudes continuas, por lo que también se consideraron factores ordenados. Esta transformación facilita la construcción de tablas de frecuencia, proporciones y gráficos descriptivos, permitiendo una interpretación más adecuada de la información categórica contenida en la base de datos.
Tras aplicar las transformaciones, se obtiene nuevamente la tabla de tipos de variables (Tabla 3), ahora con los cambios reflejados en el dataset:
vivienda$zona<-as.factor(unlist(vivienda$zona))
vivienda$piso<-as.factor(unlist(vivienda$piso))
vivienda$tipo<-as.factor(unlist(vivienda$tipo))
vivienda$barrio<-as.factor(unlist(vivienda$barrio))
vivienda$estrato<-as.factor(unlist(vivienda$estrato))
vivienda$parqueaderos<-as.factor(unlist(vivienda$parqueaderos))
vivienda$banios<-as.factor(unlist(vivienda$banios))
vivienda$habitaciones<-as.factor(unlist(vivienda$habitaciones))
tipos <- sapply(vivienda, class)
tabla_tipos <- data.frame(
Nombre = names(tipos),
Tipo = as.character(tipos),
row.names = NULL
)
tagList(
h4("Tabla 3: Tipos de datos posterior a la transformación de variables"),
reactable(tabla_tipos,
columns = list(
Nombre = colDef(name = "Nombre de la variable"),
Tipo = colDef(name = "Tipo de dato")
)))
Posterior a la conversión de variables a factor, se procede a realizar un resumen estadístico general de la base de datos (Figura 1). Este paso permite obtener una primera visión de la distribución de cada variable, identificando valores mínimos, máximos, medias, medianas y cuartiles en el caso de las variables numéricas, así como las frecuencias absolutas para las variables de tipo factor.
De esta manera, el resumen constituye una herramienta inicial para detectar posibles valores atípicos, inconsistencias y patrones relevantes que orientarán el análisis posterior.
summary(vivienda)
## id zona piso estrato preciom
## Min. : 1 Zona Centro : 124 02 :1450 3 :1453 Min. : 58.0
## 1st Qu.:2080 Zona Norte :1920 03 :1097 4 :2129 1st Qu.: 220.0
## Median :4160 Zona Oeste :1198 01 : 860 5 :2750 Median : 330.0
## Mean :4160 Zona Oriente: 351 04 : 607 6 :1987 Mean : 433.9
## 3rd Qu.:6240 Zona Sur :4726 05 : 567 NA's: 3 3rd Qu.: 540.0
## Max. :8319 NA's : 3 (Other):1103 Max. :1999.0
## NA's :3 NA's :2638 NA's :2
## areaconst parqueaderos banios habitaciones
## Min. : 30.0 1 :3155 2 :2946 3 :4097
## 1st Qu.: 80.0 2 :2475 3 :1993 4 :1729
## Median : 123.0 3 : 520 4 :1456 2 : 926
## Mean : 174.9 4 : 384 5 : 890 5 : 679
## 3rd Qu.: 229.0 5 : 68 1 : 496 6 : 318
## Max. :1745.0 (Other): 115 (Other): 538 (Other): 570
## NA's :3 NA's :1605 NA's : 3 NA's : 3
## tipo barrio longitud latitud
## Apartamento:5100 valle del lili:1008 Min. :-76.59 Min. :3.333
## Casa :3219 ciudad jardín : 516 1st Qu.:-76.54 1st Qu.:3.381
## NA's : 3 pance : 409 Median :-76.53 Median :3.416
## la flora : 366 Mean :-76.53 Mean :3.418
## santa teresita: 262 3rd Qu.:-76.52 3rd Qu.:3.452
## (Other) :5758 Max. :-76.46 Max. :3.498
## NA's : 3 NA's :3 NA's :3
El resumen descriptivo de la base muestra que las viviendas presentan una amplia variabilidad en sus características físicas y de mercado. El área construida oscila aproximadamente entre 30 y 1745 unidades, con una mediana cercana a 123, lo que indica predominio de viviendas de tamaño medio, aunque existen algunos inmuebles considerablemente más grandes. El precio presenta una dispersión importante, con valores desde cerca de 58 hasta casi 2000, sugiriendo heterogeneidad en el mercado inmobiliario analizado. En cuanto a las características habitacionales, la mayoría de viviendas cuenta con entre 2 y 4 habitaciones y entre 2 y 4 baños, mientras que el número de parqueaderos suele concentrarse entre 1 y 2. La variable tipo muestra predominio de apartamentos sobre casas. Finalmente, se identifican algunos valores faltantes en varias variables, especialmente en parqueaderos y piso.
A partir del resumen descriptivo se identificó la presencia de valores faltantes en algunas variables de la base de datos. Dado que los valores ausentes pueden influir en los resultados de los análisis posteriores, se realizará una revisión de su magnitud y distribución dentro del conjunto de datos. Este análisis permitirá decidir el tratamiento más adecuado, ya sea mediante eliminación de registros incompletos, imputación de valores o uso de métodos que toleren datos faltantes, con el fin de garantizar la consistencia y confiabilidad de los resultados.
Para el conjunto de datos analizado, en la Tabla 4 se presenta el número de valores faltantes por variable. A partir de esta revisión se observa que varias variables contienen datos ausentes, aunque su presencia no es homogénea en toda la base. Algunas variables presentan muy pocos valores faltantes, mientras que en otras la ausencia de información es más notable. La identificación de estos registros incompletos resulta fundamental, ya que los datos faltantes pueden afectar los análisis estadísticos posteriores y, por tanto, es necesario evaluarlos antes de proceder con el modelamiento o la exploración multivariada.
faltantes <- data.frame(
Variable = names(colSums(is.na(vivienda))),
N_Faltantes = as.vector(colSums(is.na(vivienda)))
)
reactable(
faltantes,
columns = list(
Variable = colDef(name = "Nombre de la variable"),
N_Faltantes = colDef(name = "Número de valores faltantes")
)
)
Al analizar la distribución de los valores faltantes se identificó un patrón particular en tres registros específicos, los cuales presentan valores ausentes en variables clave del conjunto de datos (Ver Tabla 5). En particular, estos registros carecen de identificador válido (id) y presentan información incompleta en variables relevantes como el precio. Dado que representan una proporción muy pequeña del total de observaciones y que la ausencia de estas variables limita su utilidad analítica, se decidió eliminarlos de la base de datos. Esta decisión permite reducir la presencia de datos faltantes sin afectar de manera significativa la representatividad del conjunto, además de facilitar los análisis posteriores al trabajar con información consistente.
reactable(vivienda[is.na(vivienda$id), ], rownames = TRUE)
Posterior a la eliminación de esos registros faltantes, se verifica de nuevo cuantos valores faltantes existen en el conjunto de datos (Tabla 6).
vivienda <- vivienda[!is.na(vivienda$id), ]
faltantes <- data.frame(
Variable = names(colSums(is.na(vivienda))),
N_Faltantes = as.vector(colSums(is.na(vivienda)))
)
reactable(
faltantes,
columns = list(
Variable = colDef(name = "Nombre de la variable"),
N_Faltantes = colDef(name = "Número de valores faltantes")
)
)
Como resultado, se encontró que las únicas variables que aún presentan información faltante son piso y parqueaderos. No obstante, la magnitud de estos valores ausentes es considerablemente menor en comparación con la situación inicial, lo que indica que la depuración previa permitió mejorar la consistencia del conjunto de datos. En consecuencia, se procederá a analizar con mayor detalle estos valores faltantes restantes con el fin de definir la estrategia más adecuada para su tratamiento antes de continuar con la construcción de componentes principales, análisis de conglomerados y de correspondencia.
Para decidir el tratamiento de los valores faltantes en la variable parqueaderos se analizó su distribución por categorías. Se observó en la Tabla 8 que la ausencia de información no es aleatoria, sino que se concentra especialmente por estrato socioeconómico: en el estrato 3, el 52.9% de los registros presentan parqueaderos como NA, mientras que esta proporción disminuye en estratos más altos (22.9% en estrato 4, 8.3% en estrato 5 y 5.9% en estrato 6). Por tipo de inmueble, la proporción de NA es del 17.0% en apartamentos y del 22.8% en casas (Tabla 7).
t1 <- prop.table(table(is.na(vivienda$parqueaderos), vivienda$tipo), 2)
t1_red <- round(100 * t1, 1)
t1_df <- as.data.frame.matrix(t1_red)
t1_df$Estado <- rownames(t1_df)
rownames(t1_df) <- NULL
reactable(
t1_df,
columns = list(
Estado = colDef(name = "¿Parqueaderos es NA?"),
Apartamento = colDef(name = "Apartamento (%)"),
Casa = colDef(name = "Casa (%)")
)
)
t2 <- prop.table(table(is.na(vivienda$parqueaderos), vivienda$estrato), 2)
t2_red <- round(100 * t2, 1)
t2_df <- as.data.frame.matrix(t2_red)
t2_df$Estado <- rownames(t2_df)
rownames(t2_df) <- NULL
reactable(
t2_df,
columns = list(
Estado = colDef(name = "¿Parqueaderos es NA?"),
`3` = colDef(name = "Estrato 3 (%)"),
`4` = colDef(name = "Estrato 4 (%)"),
`5` = colDef(name = "Estrato 5 (%)"),
`6` = colDef(name = "Estrato 6 (%)")
)
)
Dado que en el conjunto de datos no se registran valores cero para parqueaderos y que el patrón de faltantes es coherente con viviendas que probablemente no disponen de estacionamiento (en especial en estratos bajos), se imputó el valor 0 para los casos con NA, interpretándolos como inmuebles sin parqueadero.
vivienda$parqueaderos <- as.numeric(as.character(vivienda$parqueaderos))
vivienda$parqueaderos[is.na(vivienda$parqueaderos)] <- 0
sum(is.na(vivienda$parqueaderos))
## [1] 0
En la variable piso se identificaron valores faltantes que debían ser tratados antes de continuar con el análisis. Dado que esta variable corresponde a una característica categórica del inmueble, no resultaba apropiado imputar valores numéricos promedio ni aplicar métodos de interpolación. En su lugar, se optó por imputar los valores faltantes mediante la moda, es decir, el valor más frecuente observado en los registros. Para mejorar la coherencia de la imputación, esta se realizó considerando primero agrupaciones de viviendas con características similares (según tipo de inmueble y zona), asignando el piso más frecuente dentro de cada grupo.
moda <- function(x){
x <- x[!is.na(x)]
if (length(x) == 0) return(NA)
names(sort(table(x), decreasing = TRUE))[1]
}
vivienda <- vivienda %>%
group_by(tipo, zona) %>%
mutate(piso = ifelse(is.na(piso), moda(piso), piso)) %>%
ungroup()
sum(is.na(vivienda$piso))
## [1] 0
Una vez realizada la depuración de la base de datos y el tratamiento de los valores faltantes, se obtuvo un conjunto de información consistente y adecuado para el análisis multivariado. Con la base depurada, se procederá a aplicar distintas técnicas de análisis exploratorio con el fin de identificar patrones, relaciones y estructuras presentes en los datos. En particular, se desarrollarán análisis de componentes principales, conglomerados y correspondencias, los cuales permitirán estudiar la variabilidad de las viviendas desde diferentes perspectivas y facilitar la interpretación conjunta de sus características.
Para la aplicación del análisis de componentes principales se seleccionaron únicamente las variables cuantitativas del conjunto de datos, dado que esta técnica se basa en la estructura de varianzas y covarianzas entre variables numéricas. En particular, se consideraron las variables relacionadas con características físicas y económicas de las viviendas, tales como área construida, precio, número de parqueaderos, baños y habitaciones, así como el estrato socioeconómico y las coordenadas geográficas. Las variables categóricas nominales no fueron incluidas en esta etapa debido a que sus códigos no representan magnitudes comparables y podrían distorsionar los resultados del análisis. Con esta selección se construyó el conjunto de datos sobre el cual se aplicó el análisis de componentes principales.
vivienda$estrato <- as.numeric(as.character(vivienda$estrato))
vivienda$banios <- as.numeric(as.character(vivienda$banios))
vivienda$habitaciones <- as.numeric(as.character(vivienda$habitaciones))
vivienda$parqueaderos <- as.numeric(as.character(vivienda$parqueaderos))
pca_data <- vivienda[, c("estrato", "preciom", "areaconst",
"parqueaderos", "banios", "habitaciones",
"longitud", "latitud")]
En la Figura 2, el análisis de componentes principales evidencia que la mayor parte de la variabilidad del conjunto de datos puede resumirse en pocas dimensiones. La primera componente principal (PC1) explica el 45.12% de la varianza total, mientras que la segunda (PC2) aporta un 18.78% adicional, alcanzando en conjunto un 63.90% de varianza explicada con las dos primeras componentes. Al incluir la tercera componente (PC3), la varianza acumulada asciende a 75.19%, y con cuatro componentes se llega a 83.87%. Estos resultados sugieren que es posible representar adecuadamente la estructura global de los datos utilizando entre dos y cuatro componentes principales, reduciendo la dimensionalidad sin perder una proporción importante de información.
pca_res <- prcomp(pca_data, center = TRUE, scale. = TRUE)
summary(pca_res)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 1.8998 1.2258 0.9506 0.83289 0.66053 0.65321 0.48970
## Proportion of Variance 0.4512 0.1878 0.1129 0.08671 0.05454 0.05334 0.02998
## Cumulative Proportion 0.4512 0.6390 0.7519 0.83865 0.89318 0.94652 0.97649
## PC8
## Standard deviation 0.43366
## Proportion of Variance 0.02351
## Cumulative Proportion 1.00000
El gráfico de sedimentación (scree plot), el la Figura 3. confirma los resultados obtenidos en el resumen numérico del análisis anterior. Se observa una caída pronunciada en la varianza explicada entre la primera y la segunda componente principal, seguida de una disminución más gradual en las componentes posteriores. Este patrón sugiere que las primeras componentes concentran la mayor parte de la información relevante del conjunto de datos. En particular, las dos primeras componentes explican cerca del 64% de la variabilidad total, mientras que a partir de la tercera componente la contribución marginal disminuye considerablemente. En consecuencia, el análisis puede centrarse principalmente en las primeras componentes, ya que permiten una representación reducida del sistema sin pérdida sustancial de información.
fviz_eig(pca_res, addlabels = TRUE, barfill = "steelblue", barcolor = "steelblue")
A partir de la Figura 4 que ilustran las cargas de los componentes principales se percibe:
El primer componente principal concentra principalmente información asociada al valor y tamaño del inmueble, ya que presenta cargas positivas altas en preciom (0.464), banios (0.443), areaconst (0.411) y parqueaderos (0.400), además de una contribución positiva de estrato (0.348). Esto sugiere que PC1 resume un gradiente donde valores altos corresponden a viviendas de mayor precio, mayor área construida y con mejores dotaciones (más baños y parqueaderos), características que suelen asociarse a estratos más altos. Por tanto, PC1 puede interpretarse como un eje de nivel socioeconómico y características de vivienda de mayor tamaño y valor.
El segundo componente principal esta dominado por cargas positivas en habitaciones (0.576) y por las coordenadas geográficas longitud (0.427) y latitud (0.377), mientras que estrato presenta una carga negativa marcada (-0.438). Este patrón indica que PC2 captura una combinación entre distribución espacial y configuración interna del inmueble (número de habitaciones), diferenciando zonas/ubicaciones específicas y, al mismo tiempo, contrastando estas características con el estrato. En consecuencia, PC2 puede interpretarse como un eje asociado a localización y distribución del espacio de habitaciones, con una oposición respecto al nivel de estrato.
Para los otros componentes, el PC3 esta influenciado por latitud (0.844), lo cual refuerza que parte de la variabilidad del conjunto está relacionada con la ubicación. Asimismo, PC4 está fuertemente determinada por longitud (-0.823), sugiriendo que las coordenadas geográficas contribuyen de manera importante a explicar diferencias entre viviendas en dimensiones específicas.
pca_res$rotation
## PC1 PC2 PC3 PC4 PC5
## estrato 0.3475716 -0.43782644 0.245420545 -0.08934508 0.43721104
## preciom 0.4643619 -0.03915898 0.217996847 -0.12221942 0.21085060
## areaconst 0.4111907 0.29817458 0.001360553 -0.04660611 0.12300943
## parqueaderos 0.3998506 -0.10637019 0.192727883 -0.33510245 -0.80765836
## banios 0.4434694 0.22226311 -0.105999384 0.04083449 0.20751612
## habitaciones 0.2493901 0.57630455 -0.349109009 0.25674156 -0.08438976
## longitud -0.2450610 0.42748996 0.099508516 -0.82320382 0.21394468
## latitud -0.1252530 0.37719543 0.843851485 0.34258703 -0.03143726
## PC6 PC7 PC8
## estrato -0.40896238 0.48479324 0.16081052
## preciom 0.26794552 -0.21780051 -0.74611295
## areaconst 0.67233490 0.27398506 0.44452988
## parqueaderos -0.14011568 0.04344879 0.07439762
## banios -0.36404799 -0.66605196 0.34901516
## habitaciones -0.35586700 0.44095890 -0.29946053
## longitud -0.14509140 0.05007879 -0.01729826
## latitud -0.09520807 -0.00223570 0.05026135
Con base en las cargas vistas en la Figura 4 estimadas para cada componente, se construyó el círculo de correlaciones (gráfico de variables del ACP) presente en la Figura 5, el cual permite visualizar simultáneamente la contribución de cada variable a las dos primeras componentes y las relaciones de asociación (dirección y cercanía angular) entre ellas.
fviz_pca_var(
pca_res,
col.var = "contrib", # colorea por contribución
gradient.cols = c("#FF7F00", "#034D94"),
repel = TRUE
)
A partir del gráfico se observa que preciom, areaconst y banios se proyectan fuertemente sobre la primera dimensión (Dim1), lo que refuerza la interpretación de esta componente como un eje asociado a viviendas de mayor tamaño y valor. Por su parte, habitaciones muestra una contribución importante sobre la segunda dimensión (Dim2). En contraste, longitud y latitud se ubican hacia el lado opuesto de Dim1, indicando que la variabilidad geográfica está capturando una dimensión diferente a la asociada con tamaño y valor. Además, la cercanía en dirección entre areaconst y banios sugiere una relación positiva entre ambas variables, mientras que la oposición entre variables de ubicación y las variables de tamaño y valor evidencia un contraste entre patrones espaciales y características físicas y económicas del inmueble.
En conjunto, el análisis de componentes principales permitió reducir la dimensionalidad del problema y sintetizar la información en unas pocas componentes que capturan la mayor parte de la variabilidad. A partir de esta representación, se procederá a realizar el análisis de conglomerados, con el fin de identificar grupos de viviendas con características similares y explorar la estructura de segmentación presente en los datos.
Con el fin de complementar el análisis exploratorio realizado previamente, se aplicará un análisis de conglomerados al conjunto de datos depurado. Esta técnica multivariada permite identificar grupos de observaciones con características similares, agrupando viviendas que presentan comportamientos parecidos en términos de sus atributos cuantitativos. A diferencia del análisis de componentes principales, cuyo objetivo es reducir la dimensionalidad del conjunto de variables, el análisis de conglomerados busca clasificar las observaciones en segmentos homogéneos, facilitando la interpretación de patrones estructurales presentes en los datos. Para este propósito, se emplearán las variables numéricas previamente seleccionadas y estandarizadas, con el fin de evitar que las diferencias de escala influyan en la formación de los grupos.
cluster_data <- pca_data
cluster_scaled <- scale(cluster_data)
En la Figura 6 se presenta el gráfico del método del codo, el cual muestra la evolución de la suma total de cuadrados dentro de los clusters (WSS) a medida que aumenta el número de grupos considerados. Se observa una disminución pronunciada del WSS entre uno y aproximadamente tres o cuatro clusters, lo que indica que en este rango la incorporación de nuevos grupos mejora significativamente la homogeneidad interna de los conglomerados. A partir de ese punto, la reducción del WSS se vuelve más gradual, sugiriendo que añadir más clusters aporta beneficios marginales en la explicación de la variabilidad. Este comportamiento indica la presencia de un “codo” alrededor de los 3 o 4 clusters, por lo que estos valores se consideran candidatos razonables para el número óptimo de grupos en el análisis.
fviz_nbclust(cluster_scaled, kmeans, method = "wss")
Con el fin de complementar la elección del número de conglomerados sugerida por el método del codo, se construyó un dendrograma mediante un algoritmo de agrupamiento jerárquico basado en distancias euclidianas y el método de Ward. Esta representación permite visualizar la estructura de agrupamiento de las observaciones y evaluar de manera gráfica posibles cortes que definan grupos homogéneos.
d <- dist(cluster_scaled)
hc<-hclust(d, method = "ward.D2")
plot(hc, labels = FALSE, hang = -1, main = "Dendrograma (Ward.D2)")
rect.hclust(hc, k = 4)
En la Figura 7 se presenta el dendrograma obtenido mediante agrupamiento jerárquico utilizando distancia euclidiana sobre los datos estandarizados y el método de enlace Ward.D2. La estructura del árbol muestra cómo las observaciones se van fusionando progresivamente, y se observan incrementos más marcados en la altura (“height”) en las últimas uniones, lo cual sugiere la existencia de grupos relativamente diferenciados. Al realizar un corte en k = 4 (rectángulos rojos), se obtiene una partición en cuatro conglomerados principales que captura una parte importante de la heterogeneidad del conjunto de datos. Este resultado es consistente con lo sugerido por el método del codo (Figura 6), donde a partir de 3–4 grupos la mejora en la homogeneidad interna comienza a ser marginal. Por tanto, se considera razonable continuar el análisis adoptando 4 clusters para la segmentación de las viviendas.
Una vez definido el número de conglomerados a partir del análisis previo mediante el gráfico de codo y el dendograma, se procedió a aplicar el algoritmo de k-means con el fin de obtener la partición final de las viviendas. Para facilitar la interpretación de los resultados, se construyó un gráfico de clusters, el cual permite visualizar la distribución de las observaciones y la separación entre los grupos identificados. Esta representación gráfica ayuda a evaluar la cohesión interna de los conglomerados y el grado de diferenciación entre ellos, proporcionando una aproximación visual a la estructura de segmentación presente en los datos.
set.seed(123)
km_res <- kmeans(cluster_scaled, centers = 4, nstart = 25)
fviz_cluster(
km_res,
data = cluster_scaled,
geom = "point",
ellipse.type = "convex",
main = "Grupos de viviendas (k-means, k = 4)"
)
En la Figura 8 se presenta la partición final obtenida mediante el algoritmo k-means con cuatro conglomerados. En el plano de las dos primeras componentes principales se observa que los grupos presentan una separación moderada, lo que indica que el algoritmo logró identificar patrones diferenciados en las características de las viviendas. Se aprecia que los clusters no se distribuyen aleatoriamente, sino que ocupan regiones específicas del espacio reducido, lo que sugiere la existencia de perfiles distintos de viviendas. Algunos grupos muestran mayor dispersión interna, lo cual indica heterogeneidad dentro del cluster, mientras que otros se presentan más compactos, reflejando mayor similitud entre sus observaciones. En conjunto, el resultado evidencia que el conjunto de datos puede segmentarse en cuatro grupos con características diferenciadas, lo que permitirá analizar posteriormente el perfil promedio de cada conglomerado y comprender mejor la estructura del mercado de viviendas representado en la base.
Con el fin de caracterizar los conglomerados obtenidos mediante k-means (k = 4), se calcularon los promedios de las variables numéricas dentro de cada grupo expuestos en la Figura 9.
clustered <- cbind(cluster_data, cluster = km_res$cluster)
aggregate(. ~ cluster, data = clustered, FUN = mean)
## cluster estrato preciom areaconst parqueaderos banios habitaciones
## 1 1 5.225410 428.5621 146.08822 1.6112863 3.139029 3.254729
## 2 2 3.939262 449.4328 302.57283 1.2060738 4.427332 6.438178
## 3 3 5.724638 1072.3877 389.50539 3.4836957 5.044384 4.291667
## 4 4 3.851330 208.8943 90.64589 0.7234861 2.010574 2.882089
## longitud latitud
## 1 -76.53733 3.407448
## 2 -76.52402 3.432445
## 3 -76.53829 3.402059
## 4 -76.51767 3.429148
El cluster 3 corresponde al segmento de viviendas de mayor nivel socioeconómico y valor, con el mayor estrato promedio (5.72), el precio promedio más alto (1072) y el mayor tamaño (área construida ≈389), además de presentar en promedio más parqueaderos (3.48) y más baños (5.04). El cluster 2 agrupa viviendas con áreas altas (≈303) y un número elevado de habitaciones (6.44) y baños (4.43), aunque con un estrato promedio menor (3.94) y un precio promedio intermedio (449), lo que sugiere inmuebles amplios pero no necesariamente los más costosos. El cluster 1 representa un perfil intermedio, con estrato medio-alto (5.23), precio promedio moderado (429) y área media (≈146), con dotaciones promedio de parqueaderos (1.61) y baños (3.14). Finalmente, el cluster 4 concentra viviendas de menor tamaño y valor relativo, con estrato promedio más bajo (3.85), el menor precio (209) y el área construida más pequeña (≈91), así como menores dotaciones en parqueaderos (0.72) y baños (2.01). En conjunto, estos resultados evidencian una segmentación del conjunto de viviendas en grupos que difieren principalmente por tamaño, dotación y nivel socioeconómico, además de presentar variaciones en la localización geográfica (longitud/latitud).
El análisis de correspondencias, es una técnica que permite estudiar la asociación entre variables categóricas y representar sus relaciones en un espacio reducido de dimensiones. A diferencia del análisis de componentes principales, que se centra en variables cuantitativas, y del análisis de conglomerados, que agrupa observaciones similares, el análisis de correspondencias busca identificar patrones de asociación entre categorías y facilitar su interpretación mediante representaciones gráficas. Para este propósito, se seleccionaron variables cualitativas del conjunto de datos que describen características de localización y tipología de las viviendas, construyendo tablas de contingencia sobre las cuales se desarrollará el análisis.
mca_data <- vivienda[, c("zona", "piso", "estrato", "tipo", "barrio")]
mca_data <- data.frame(lapply(mca_data, as.factor))
La Figura 10 presenta el gráfico de sedimentación (scree plot) del análisis de correspondencias múltiples. Se observa que la inercia explicada por cada dimensión es relativamente baja: la Dimensión 1 explica aproximadamente 0.7% y la Dimensión 2 alrededor de 0.6%, mientras que las dimensiones posteriores aportan porcentajes similares o menores (cercanos a 0.3–0.5%). Este comportamiento es esperado en el análisis de correspondencias multiple cuando se analizan varias variables categóricas con numerosas modalidades, ya que la variabilidad se distribuye entre muchas dimensiones.
res_mca <- MCA(mca_data, graph = FALSE)
fviz_screeplot(res_mca, addlabels = TRUE)
Dado que la inercia se distribuye entre un gran número de dimensiones y categorías, la interpretación del análisis de correspondencias múltiples se centra en el estudio del mapa factorial de categorías, el cual permite visualizar las asociaciones entre modalidades de las variables analizadas. Sin embargo, debido al elevado número de categorías presentes en el conjunto de datos, la representación completa del mapa resultaría difícil de interpretar por la saturación de elementos. Por esta razón, se optó por mostrar únicamente aquellas categorías que presentan mayor contribución a las dimensiones principales, ya que son las que explican en mayor medida la estructura de asociación observada y permiten una interpretación más clara de los patrones presentes en los datos.
fviz_mca_var(res_mca,
select.var = list(contrib = 30), # muestra top 30 categorías
col.var = "contrib",
gradient.cols = c("#FF7F00", "#034D94"),
repel = TRUE)
En la Figura 11 se presenta el mapa factorial del análisis de correspondencias múltiples considerando únicamente las categorías con mayor contribución a las dimensiones principales. Se observa que las modalidades se agrupan en regiones específicas del plano, lo que indica asociaciones entre ciertas características de las viviendas. Hacia la derecha del eje principal se ubican categorías relacionadas con la Zona Oriente y Zona Centro, junto con barrios como Ciudad Córdoba, Las Ceibas y Alfonso López, lo que sugiere una asociación territorial entre estas localizaciones. En contraste, hacia la izquierda se concentran categorías vinculadas con otras zonas y barrios, así como diferentes niveles de piso y estrato, indicando patrones diferenciados de localización y características habitacionales. Asimismo, algunas modalidades como Apartamento, ciertos estratos y niveles de piso aparecen próximas entre sí, lo que sugiere que tienden a presentarse conjuntamente dentro del conjunto de datos. En general, el mapa factorial permite identificar relaciones entre categorías que no serían evidentes mediante análisis univariados, evidenciando la existencia de estructuras espaciales y tipológicas en la distribución de las viviendas.
A partir del análisis exploratorio multivariado realizado sobre el conjunto de datos de viviendas, se pueden destacar las siguientes conclusiones principales:
Enlaces consultados:
library(DT)
library(reactable)
library(reactablefmtr)
library(paqueteMODELOS)
library(htmltools)
library(dplyr)
library(factoextra)
library(FactoMineR)