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.
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.
Para la visualización de los resultados se presentas los gráficos, mapas y otros recursos visuales para comunicar los hallazgos de manera clara y efectiva a la dirección de la empresa.
La Tabla 1 presenta la descripción de las variables que contiene el conjunto de datos que dispone la empresa, que se obtuvieron de la página OXL mediante procedimiento webscraping y contenidos en paqueteMOD.
| Nombre de la variable | Descripción de la variable | Clasificación |
|---|---|---|
| id | Código de identificación único asignado a cada inmueble o registro. | Cualitativa nominal (identificador), aunque esté almacenada como numérica; no debe analizarse como variable cuantitativa |
| zona | Zona geográfica de la ciudad donde se localiza el inmueble. | Cualitativa nominal politómica |
| piso | Piso o nivel en el que se ubica el inmueble. En las casas puede no aplicar. | Cualitativa ordinal |
| estrato | Estrato socioeconómico del inmueble, usualmente categorizado de 1 a 6 en Colombia. | Cualitativa ordinal |
| preciom | Precio del inmueble, expresado en millones de pesos colombianos. | Cuantitativa continua |
| areaconst | Área construida del inmueble, generalmente medida en metros cuadrados. | Cuantitativa continua |
| parqueaderos | Cantidad de espacios de parqueadero disponibles en el inmueble. | Cuantitativa discreta |
| banios | Número de baños disponibles en la vivienda. | Cuantitativa discreta |
| habitaciones | Número de habitaciones o alcobas del inmueble. | Cuantitativa discreta |
| tipo | Clase de inmueble residencial, por ejemplo, Casa o Apartamento. | Cualitativa binaria. |
| barrio | Barrio en el cual se encuentra ubicado el inmueble. | Cualitativa nominal politómica |
| longitud | Coordenada geográfica que indica la posición este-oeste del inmueble. | Cuantitativa continua |
| latitud | Coordenada geográfica que indica la posición norte-sur del inmueble. | Cuantitativa continua |
Tabla 1. Descripción de las variables incluidas en el Dataset de Vivienda
El Mapa 1 presenta la distribución espacial de la oferta de vivienda en Cali, diferenciada según el precio publicado de cada inmueble. La visualización se elaboró con la librería Leaflet, utilizando como capa cartográfica los recursos de OpenStreetMap bajo licencia Open Database License (ODbL).
De manera descriptiva, se observa una mayor concentración de inmuebles con precios elevados en las zonas sur y oeste de la ciudad, mientras que las viviendas ubicadas en las zonas oriente y nororiente tienden a registrar precios relativamente más bajos. No obstante, este patrón espacial no debe interpretarse como una relación causal ni como evidencia de que la localización determine por sí sola el valor de los inmuebles.
El precio publicado también puede estar asociado con características estructurales de la vivienda, como el área construida, el número de habitaciones y baños, el tipo de inmueble y el estrato socioeconómico. Por tanto, el mapa constituye una aproximación exploratoria a la distribución territorial de los precios, que será complementada en el informe mediante análisis multivariados de las características físicas, socioeconómicas y espaciales de la oferta inmobiliaria.
library(leaflet)
library(dplyr)
vivienda_mapa <- vivienda |>
mutate(
latitud = as.numeric(latitud),
longitud = as.numeric(longitud),
preciom = as.numeric(preciom)
) |>
filter(
!is.na(latitud),
!is.na(longitud),
!is.na(preciom),
latitud >= -90,
latitud <= 90,
longitud >= -180,
longitud <= 180,
preciom > 0
) |>
as.data.frame()
pal_precio <- colorNumeric(
palette = "YlOrRd",
domain = vivienda_mapa$preciom,
na.color = "transparent"
)
mapa_prueba <- leaflet() |>
addTiles() |>
setView(
lng = -76.5320,
lat = 3.4516,
zoom = 12
) |>
addCircleMarkers(
data = vivienda_mapa,
lng = ~longitud,
lat = ~latitud,
radius = 5,
color = "#4A4A4A",
weight = 1,
fillColor = ~pal_precio(preciom),
fillOpacity = 0.80
) |>
addLegend(
position = "bottomright",
pal = pal_precio,
values = vivienda_mapa$preciom,
title = "Precio (millones COP)"
)
mapa_pruebaMapa 1. Distribución de los inmuebles en la ciudad, caracterizados por el precio
Este conjunto de datos tiene 8322 registros y 13 variables y se describen como lo muestra la Tabla 2 recopilando atributos físicos, socioeconómicos y espaciales de cada inmueble.
library(dplyr)
library(purrr)
library(tibble)
library(knitr)
library(kableExtra)
library(tidyr)
library(ggplot2)
library(FactoMineR)
library(factoextra)
library(cluster)
library(NbClust)
library(viridis)
library(scales)
tabla_descripcion <- tibble(
Variable = names(vivienda),
Tipo_de_dato = map_chr(
vivienda,
~ class(.x)[1]
),
Registros_no_nulos = map_int(
vivienda,
~ sum(!is.na(.x))
),
Datos_faltantes = map_int(
vivienda,
~ sum(is.na(.x))
),
Porcentaje_faltantes = map_dbl(
vivienda,
~ round(mean(is.na(.x)) * 100, 2)
),
Valores_unicos = map_int(
vivienda,
~ n_distinct(.x, na.rm = TRUE)
),
Ejemplo_de_valores = map_chr(
vivienda,
~ paste(
head(unique(na.omit(.x)), 3),
collapse = ", "
)
)
)
tabla_descripcion |>
kable(
caption = paste0(
"<span style='font-size: 18px; font-weight: 600; color: #1f4e79;'>",
"</span>"
),
escape = FALSE,
col.names = c(
"Variable",
"Tipo de dato",
"Registros no nulos",
"Datos faltantes",
"% faltantes",
"Valores únicos",
"Ejemplo de valores"
),
align = c("l", "l", "c", "c", "c", "c", "l")
) |>
kable_styling(
bootstrap_options = c(
"striped",
"hover",
"condensed",
"responsive"
),
full_width = FALSE,
position = "center"
) |>
row_spec(
0,
bold = TRUE,
color = "white",
background = "#1f4e79"
)| Variable | Tipo de dato | Registros no nulos | Datos faltantes | % faltantes | Valores únicos | Ejemplo de valores |
|---|---|---|---|---|---|---|
| id | integer | 8319 | 3 | 0.04 | 8319 | 1147, 1169, 1350 |
| zona | character | 8319 | 3 | 0.04 | 5 | Zona Oriente, Zona Sur, Zona Norte |
| piso | integer | 5684 | 2638 | 31.70 | 12 | 2, 1, 3 |
| estrato | integer | 8319 | 3 | 0.04 | 4 | 3, 4, 5 |
| preciom | integer | 8320 | 2 | 0.02 | 539 | 250, 320, 350 |
| areaconst | numeric | 8319 | 3 | 0.04 | 652 | 70, 120, 220 |
| parqueaderos | integer | 6717 | 1605 | 19.29 | 10 | 1, 2, 3 |
| banios | integer | 8319 | 3 | 0.04 | 11 | 3, 2, 5 |
| habitaciones | integer | 8319 | 3 | 0.04 | 11 | 6, 3, 4 |
| tipo | character | 8319 | 3 | 0.04 | 2 | Casa, Apartamento |
| barrio | character | 8319 | 3 | 0.04 | 436 | 20 de julio, 3 de julio, acopi |
| longitud | numeric | 8319 | 3 | 0.04 | 2928 | -76.51168, -76.51237, -76.51537 |
| latitud | numeric | 8319 | 3 | 0.04 | 3679 | 3.43382, 3.43369, 3.43566 |
Tabla 2. Descripción general de las variables de la base de viviendas
La Tabla 2 evidencia una limitación relevante en la calidad de la
información: las variables piso y parqueaderos
presentan un número considerable de valores faltantes, con 2.638 y 1.605
registros ausentes, respectivamente. Dado que ambas características
pueden incidir en la valoración y diferenciación de las viviendas
—especialmente al comparar casas y apartamentos—, antes de avanzar con
la depuración definitiva y los análisis multivariados se realiza un
análisis descriptivo de sus patrones de ausencia. Este análisis tiene
como propósito establecer si los valores faltantes podían atribuirse a
un mecanismo que hiciera técnicamente viable una estrategia de
imputación y, en consecuencia, determinar si las variables podían
recuperarse e incorporarse de manera confiable en los análisis
posteriores.
pisoSegún la documentación del paquete paqueteMODELOS, la variable “piso” corresponde al piso en el que está ubicada la vivienda . No obstante, dicha variable presenta 2.638 valores faltantes (31,7%) y una distribución heterogénea entre casas y apartamentos (Ver Tabla 3). En particular, entre las casas con información observada predominan los valores 2 y 3 (Ver Gráfico 1), lo cual desaconsejaría la imputación del valor 1 a las casas sin información (idea inicial, asumiendo que las casas están en el primer piso). Dada la magnitud y heterogeneidad de los datos faltantes, la variable se excluiría de la especificación principal para evitar introducir supuestos de imputación no verificables.
library(dplyr)
library(ggplot2)
library(forcats)
vivienda %>%
mutate(
piso_grafico = case_when(
is.na(piso) ~ "Sin información",
TRUE ~ as.character(piso)
),
piso_grafico = factor(
piso_grafico,
levels = c(
as.character(sort(unique(na.omit(piso)))),
"Sin información"
)
)
) %>%
ggplot(aes(x = piso_grafico)) +
geom_bar(
fill = "#457B9D",
color = "white",
width = 0.8
) +
geom_text(
stat = "count",
aes(label = after_stat(count)),
vjust = -0.35,
size = 3.5
) +
scale_y_continuous(
expand = expansion(mult = c(0, 0.10)),
labels = scales::comma
) +
labs(
title = "Distribución del número de piso",
subtitle = "Incluye la categoría de registros sin información",
x = "Piso",
y = "Número de viviendas"
) +
theme_minimal()
Gráfico 1. Distribución Frecuencia de la variable piso
vivienda |>
mutate(
piso_faltante = ifelse(
is.na(piso),
"No informado",
"Informado"
)
) |>
count(tipo, piso_faltante) |>
group_by(tipo) |>
mutate(
porcentaje = round(n / sum(n) * 100, 2)
) |>
ungroup()Tabla 3. Descripción de la variable Piso por Tipo de Vivienda (Informado = Con Dato; No Informado = NA)
El análisis también se realizó para los faltantes de esta variable por tipo (Casa, Apartamento); zona (norte, sur, etc.), estrato y barrio. En todos los casos no se encontraron patrones que permitieran justificar técnicamente la imputación de los datos faltantes mediante alguno de los métodos conocidos. Por lo anterior, se revisó y discutió su inclusión en el análisis inferencial únicamente mediante análisis de sensibilidad sobre observaciones completas y, de forma complementaria.
parqueaderoLa variable parqueadero presentó 1605 valores faltantes
(19,29%). Los anuncios sin información de parqueaderos difieren
sistemáticamente de aquellos con información disponible: presentan un
precio mediano de 180 millones frente a 355 millones, un área mediana de
90 m² frente a 130 m², una mediana de dos baños frente a tres y un
estrato mediano de cuatro frente a cinco (Ver Tabla 4).
library(dplyr)
library(ggplot2)
vivienda %>%
mutate(
parqueaderos_grafico = case_when(
is.na(parqueaderos) ~ "Sin información",
TRUE ~ as.character(parqueaderos)
),
parqueaderos_grafico = factor(
parqueaderos_grafico,
levels = c(
as.character(
sort(unique(na.omit(parqueaderos)))
),
"Sin información"
)
)
) %>%
ggplot(aes(x = parqueaderos_grafico)) +
geom_bar(
fill = "#2A9D8F",
color = "white",
width = 0.8
) +
geom_text(
stat = "count",
aes(label = after_stat(count)),
vjust = -0.35,
size = 3.5
) +
scale_y_continuous(
labels = scales::comma,
expand = expansion(mult = c(0, 0.10))
) +
labs(
title = "Distribución del número de parqueaderos",
subtitle = "Incluye los registros sin información de parqueaderos",
x = "Número de parqueaderos",
y = "Frecuencia de viviendas"
) +
theme_minimal()
Gráfico 2. Distribución Frecuencia de la variable
parqueadero
library(dplyr)
vivienda %>%
mutate(parq_faltante = is.na(parqueaderos)) %>%
group_by(parq_faltante) %>%
summarise(
n = n(),
prop_casas = mean(tipo == "Casa", na.rm = TRUE),
precio_mediano = median(preciom, na.rm = TRUE),
area_mediana = median(areaconst, na.rm = TRUE),
habitaciones_mediana = median(habitaciones, na.rm = TRUE),
banios_mediana = median(banios, na.rm = TRUE),
estrato_mediano = median(estrato, na.rm = TRUE),
.groups = "drop"
)Tabla 4.Distribución frecuencia de Parqueadero Vs. otras características de la vivieda (valores medianos)
Adicionalmente, podemos mencionar que las viviendas tipo casa
representan 45,8% de los registros con información faltante y 37,0% de
los registros con información observada. Dado que no se observan valores
cero (aunque que cero parqueaderos es una categoría factible) no es
posible distinguir entre ausencia de parqueadero y falta de reporte. Por
ello, no se realizó imputación determinística; la variable
parqueadero se excluye de la especificación principal y se
examina en análisis de sensibilidad bajo escenarios alternativos. Sin
embargo, sigue haciendo parte del conjunto de datos.
parqueadero?El Mapa 2 presenta la distribución espacial de la calidad de la información de la variable parqueaderos en la oferta inmobiliaria de Cali. Los puntos en rojo corresponden a inmuebles sin dato reportado sobre el número de parqueaderos, mientras que los puntos grises representan registros con información disponible. La visualización permite identificar si la ausencia de información se distribuye de manera aparentemente aleatoria o si, por el contrario, se concentra en determinadas zonas de la ciudad.
Se observa que los puntos rojos forman agrupamientos territoriales (pequeños en el sur-oriente y nor-oriente), y el resto de los puntos se distribuye por toda la ciudad. En principio, esto sugiere que la falta de reporte no está relacionada con características observables de la ubicación o del tipo de oferta, y puede ser completamente aleatoria. No obstante, el mapa es únicamente descriptivo: para confirmar formalmente la existencia de agrupamiento espacial se requeriría complementar el análisis con una medida de autocorrelación espacial, como el estadístico global de Moran (el cual no hace parte de este análisis).
ggplot(vivienda_geo, aes(x = longitud, y = latitud)) +
geom_point(
data = filter(vivienda_geo, parq_faltante == 0),
color = "grey80",
alpha = 0.15,
size = 0.7
) +
geom_point(
data = filter(vivienda_geo, parq_faltante == 1),
color = "red3",
alpha = 0.60,
size = 1.0
) +
coord_equal() +
labs(
title = "Distribución espacial de faltantes en parqueaderos",
subtitle = "Rojo: no se reportó el número de parqueaderos",
x = "Longitud",
y = "Latitud"
) +
theme_minimal()
Mapa 2. Distribución de la ausencia de valores en la variable
parqueadero
Las Tablas 5 y 6 muestran que de los 8322 registros, hay 3 datos con valores faltantes (NaN) y una fila duplicada, también se evidencia que hay 890 ubicaciones repetidas (posiblemente viviendas en el mismo edificio), con 3298 anuncios en estas ublicaciones.
vivienda %>%
summarise(
n_registros = n(),
id_unicos = n_distinct(id),
id_faltantes = sum(is.na(id)),
filas_duplicadas = sum(duplicated(.))
)Tabla 5. Datos faltantes y duplicados
vivienda %>%
count(longitud, latitud, sort = TRUE) %>%
filter(n > 1) %>%
summarise(
ubicaciones_repetidas = n(),
anuncios_en_ubicaciones_repetidas = sum(n)
)Tabla 6. Ubicaciones repetidas (edificios) y anuncios en ubicaciones repetidas
Los Gráficos 3 a 7 permiten caracterizar la composición de la oferta inmobiliaria de Cali según tipo de vivienda, zona y estrato socioeconómico. El Gráfico 3 muestra que el 61.3% de la oferta corresponde a apartamentos y el 38.7% restante a casas, el Gráfico 4, por su parte muestra que la mayor cantidad de anuncios están en la zona sur (4726) y el zona norte (1920).
vivienda %>%
count(tipo) %>%
mutate(
porcentaje = n / sum(n)
) %>%
ggplot(aes(x = tipo, y = n, fill = tipo)) +
geom_col(width = 0.65, show.legend = FALSE) +
geom_text(
aes(label = percent(porcentaje, accuracy = 0.1)),
vjust = -0.4,
fontface = "bold"
) +
scale_y_continuous(labels = comma) +
scale_fill_manual(values = c(
"Apartamento" = "#457B9D",
"Casa" = "#E76F51"
)) +
labs(
title = "Distribución de la oferta por tipo de vivienda",
x = NULL,
y = "Número de anuncios"
)
Gráfico 3. Distribución de la oferta por tipo de vivienda
vivienda %>%
count(zona, sort = TRUE) %>%
ggplot(aes(x = reorder(zona, n), y = n, fill = zona)) +
geom_col(show.legend = FALSE) +
geom_text(
aes(label = comma(n)),
hjust = -0.1,
size = 3.5
) +
coord_flip() +
scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.10))) +
labs(
title = "Número de anuncios por zona",
x = NULL,
y = "Número de anuncios"
)
Gráfico 4. Número de anuncios por zona
El Gráfico 5 muestra que la mayor proporción de anuncios se concentran en los estratos 5 y 4 de la ciudad, seguidos por el estrato 6. Así mismo, el Gráfico 6 muestra la distribución del tipo de vivienda por estratos (apartamentos y casas es muy simiilar entre los estratos 4, 5, y 6; mientras que en el estrato 3 es más alta la oferta de casas que de apartamentos.
vivienda %>%
count(estrato) %>%
mutate(
estrato = factor(estrato, levels = sort(unique(estrato)))
) %>%
ggplot(aes(x = estrato, y = n, fill = estrato)) +
geom_col(show.legend = FALSE, width = 0.7) +
geom_text(
aes(label = comma(n)),
vjust = -0.4
) +
scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.10))) +
scale_fill_viridis_d() +
labs(
title = "Distribución de anuncios por estrato socioeconómico",
x = "Estrato",
y = "Número de anuncios"
)
Gráfico 5. Distribución de los anuncios por estrato
socioeconómico
tabla_tipo_estrato <- vivienda %>%
count(tipo, estrato) %>%
group_by(tipo) %>%
mutate(
porcentaje = n / sum(n)
) %>%
ungroup()
ggplot(
tabla_tipo_estrato,
aes(x = estrato, y = porcentaje, fill = tipo)
) +
geom_col(position = "dodge") +
scale_y_continuous(labels = percent) +
scale_fill_manual(values = c(
"Apartamento" = "#457B9D",
"Casa" = "#E76F51"
)) +
labs(
title = "Composición por estrato según tipo de vivienda",
x = "Estrato",
y = "Proporción dentro de cada tipo",
fill = "Tipo"
)
Gráfico 6. Distribución por estrato y tipo de vivienda
El Gráfico 7 muestyra que los principales barrios donde se reportan los anuncios son Valle del Lili, Ciudad Jardín, Pance, La Flora y Santa Teresita, coincidiendo necesariamente con las zonas de la ciudad a la que pertenecen.
top_barrios <- vivienda %>%
count(barrio, sort = TRUE) %>%
slice_head(n = 20)
ggplot(
top_barrios,
aes(x = reorder(barrio, n), y = n)
) +
geom_col(fill = "#457B9D") +
geom_text(
aes(label = comma(n)),
hjust = -0.1,
size = 3.3
) +
coord_flip() +
scale_y_continuous(
labels = comma,
expand = expansion(mult = c(0, 0.10))
) +
labs(
title = "Veinte barrios con mayor número de anuncios",
x = NULL,
y = "Número de anuncios"
)
Gráfico 7. Principales barrios en los que ubican los
anuncios
La Tabla 7 muestra las características numéricas de las 8320
viviendas. El precio publicado (preciom) presenta una media
de 433,89 millones de pesos y una mediana de 330 millones, con un rango
entre 58 y 1.999 millones; la diferencia entre media y mediana, junto
con el máximo elevado, sugiere una distribución asimétrica hacia valores
altos, asociada a una proporción reducida de inmuebles de alto
valor.
El 50% central de los precios se ubica entre 220 y 540 millones, para un rango intercuartílico de 320 millones. De manera similar, el área construida tiene una media de 174,93 m² y una mediana de 123 m², con valores entre 30 y 1.745 m²; el 50% de las viviendas se concentra entre 80 y 229 m², lo que también evidencia heterogeneidad y presencia de inmuebles de gran tamaño.
resumen_numerico <- vivienda %>%
summarise(
across(
c(preciom, areaconst, banios, habitaciones),
list(
n = ~ sum(!is.na(.)),
media = ~ mean(., na.rm = TRUE),
de = ~ sd(., na.rm = TRUE),
minimo = ~ min(., na.rm = TRUE),
q1 = ~ quantile(., 0.25, na.rm = TRUE),
mediana = ~ median(., na.rm = TRUE),
q3 = ~ quantile(., 0.75, na.rm = TRUE),
maximo = ~ max(., na.rm = TRUE),
iqr = ~ IQR(., na.rm = TRUE)
),
.names = "{.col}_{.fn}"
)
) %>%
pivot_longer(
everything(),
names_to = c("variable", "estadistico"),
names_sep = "_",
values_to = "valor"
) %>%
pivot_wider(
names_from = estadistico,
values_from = valor
)
knitr::kable(
resumen_numerico,
digits = 2,
caption = ""
)| variable | n | media | de | minimo | q1 | mediana | q3 | maximo | iqr |
|---|---|---|---|---|---|---|---|---|---|
| preciom | 8320 | 433.89 | 328.65 | 58 | 220 | 330 | 540 | 1999 | 320 |
| areaconst | 8319 | 174.93 | 142.96 | 30 | 80 | 123 | 229 | 1745 | 149 |
| banios | 8319 | 3.11 | 1.43 | 0 | 2 | 3 | 4 | 10 | 2 |
| habitaciones | 8319 | 3.61 | 1.46 | 0 | 3 | 3 | 4 | 10 | 1 |
Tabla 7. Estadísticas Descriptivas de las variables numéricas
En promedio, las propiedades cuentan con 3,11 baños y 3,61 habitaciones; sin embargo, sus respectivas medianas son de 3 baños y 3 habitaciones, lo cual indica que la oferta típica se concentra alrededor de esas características. Los valores mínimos de cero baños y cero habitaciones deben revisarse como posibles casos atípicos o inconsistencias de registro, antes de utilizarlos en análisis posteriores. Nota: con respecto a cero habiaciones (66 casos) se puede asumir apartaestudios de un sólo ambiente. Sin embargo, con respecto a cero baños (45 casos) no es fácil de justificar una vivienda sin este servicio y se asume para este análisis como un error de registro y deberían ser eliminados.
Debido a la presencia de extremos y al sesgo positivo aparente en precio y área, la mediana y el rango intercuartílico constituyen medidas especialmente informativas para describir estas variables.
ggplot(vivienda, aes(x = preciom)) +
geom_histogram(
bins = 60,
fill = "#457B9D",
color = "white",
alpha = 0.9
) +
scale_x_continuous(labels = comma) +
labs(
title = "Distribución del precio de las viviendas",
subtitle = "Precio expresado en millones de pesos",
x = "Precio (millones de pesos)",
y = "Frecuencia"
)
Gráfico 8. Distribución de frecuencias de la variable
precio
ggplot(vivienda, aes(x = log_preciom)) +
geom_histogram(
bins = 60,
fill = "#457B9D",
color = "white",
alpha = 0.9
) +
labs(
title = "Distribución del logaritmo del precio",
x = "log(1 + precio en millones)",
y = "Frecuencia"
)
Gráfico 9. Distribución de frecuencias de la variable
log(precio)
Los Gráficos 8 y 9 muestran la distribución del precio de las viviendas. Mientras que en la variable original (preciom), la distribución muestra un sesgo hacia la derecha, al transforma en su logaritmo, encontramos una distribución más uniforme y cercana a la normal, aunque sin pruabas estadísticas, no podemos afirmarlo.
ggplot(vivienda, aes(x = areaconst)) +
geom_histogram(
bins = 60,
fill = "#2A9D8F",
color = "white",
alpha = 0.9
) +
scale_x_continuous(labels = comma) +
labs(
title = "Distribución del área construida",
x = "Área construida (m²)",
y = "Frecuencia"
)
Gráfico 10. Distribución de la variable Área Construida (en
metros^2)
Los Gráficos 11 y 12 muestran la distribución de las variables baños y habitaciones. La mayor proporción de viviendas tienen 3 baños, seguidos de 4 y 2; y por otro lado, la mayor frecuencia de habitaciones es 2, seguido de 3 y 4, llamando la atención casos extremos de viviendas con 10 habitaciones y en el otro extremos viviendas con cero habitaciones (posiblemente apartaestudios).
ggplot(vivienda, aes(x = factor(habitaciones))) +
geom_bar(fill = "#6A4C93", width = 0.75) +
labs(
title = "Número de habitaciones por vivienda",
x = "Número de habitaciones",
y = "Número de anuncios"
)
Gráfico 11. Distribución de la variable Número de
habitaciones
ggplot(vivienda, aes(x = factor(banios))) +
geom_bar(fill = "#F4A261", width = 0.75) +
labs(
title = "Número de baños por vivienda",
x = "Número de baños",
y = "Número de anuncios"
)
Gráfico 12. Distribución de la variable Número de
habitaciones
La Tabla 8 muestra las observaciones con los precios publicados más
altos del set de datos y, por tanto, identifica potenciales valores
extremos en la variable preciom. Los inmuebles listados
tienen precios entre 1.850 y 1.999 millones de pesos, muy por encima de
la mediana de 330 millones y del tercer cuartil de 540 millones; bajo el
criterio de \(Q_3 + 1{,}5 \times IQR\),
cuyo límite superior es 1.020 millones, todos estos registros serían
clasificados como atípicos superiores.
Sin embargo, al revisar sus características, los valores parecen en gran medida plausibles: predominan casas ubicadas en las zonas sur y oeste, en estratos 5 y 6, y en barrios asociados con segmentos de alto valor como Pance, Ciudad Jardín, Aguacatal, Santa Rita, San Antonio, Normandía y Parcelaciones Pance. Además, estas viviendas suelen presentar áreas construidas amplias —entre 261 y 1.092 m²— y un número elevado de baños y habitaciones, características coherentes con inmuebles residenciales de lujo.
Por lo tanto, la tabla no evidencia necesariamente errores de digitación, sino un segmento minoritario y que podríamos categorizar como premium de la oferta inmobiliaria; Por lo tanto, estos registros se conservan, se emplean transformaciones como \(\log(\text{precio})\) (Ver Gráfcio 13) en análisis posteriores para reducir su influencia sobre estimaciones y algoritmos sensibles a extremos.
detectar_atipicos_iqr <- function(datos, variable) {
q1 <- quantile(datos[[variable]], 0.25, na.rm = TRUE)
q3 <- quantile(datos[[variable]], 0.75, na.rm = TRUE)
iqr <- q3 - q1
datos %>%
filter(
.data[[variable]] < q1 - 1.5 * iqr |
.data[[variable]] > q3 + 1.5 * iqr
)
}
atipicos_precio <- detectar_atipicos_iqr(vivienda, "preciom")
atipicos_precio %>%
select(
id, tipo, zona, estrato, barrio,
preciom, areaconst, banios, habitaciones
) %>%
arrange(desc(preciom)) %>%
slice_head(n = 20)Tabla 8. Identificación de valores extremos variable precio y características de las viviendas
Precio por tipo de vivienda
ggplot(
vivienda,
aes(x = tipo, y = log_preciom, fill = tipo)
) +
geom_boxplot(
outlier.alpha = 0.15,
outlier.size = 0.7,
show.legend = FALSE
) +
scale_fill_manual(values = c(
"Apartamento" = "#457B9D",
"Casa" = "#E76F51"
)) +
labs(
title = "Precio de vivienda según tipo de inmueble",
x = NULL,
y = "log(1 + precio en millones)"
)
Gráfico 13. Boxplot de la variable preciom diferenciado por tipo
(Apartamento o Casa)
La Tabla 9 evidencia diferencias marcadas entre apartamentos y casas dentro de la oferta inmobiliaria analizada. Los apartamentos constituyen la categoría más frecuente, con 5100 registros, frente a 3219 casas; sin embargo, las casas presentan valores y dimensiones considerablemente mayores (obviamente por su naturaleza).
El precio mediano de una casa es de 430 millones de pesos, mientras que el de un apartamento es de 279 millones, una diferencia de 151 millones. Asimismo, el valor mediano de los precios de las casas se ubica entre 300 y 670 millones, frente a un intervalo de 175 a 430 millones para los apartamentos, lo que indica una mayor dispersión y un nivel de precios más alto en las casas. La diferencia también se refleja en el área construida mediana: 240 m² para las casas y 90 m² para los apartamentos. Este análisis se complementa con el Gráfico 14.
vivienda %>%
group_by(tipo) %>%
summarise(
n = n(),
precio_mediano = median(preciom, na.rm = TRUE),
precio_q1 = quantile(preciom, 0.25, na.rm = TRUE),
precio_q3 = quantile(preciom, 0.75, na.rm = TRUE),
area_mediana = median(areaconst, na.rm = TRUE),
.groups = "drop"
)Tabla 9. Estadísticas de tendencia central del precio, discriminando entre tipo de vivienda
Precio por estrato y zona
ggplot(
vivienda,
aes(x = zona, y = log_preciom, fill = zona)
) +
geom_boxplot(
outlier.alpha = 0.10,
show.legend = FALSE
) +
coord_flip() +
labs(
title = "Distribución del precio por zona",
x = NULL,
y = "log(1 + precio en millones)"
)
Gráfico 14. Boxplot del precio de la vivienda discriminado por
zonas
Con respecto a las variables preciomy área construida
areconst, El Gráfico 15 evidencia una relación positiva
entre el área construida y el precio publicado de las viviendas: los
inmuebles de mayor tamaño se ofrecen a precios más altos. Esta relación
se observa tanto para apartamentos como para casas, aunque presenta
diferencias según el tipo de vivienda.
Los apartamentos se concentran principalmente en áreas pequeñas y medias y muestran un incremento pronunciado del precio a medida que aumenta el área, mientras que las casas presentan una trayectoria creciente más sostenida y concentran los mayores precios en superficies amplias.
ggplot(
vivienda,
aes(x = areaconst, y = preciom, color = tipo)
) +
geom_point(alpha = 0.25, size = 1) +
geom_smooth(
method = "loess",
se = FALSE,
linewidth = 1
) +
scale_x_log10(labels = comma) +
scale_y_log10(labels = comma) +
scale_color_manual(values = c(
"Apartamento" = "#457B9D",
"Casa" = "#E76F51"
)) +
labs(
title = "",
subtitle = "Escalas logarítmicas para reducir la influencia visual de extremos",
x = "Área construida (m², escala logarítmica)",
y = "Precio (millones, escala logarítmica)",
color = "Tipo"
)
Gráfico 15. Relación entre área construida y precio
La dispersión observada para inmuebles con áreas similares indica que el área construida no explica por sí sola la variación de los precios; la ubicación, el estrato socioeconómico, el tipo de inmueble y sus características estructurales también constituyen factores relevantes. Dado que ambos ejes están en escala logarítmica, el gráfico permite visualizar de manera más equilibrada la distribución de viviendas y reduce la influencia visual de los valores extremos.
Los Gráficos 16 y 17 refuerzan la idea descrita anteriormente. A excpeción del caso de cero baños, se observa una relación positiva entre el número de baños y el precio del inmueble hasta el caso de baños=7, donde el incremento marginal a partir de este punto no parece incidir más en el precio. Algo similiar puede observarse en el caso de las habitaciones, aunque no tiene la misma distribución y es ascendente hasta viviendas con cinco habitaciones.
ggplot(
vivienda,
aes(x = factor(banios), y = log_preciom)
) +
geom_boxplot(
fill = "#F4A261",
outlier.alpha = 0.10
) +
labs(
title = "Precio según número de baños",
x = "Número de baños",
y = "log(1 + precio en millones)"
)
Gráfico 16. Relación entre número de baño y log(precio)
ggplot(
vivienda,
aes(x = factor(habitaciones), y = log_preciom)
) +
geom_boxplot(
fill = "#6A4C93",
outlier.alpha = 0.10
) +
labs(
title = "Precio según número de habitaciones",
x = "Número de habitaciones",
y = "log(1 + precio en millones)"
)
Gráfico 17. Relación entre número de habitaciones y
log(precio)
La matriz de correlaciones (Gráficos 18A y 18B) evidencia asociaciones positivas entre casi todas las características físicas y socioeconómicas de los inmuebles. Las viviendas con mayor área construida, más baños y mayor estrato tienden a presentar precios publicados más altos, tal y como observamos en el análisis gráfico.
La asociación más fuerte del precio se observa con el área construida (\(\rho = 0{,}822\)), seguida por el número de baños (\(\rho = 0{,}768\)) y el estrato socioeconómico (\(\rho = 0{,}710\)); esto sugiere que tamaño, dotación de baños y segmento socioeconómico son dimensiones relevantes para diferenciar el valor de la oferta.
El precio presenta una relación positiva moderada con el número de habitaciones (\(\rho = 0{,}427\)), por lo que esta variable parece aportar información adicional, aunque menor que el área o los baños. Asimismo, el área construida se relaciona fuertemente con baños (\(\rho = 0{,}771\)) y de forma moderada-alta con habitaciones (\(\rho = 0{,}651\)), lo cual indica que estas variables describen parcialmente una misma dimensión de tamaño y capacidad del inmueble.
GGally::ggcorr(
vars_cor,
method = c("pairwise", "spearman"),
label = TRUE,
label_round = 2,
layout.exp = 1
) +
labs(
title = "Correlaciones de Spearman entre atributos numéricos"
)
Gráfico 18 A. Matriz de Correlaciones de Spearman
library(dplyr)
library(GGally)
library(ggplot2)
df_mat_spearman <- vivienda %>%
transmute(
Precio = as.numeric(preciom),
`Área construida` = as.numeric(areaconst),
Baños = as.numeric(banios),
Habitaciones = as.numeric(habitaciones),
Estrato = as.numeric(estrato)
) %>%
drop_na()Gráfico 18B. Matriz de Correlaciones de Spearman
En contraste, la correlación casi nula entre habitaciones y estrato (\(\rho = 0{,}040\)) muestra que los estratos altos no se distinguen necesariamente por tener más habitaciones, sino posiblemente por otros atributos como ubicación, calidad, área, tipo de vivienda y número de baños. Dado que todas las correlaciones son positivas, no se identifica una relación inversa relevante entre las variables analizadas; sin embargo, estas asociaciones son descriptivas y no implican causalidad. Dado que se calculó con Spearman, los coeficientes reflejan relaciones monótonas entre rangos y son apropiados frente a asimetrías y valores extremos en precio y área.
El Mapa 3 muestra que los anuncios se concentran mayoritariamente en la zona sur y en el norte, también refelja una concentración especial en el oeste. Al compararlo con el Mapa 4 podemos comparar la relación en el espacio con el precio de las viviendas anunciadas, los precios más altos en la zona sur de Pance y en el Oeste de la ciudad.
ggplot(
vivienda_geo,
aes(x = longitud, y = latitud, color = zona)
) +
geom_point(alpha = 0.45, size = 0.9) +
coord_equal() +
labs(
title = "",
x = "Longitud",
y = "Latitud",
color = "Zona"
)
Mapa 3. Distribución espacial de los anuncios de vivienda
Precio en el Espacio
library(ggplot2)
library(scales)
ggplot(
vivienda_geo,
aes(
x = longitud,
y = latitud,
color = preciom
)
) +
geom_point(
alpha = 0.60,
size = 1.2
) +
scale_color_gradientn(
colours = c(
"#FFF5F0", # Precios bajos: casi blanco
"#FCAE91", # Precios medio-bajos: salmón claro
"#FB6A4A", # Precios medios: naranja rojizo
"#CB181D", # Precios altos: rojo
"#67000D" # Precios muy altos: rojo oscuro
),
name = "Precio\n(millones COP)",
labels = label_number(
big.mark = ".",
decimal.mark = ",",
suffix = " M"
)
) +
coord_equal() +
labs(
title = "Distribución espacial del precio de las viviendas",
subtitle = "Los tonos rojos más intensos representan precios publicados más altos",
x = "Longitud",
y = "Latitud"
) +
theme_minimal()
Mapa 4. Distribución espacial de la variable precio de la
vivienda
La muestra de datos describe una oferta inmobiliaria urbana de Cali dominada por apartamentos (5.100 anuncios, frente a 3.219 casas), aunque las casas corresponden al segmento de mayor tamaño y valor: su precio mediano es de 430 millones de pesos y su área mediana de 240 m², frente a 279 millones y 90 m² en los apartamentos.
La oferta se concentra de manera desigual entre zonas, estratos y barrios, con una presencia visible de inmuebles de alto valor en las zonas sur y oeste —incluidos barrios como Pance, Ciudad Jardín, Aguacatal, Santa Rita, San Antonio, Normandía y Parcelaciones Pance—, mientras que las zonas oriente y nororiente muestran, descriptivamente, una mayor presencia de anuncios de menor precio.
El precio mediano general es de 330 millones de pesos, con valor mediano de la oferta entre 220 y 540 millones, y el área mediana es de 123 m², con un rango intercuartílico de 80 a 229 m²; en ambas variables la media supera la mediana y existen máximos de 1.999 millones y 1.745 m², respectivamente, lo que evidencia asimetría positiva y alta dispersión. Los valores extremos observados parecen mayoritariamente plausibles, pues corresponden a casas o apartamentos amplios, con más baños y habitaciones, ubicados en estratos altos y sectores asociados con vivienda de lujo; por ello deben conservarse y no tratarse automáticamente como errores.
La matriz de correlaciones confirman que el precio se relaciona de forma positiva y alta con el área construida (\(\rho = 0{,}822\)), el número de baños (\(\rho = 0{,}768\)) y el estrato (\(\rho = 0{,}710\)), mientras que la relación con habitaciones es moderada (\(\rho = 0{,}427\)); en consecuencia, área, baños y estrato son atributos especialmente relevantes para analizar la heterogeneidad de precios. Los mapas sugieren además un patrón espacial de la oferta y del precio, pero su confirmación formal requiere pruebas de autocorrelación espacial (que no hacen parte de este informe).
Antes de una análisis inferemncial, conviene transformar
logarítmicamente preciom y areaconst, debido a
su asimetría, la presencia de valores extremos y la posible no
linealidad de su relación con las demás variables; la transformación
logarítmica es habitual en modelos hedónicos de vivienda (teórica
económica de precios hedónicos) y puede mejorar la forma de la
distribución y la especificación del modelo.
Luego del anális exploratorio de datos de lsección 3, se toman las siguientes decisiones que se resumen en la Tabla 10.
| Variable/Característica | Decisión después del EDA | Justificación |
|---|---|---|
| id | Conservar como identificador, no como predictor | Identifica registros, pero no aporta significado económico |
| piso | Excluir del análisis principal | 31,7% de faltantes y heterogeneidad de registro |
| parqueaderos | Excluir del análisis principal | 19,3% de faltantes y no se observa la categoría 0 |
| Filas con faltantes marginales en variables esenciales | Eliminar del dataset | Son cerca de 0,04%; no justifica imputación |
| barrio | Normalizar texto y preservar versión original | Existen tildes, espacios, variantes y problemas de codificación |
| Extremos válidos | Conservar, marcar y explorar | Un valor extremo no es necesariamente un error |
| Precio y área | Conservar en escala original y crear logaritmos | Normalmente presentan asimetría positiva |
| Baños | Eliminar los 45 registros de viviendas sin baños | Se asumen como error de registro |
| Habitaciones | Conservar las 66 viviendas con habitación=0 | Se presumen como apartaestudios o viviendas de un solo ambiente |
Tabla 10. Resumen de las decisiones después del EDA
La depuración se realizó de manera reproducible a partir de la base original. Se excluyeron las variables piso y parqueaderos de la base analítica principal debido a las limitaciones identificadas en su calidad y falta de datos. Posteriormente, se estandarizaron las variables de texto, particularmente zona, tipo y barrio; se verificó la unicidad del identificador; se eliminaron observaciones incompletas en las variables analíticas esenciales, cuya proporción era marginal; y se validó la coherencia de precios, áreas, conteos y coordenadas. Los valores extremos plausibles se conservaron y se trataron mediante transformaciones logarítmicas de precio y área para los análisis posteriores
resumen_depurar <- tibble::tibble(
etapa = c(
"Dataset original",
"Después de excluir piso y parqueaderos",
"Después de validar reglas y casos completos"
),
n = c(
nrow(vivienda_raw),
nrow(vivienda_auditoria),
nrow(vivienda_limpia)
)
) %>%
mutate(
eliminados = c(0, n[1] - n[2], n[2] - n[3]),
porcentaje_eliminado = eliminados / n[1] * 100
)
resumen_depurar# Validación de reglas
vivienda_limpia %>%
summarise(
precios_no_positivos = sum(preciom <= 0),
areas_no_positivas = sum(areaconst <= 0),
banios_menor_uno = sum(banios < 1),
habitaciones_menor_uno = sum(habitaciones < 1),
longitud_fuera_rango = sum(longitud < -77 | longitud > -76),
latitud_fuera_rango = sum(latitud < 3 | latitud > 4),
ids_duplicados = sum(duplicated(id))
)¿Por qué excluir las variables piso y
parqueadero?
La exclusión de piso se sustenta en tres elementos: (1) Tiene 2.638 faltantes de 8.322 registros, equivalentes a 31,70%; (2) la ausencia no es homogénea: fue 38,96% en casas y 27,08% en apartamentos; además varía por zona, estrato y barrio; (3) Aunque el diccionario del paquete define piso como “piso en la que está ubicada la vivienda”, la distribución observada en casas es difícil de interpretar como un nivel de ubicación homogéneo: entre las casas observadas predominan los valores 2 y 3, mientras que solo 21,9% tiene valor 1.
Por estas razones, imputar mecánicamente piso = 1 para casas, o imputar un valor global como 2, distorsionaría la distribución y subestimaría la incertidumbre. Además, una imputación múltiple requeriría asumir que, condicionando por precio, área, tipo, estrato, zona, barrio y ubicación, los valores faltantes siguen un mecanismo MAR; dado el patrón observado, esta hipótesis no puede sostenerse como un hecho. Los análisis de sensibilidad son precisamente el medio recomendado para mostrar cuánto dependen las conclusiones de las decisiones frente a faltantes.
La exclusión de parqueaderos está igualmente respaldada: (1) Tiene 1.605 faltantes, equivalentes a 19,29% de la base; (2) Entre los 6.717 valores observados, el soporte va de 1 a 10: no existe ningún registro con cero parqueaderos, aunque cero es una categoría económicamente posible; (3) Los anuncios sin dato de parqueadero tienen un perfil sistemáticamente distinto: precio mediano de 180 millones, frente a 355 millones entre los registros observados; área mediana de 90 m² frente a 130 m²; dos baños frente a tres y estrato mediano 4 frente a 5.
Tal y como se menciona en el material del curso en Brigthspace “[…] este análisis consiste en describir la variación producida por las observaciones de p variables aleatorias, mediante un conjunto de nuevas variables que están correlacionadas entre si, denominadas componentes y que están conformadas por combinación lineal de las variables originales. Se utiliza como complemento de los análisis descriptivos y para contribución en modelos predictivos, reduciendo el número de variables empleadas en el modelo”
Así, “las nuevas variables (llamadas componentes principales) se obtienen en orden de contribución a la variabilidad total de los datos, de tal forma que el primer componente describe la mayor cantidad de la variación total del conjunto de variables originales. El segundo componente principal se elige de tal forma que explique la mayor cantidad de la variación total del conjunto de datos que resta sin explicar por el primer componente, bajo la condición de ser independiente de la primera componente y así sucesivamente.
En nuestro caso particular de datos inmoboliarios, el ACP busca responder a la pregunta ¿qué combinaciones de atributos cuantitativos explican la mayor variabilidad de la oferta residencial? No está diseñado para explicar causalmente el precio, ni debe utilizar variables categóricas como tipo, zona o barrio para calcular los componentes.
Para esta aplicación, los componentes se estiman teniendo en cuenta las variables log_preciom (logaritmo del precio publicado) y log_areaconst (logaritmo del área construida), banios (cantidad de baños), habitaciones (cantidad de habitaciones), estrato_num: estrato como ordinal numérico.
Después se proyectan como variables suplementarias: tipo y zona, la variable estrato como factor, para visualizar sus categorías sin usarlo dos veces en el cálculo. Las variables suplementarias ayudan a interpretar los ejes pero no alteran la construcción de los componentes. FactoMineR::PCA() admite explícitamente variables cuantitativas y cualitativas suplementarias
datos_acp %>%
summarise(
across(
c(log_preciom, log_areaconst, banios, habitaciones, estrato_num),
list(
minimo = min,
maximo = max,
desviacion = sd
)
)
)P1. Se revisan nuevamente correlaciones de las variables a incluir en el análisis (esta vez inlcuimos la transformación logaritmica de las variables precio y área construida). (Ver Gráfico 19)
library(ggcorrplot)
ggcorrplot::ggcorrplot(
cor_acp,
type = "lower",
lab = TRUE,
lab_size = 3,
colors = c("#D73027", "white", "#1A9850")
) +
labs(
title = ""
)
Gráfico 19. Correlaciones de Spearman previas al ACP, incluyendo las
variables transformadas logaritmicamente
P2. Ejecutamos el PCA
En este caso el primer componente principal explica el 64.1% de la variabilidad contenida en la base de datos y entre los dos primeros se casi el 88% de los datos (88.1%), lo cual indicaría que con solo una variable (CP1) que se obtiene mediante una combinación lineal de las variables se puede resumir gran parte de la variabilidad que contiene la base de datos.
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 3.20377158 64.075432 64.07543
## Dim.2 1.19920606 23.984121 88.05955
## Dim.3 0.27567603 5.513521 93.57307
## Dim.4 0.22694416 4.538883 98.11196
## Dim.5 0.09440216 1.888043 100.00000
Tabla 11. Autovalores
El análisis de autovalores indica que las dos primeras componentes principales explican conjuntamente el 88,06% de la variabilidad total de las variables analizadas. La primera dimensión concentra el 64,08% de la información y constituye el eje dominante de diferenciación entre los inmuebles, mientras que la segunda dimensión aporta un 23,98% adicional.
Las tres componentes restantes presentan contribuciones individuales inferiores al 6%, por lo que su capacidad explicativa es marginal. Asimismo, las dos primeras dimensiones presentan autovalores superiores a uno, cumpliendo el criterio de Kaiser para su retención. En consecuencia, se seleccionaron las dos primeras componentes para representar e interpretar la estructura multivariada de la oferta inmobiliaria, pues permiten resumir de manera eficiente la información de precio, área construida, baños, habitaciones y estrato socioeconómico.
fviz_eig(
acp,
addlabels = TRUE,
ylim = c(0, 100)
) +
labs(
title = "",
x = "Componente principal",
y = "Porcentaje de varianza explicada"
)
Gráfico 20. Varianza explicada por los componentes
principales
fviz_pca_var(
acp,
col.var = "contrib",
gradient.cols = c("#457B9D", "#F4A261", "#D62828"),
repel = TRUE
) +
labs(
title = "Círculo de correlaciones: contribución de variables al ACP"
)
Gráfico 21. Varianza explicada por los componentes
principales
La primera dimensión, que explica el 64,1%, sintetiza principalmente una dimensión de escala y valor del inmueble, al estar asociada positivamente con el logaritmo del precio, el logaritmo del área construida y el número de baños. En consecuencia, las viviendas situadas hacia valores positivos de este eje tienden a ser más amplias, contar con mayor número de baños y presentar precios más altos. (Ver Gráfico 22)
La segunda dimensión, que explica el 24,0%, contrapone principalmente el estrato socioeconómico y el precio frente al número de habitaciones y, en menor medida, al área construida. Este resultado sugiere que los inmuebles de estratos más altos se diferencian no solo por su tamaño, sino también por atributos de localización y calidad asociados al segmento socioeconómico. La orientación opuesta entre estrato y habitaciones confirma que un mayor estrato no implica necesariamente un mayor número de habitaciones. (Ver Gráfico 23)
fviz_contrib(
acp,
choice = "var",
axes = 1,
top = 10
) +
labs(
title = "Variables que más contribuyen al Componente 1"
)
Gráfico 22. Variables que más contribuyen al Componente CP1
fviz_contrib(
acp,
choice = "var",
axes = 2,
top = 10
) +
labs(
title = "Variables que más contribuyen al Componente 2"
)
Gráfico 23. Variables que más contribuyen al Componente CP2
ggplot(
datos_acp_grafico,
aes(x = dim1, y = dim2, color = tipo)
) +
geom_point(alpha = 0.30, size = 1) +
stat_ellipse(
aes(group = tipo),
linewidth = 0.8,
linetype = 2
) +
scale_color_manual(
values = c(
"apartamento" = "#457B9D",
"casa" = "#E76F51"
)
) +
labs(
title = "",
subtitle = "Color según tipo de vivienda; muestra aleatoria para visualización",
x = "Componente principal 1",
y = "Componente principal 2",
color = "Tipo"
)Gráfico 24. Propiedades proyectadas sobre los dos primeros componentes
El Gráfico 24 mustra la proyección de las propiedades sobre las dos primeras componentes principales, evidencia una diferenciación parcial entre apartamentos y casas.
Los apartamentos se concentran principalmente en valores centrales y negativos de la primera componente, asociados con perfiles de menor área construida, menor número de baños y precios relativamente inferiores. En contraste, las casas presentan una mayor dispersión y una presencia más marcada hacia valores positivos de la primera componente, lo que refleja su mayor heterogeneidad y la existencia de viviendas de mayor tamaño, precio y dotación.
Sin embargo, las elipses de ambos tipos se superponen de manera importante en la región central del plano, lo que indica que existen apartamentos y casas con características similares. En consecuencia, el tipo de vivienda contribuye a describir la estructura de la oferta, pero no determina por sí solo la posición de los inmuebles en el espacio multivariado.
El Análisis de Componentes Principales se aplicó a las variables cuantitativas transformadas y estandarizadas: logaritmo del precio, logaritmo del área construida, número de baños, número de habitaciones y estrato socioeconómico. Las variables tipo de vivienda, zona y barrio se incorporaron como cualitativas suplementarias para apoyar la interpretación, sin participar en el cálculo de los componentes. La estandarización fue necesaria para evitar que las diferencias de escala dominaran la solución factorial. Los dos primeros componentes se interpretaron a partir de su varianza explicada, las contribuciones de cada variable y el círculo de correlaciones.
El Análisis de Componentes Principales evidencia que la estructura multivariada de la oferta inmobiliaria puede resumirse de manera eficiente en dos dimensiones, que explican conjuntamente el 88,06% de la variabilidad de precio, área construida, número de baños, habitaciones y estrato. La primera componente, responsable del 64,08% de la variación, representa principalmente una dimensión de escala y valor del inmueble: las viviendas con mayores valores en este eje tienden a tener precios más altos, mayor área construida y más baños.
La segunda componente, que explica 23,98%, diferencia el estrato socioeconómico y el precio relativo frente a la configuración habitacional, especialmente el número de habitaciones; este resultado muestra que las viviendas de estratos altos no se caracterizan necesariamente por tener más habitaciones, sino por una combinación de localización, precio, calidad y otros atributos asociados al segmento socioeconómico. La proyección de los inmuebles revela una diferenciación parcial entre casas y apartamentos: los apartamentos se concentran en perfiles más compactos y relativamente homogéneos, mientras que las casas presentan mayor dispersión y se ubican con más frecuencia en perfiles de mayor tamaño, precio y dotación.
Sin embargo, el solapamiento entre ambos tipos confirma que existen apartamentos de alta gama y casas de perfil intermedio con características similares. En síntesis, el ACP identifica que el mercado se organiza principalmente alrededor de la escala física y económica de las viviendas, complementada por un eje socioeconómico-territorial, y ofrece una base apropiada para el análisis de conglomerados posterior.
Tal y como menciona el material del curso “el análisis de conglomerados, también conocido como clustering, es un método estadístico usado para agrupar objetos similares en función de sus características. Mediante este análisis se logra identificar grupos muy parecidos (homogéneos) de objetos o individuos. Dentro de cada grupo los objetos son más similares entre sí que con los de otros grupos. El análisis de conglomerados implica la selección de un conjunto de variables para medir las características de los objetos o individuos, y luego aplicar un algoritmo de agrupamiento para clarificarlos en conglomerados. Los algoritmos de agrupamiento utilizados pueden ser jerárquicos o no jerárquicos, dependiendo de si los grupos se construyen de forma iterativa a partir de subgrupos más pequeños.
En este trabajo, se usa k-means como una técnica de segmentación exploratoria para clasificar las viviendas en un número predefinido de conglomerados con características similares. Cada inmueble fue representado por el precio y el área construida transformados logarítmicamente, el número de baños, el número de habitaciones y el estrato socioeconómico, variables que fueron estandarizadas antes de calcular las distancias.
El algoritmo asigna cada vivienda al conglomerado cuyo centroide —definido como el perfil promedio del grupo— resulta más cercano y actualiza iterativamente dichos centroides hasta minimizar la heterogeneidad interna de los grupos. Por tanto, los conglomerados representan perfiles estadísticos de la oferta inmobiliaria y permiten distinguir segmentos de viviendas con niveles similares de valor, tamaño, dotación y condición socioeconómica.
Para el k-means principal, se propone las siguientes variables activas:
| Variable | Tratamiento | Razón |
|---|---|---|
| preciom | log_preciom = log(preciom) | Tiene cola derecha; el log reduce la influencia de inmuebles muy caros |
| areaconst | log_areaconst = log(areaconst) | También suele ser asimétrica y tener extremos |
| banios | Numérica | Resume calidad/capacidad del inmueble |
| habitaciones | Numérica | Resume configuración habitacional |
| estrato | estrato_num | Representa posición socioeconómica ordinal |
| tipo | No entra inicialmente | Es categórica; se utiliza para describir cada grupo |
| zona, barrio | No entran inicialmente | Son categóricas y territoriales; se usan para interpretación y mapas |
| longitud, latitud | No entran inicialmente | Si se incluyen, los grupos se vuelven primordialmente geográficos, no de perfil inmobiliario |
| id | Excluir | Es un identificador |
| piso, parqueaderos | Excluir | Ya se justificó técnicamente su exclusión |
Tabla 12. Descripción y justificación de variables incluidas en el análisis de conglomerados
K-means es sensible a valores extremos porque los centroides se basan en medias, y tiende a funcionar mejor si los grupos son relativamente compactos, aproximadamente esféricos y de dispersión comparable. Por esto, se transforma precio/área, se estandariza, se revisan valores extremos.
P1. Verificación de los valores de las variables
datos_kmeans %>%
summarise(
n = n(),
precios_no_positivos = sum(precio <= 0),
areas_no_positivas = sum(area <= 0),
banios_menor_uno = sum(banios < 1),
habitaciones_menor_uno = sum(habitaciones < 1),
estrato_fuera_rango = sum(!estrato_num %in% c(3, 4, 5, 6))
)Tabla 13. Verificación de los valores dentro de los rangos permitidos por el algoritmo
P2. Revisión de datos extremos
datos_kmeans %>%
select(
id, tipo, zona, barrio,
precio, area, banios, habitaciones, estrato_num
) %>%
arrange(desc(precio)) %>%
slice_head(n = 20)Tabla 14 Datos extremos observados en las variables includias
P3. Distribución transformada. Las variables precio y área construida se transformas en sus logaritmos. Ver Gráficos 25 y 26.
ggplot(datos_kmeans, aes(x = log_preciom)) +
geom_histogram(
bins = 50,
fill = "#457B9D",
color = "white"
) +
labs(
title = "Distribución del logaritmo del precio",
x = "log(precio en millones)",
y = "Número de anuncios"
)
Gráfico 25. Distribución del logaritmo del precio de la
vivienda
ggplot(datos_kmeans, aes(x = log_areaconst)) +
geom_histogram(
bins = 50,
fill = "#2A9D8F",
color = "white"
) +
labs(
title = "Distribución del logaritmo del área construida",
x = "log(área construida en m²)",
y = "Número de anuncios"
)
Gráifco 26. Distribución del logaritmo del área construida
P4. Estandarizar las variables
Comprobar la estandarización. Las medias deben aproximarse a 0 y las desviaciones estándar a 1.Seleccionar el número de grupos No se elije 𝑘arbitrariamente. La eleccción se realiza evaluando como mínimo: (A) Método del codo: observa la reducción de la suma de cuadrados intra-grupo; (B) Silhouette promedio: mide qué tan bien se separa cada observación de otros grupos. (C) Tamaño e interpretabilidad: evita grupos diminutos o perfiles indistinguibles.(D) Estabilidad: usa varias inicializaciones y una semilla fija.
## log_preciom log_areaconst banios habitaciones estrato_num
## 0 0 0 0 0
## log_preciom log_areaconst banios habitaciones estrato_num
## 1 1 1 1 1
fviz_nbclust(
datos_kmeans_z,
FUNcluster = kmeans,
method = "wss",
k.max = 10,
nstart = 50
) +
labs(
title = "Método del codo para seleccionar k",
x = "Número de conglomerados",
y = "Suma de cuadrados intra-grupo"
)
Gráfico 27. Método del codo para seleccionar k
El método del codo muestra que la suma de cuadrados intra-grupo disminuye de manera pronunciada al aumentar el número de conglomerados desde uno hasta cuatro, lo que evidencia una mejora importante en la homogeneidad interna de los segmentos. A partir de 𝑘=4, la curva se aplana y las reducciones adicionales en la variación intra-grupo son cada vez menores. En consecuencia, se selecciona una solución de cuatro conglomerados, ya que ofrece un balance razonable entre reducción de heterogeneidad, parsimonia e interpretabilidad de los perfiles inmobiliarios. Esta elección debe complementarse con el análisis de silhouette y la caracterización sustantiva de los grupos obtenidos.
fviz_nbclust(
datos_kmeans_z,
FUNcluster = kmeans,
method = "silhouette",
k.max = 10,
nstart = 50
) +
labs(
title = "Silhouette promedio para seleccionar k",
x = "Número de conglomerados",
y = "Anchura promedio de silhouette"
)
Gráfico 28. Silhouette promedio para seleccionar k
El criterio de silhouette indica que las soluciones con dos y tres conglomerados presentan la mayor separación interna y externa, con anchuras promedio cercanas a 0,40 y 0,39, respectivamente.
La solución de cuatro grupos alcanza una silhouette aproximada de 0,32, lo que representa una estructura moderada y evidencia cierto solapamiento entre los segmentos. A partir de cuatro conglomerados, la calidad de la partición no mejora de forma sostenida y tiende a disminuir.
En consecuencia, la elección entre tres y cuatro conglomerados debe equilibrar la separación estadística con la utilidad analítica de los perfiles obtenidos: tres grupos (k=3) ofrecen una segmentación más nítida, mientras que cuatro grupos pueden justificarse si permiten identificar un segmento adicional con características inmobiliarias claramente diferenciadas, como la oferta de alta gama.
evaluacion_k <- tibble(
k = 2:8,
wss = NA_real_,
silhouette_promedio = NA_real_
)
for (i in seq_along(evaluacion_k$k)) {
k_i <- evaluacion_k$k[i]
set.seed(123)
km_i <- kmeans(
datos_kmeans_z,
centers = k_i,
nstart = 50,
iter.max = 100
)
evaluacion_k$wss[i] <- km_i$tot.withinss
sil_i <- silhouette(
km_i$cluster,
dist(datos_kmeans_z)
)
evaluacion_k$silhouette_promedio[i] <- mean(sil_i[, "sil_width"])
}
evaluacion_kTabla 15. Cálculo de valores exactos para k= 2,…8.
La Tabla 15 muestra que k=2 maximiza la separación estadística, k=3 ofrece un equilibrio muy favorable entre calidad y mayor detalle, y k=4 solo se justificaría si permite identificar un segmento adicional relevante e interpretable —por ejemplo, la oferta inmobiliaria premium— que se pierde al usar tres grupos.
Después de revisar los gráficos y la evaluacion_k (Tabla 15), se define número de grupos (k=3). .
Se seleccionaron tres conglomerados (k=3) porque el método del codo mostró una reducción marginal de WSS a partir de tres grupos, la silhouette promedio fue competitiva frente a soluciones vecinas y los tres perfiles resultantes tuvieron tamaños suficientes e interpretación inmobiliaria diferenciada.
Tamaño de los conglomerados. La solución de tres conglomerados distribuye las 8.243 viviendas analizadas de manera desigual. El primer conglomerado concentra 4.408 inmuebles, equivalentes al 53,48% de la muestra, seguido por el segundo conglomerado con 2.929 observaciones (35,53%). El tercer conglomerado agrupa 906 viviendas, correspondientes al 10,99% de la oferta. Esta composición indica que el mercado analizado está dominado por dos perfiles principales de vivienda, mientras que el tercer grupo representa un segmento de menor tamaño y potencialmente más específico. Como se observa a continuación:
Silhouette por observación
sil_final <- silhouette(
km_final$cluster,
dist(datos_kmeans_z)
)
fviz_silhouette(sil_final) +
labs(
title = paste(
""
)
)## cluster size ave.sil.width
## 1 1 4408 0.46
## 2 2 2929 0.33
## 3 3 906 0.20
Gráfico 29. Silhouette por vivienda: solución con k=
3conglomerados
El Gráfico 29 de silhouette para la solución de tres conglomerados muestra una anchura promedio cercana a 0,39, lo que indica una estructura de segmentación moderada. El primer conglomerado presenta la mayor proporción de viviendas con valores positivos y superiores al promedio, por lo que constituye el grupo más cohesionado.
El segundo conglomerado presenta una calidad intermedia, con un núcleo de observaciones bien asignadas y algunas viviendas próximas a la frontera con otros grupos. El tercer conglomerado, de menor tamaño, registra los valores de silhouette más bajos e incluso algunas asignaciones negativas, lo que evidencia un mayor solapamiento con los demás segmentos. En consecuencia, la solución de tres grupos resulta útil para caracterizar perfiles generales de la oferta inmobiliaria
Análisis de los centros de cada grupo en escala estandarizada.
centros_z <- as.data.frame(km_final$centers) %>%
mutate(
conglomerado = factor(seq_len(n()))
) %>%
select(conglomerado, everything())
centros_z_redondeado <- centros_z %>%
mutate(
across(
where(is.numeric),
~ round(.x, 2)
)
)
centros_z_redondeadoTabla 16. Centroides estandarizados
La Tabla 16 presenta los centroides estandarizados de los tres conglomerados obtenidos mediante k-means. Cada valor indica cuántas desviaciones estándar se encuentra el perfil promedio de un conglomerado por encima o por debajo del promedio de toda la muestra: valores negativos representan atributos inferiores al promedio y valores positivos, atributos superiores. Por tanto, esta tabla permite identificar y nombrar el perfil característico de cada segmento. (Ver Tabla 17.)
| Conglomerado | Perfil principal | Evidencia en los centroides |
|---|---|---|
| 1 | Vivienda compacta de menor valor relativo | Precio −0,70-0,70−0,70, área −0,72-0,72−0,72, baños −0,68-0,68−0,68, habitaciones −0,48-0,48−0,48 y estrato −0,45-0,45−0,45 |
| 2 | Vivienda de alto valor y estrato alto | Precio +0,93+0,93+0,93, área +0,73+0,73+0,73, baños +0,68+0,68+0,68, estrato +0,88+0,88+0,88; habitaciones cercanas al promedio +0,05+0,05+0,05 |
| 3 | Vivienda familiar amplia de estrato relativamente bajo | Área +1,16+1,16+1,16, baños +1,13+1,13+1,13, habitaciones +2,18+2,18+2,18, precio +0,41+0,41+0,41, pero estrato −0,68-0,68−0,68 |
Tabla 17. Intepretación de los conglomerados
Los centroides estandarizados permiten caracterizar tres segmentos de la oferta inmobiliaria. El primer conglomerado agrupa viviendas con precio, área construida, número de baños, habitaciones y estrato por debajo del promedio de la muestra, por lo que representa una oferta relativamente compacta y de menor valor. El segundo conglomerado corresponde a viviendas de alta gama, con precios, áreas, baños y estratos significativamente superiores al promedio, aunque con un número de habitaciones cercano a la media general.
Finalmente, el tercer conglomerado se distingue por su elevada capacidad habitacional: presenta áreas y número de baños superiores al promedio, y especialmente un número de habitaciones 2,18 desviaciones estándar por encima de la media; no obstante, su estrato se ubica por debajo del promedio. Este último resultado muestra que la amplitud física de una vivienda no implica necesariamente una ubicación en los estratos socioeconómicos más altos.
perfil_kmeans <- vivienda_kmeans %>%
group_by(conglomerado) %>%
summarise(
n = n(),
porcentaje = n / nrow(vivienda_kmeans),
precio_mediano = median(precio, na.rm = TRUE),
precio_promedio = mean(precio, na.rm = TRUE),
area_mediana = median(area, na.rm = TRUE),
area_promedio = mean(area, na.rm = TRUE),
banios_medianos = median(banios, na.rm = TRUE),
habitaciones_medianas = median(habitaciones, na.rm = TRUE),
estrato_mediano = median(estrato_num, na.rm = TRUE),
.groups = "drop"
)
perfil_kmeansTabla 18. Perfil de precio y área en escala original
La Tabla 18 presenta el perfil de precio y área en escala original para los tres conglomerados, y confirma que los segmentos identificados por k-means son claramente diferentes. El conglomerado 1, que reúne el 53,48% de la muestra, corresponde a la oferta más compacta y de menor valor relativo: tiene un precio mediano de 228,5 millones de pesos y un área mediana de 83 m².
El conglomerado 2, con el 35,53% de las viviendas, representa la oferta de mayor valor económico: su precio mediano alcanza 600 millones y el área mediana 216 m², coherente con su perfil de estrato, baños y precio superiores al promedio. El conglomerado 3, que concentra el 10,99% de los inmuebles, se caracteriza por ser el segmento de mayor tamaño físico, con un área mediana de 300 m², pero con un precio mediano de 430 millones, inferior al del conglomerado 2; esto confirma que corresponde a viviendas amplias y con alta capacidad habitacional, aunque ubicadas en estratos relativamente menores.
En los tres grupos, los promedios superan las medianas —en especial en el conglomerado 2, donde el precio promedio es 712,5 millones frente a una mediana de 600 millones—, lo que revela asimetría positiva y la presencia de inmuebles de precio o área excepcionalmente altos. Por ello, la mediana constituye la medida más adecuada para describir el perfil típico de cada segmento.
Visualizaciones Principales
acp_visual <- prcomp(
datos_kmeans_z,
center = FALSE,
scale. = FALSE
)
coords_acp <- as.data.frame(acp_visual$x[, 1:2]) %>%
setNames(c("CP1", "CP2")) %>%
mutate(
conglomerado = vivienda_kmeans$conglomerado
)
ggplot(
coords_acp,
aes(
x = CP1,
y = CP2,
color = conglomerado
)
) +
geom_point(alpha = 0.25, size = 0.9) +
stat_ellipse(
aes(group = conglomerado),
linewidth = 0.8,
linetype = 2
) +
scale_color_viridis_d() +
labs(
title = "Conglomerados k-means en el espacio de componentes principales",
subtitle = "La proyección es solo para visualización",
x = "Componente principal 1",
y = "Componente principal 2",
color = "Conglomerado"
)
Gráfico 30. Conglomerados k-means en el espacio de componentes
principales
En el Gráfico 30 podemos ver el Conglomerado 1, morado que concentra principalmente a la izquierda, con valores negativos de la primera componente. De acuerdo con la interpretación del ACP, esta ubicación corresponde a viviendas de menor precio, menor área, menos baños y estratos relativamente inferiores. Es el grupo más numeroso y representa la oferta compacta y de menor valor relativo. Sus bandas horizontales reflejan la naturaleza discreta de variables como número de baños, habitaciones y estrato, no necesariamente subgrupos independientes.
El Conglomerado 2, verde se ubica principalmente en la parte superior derecha del plano. Tiene valores positivos de la primera componente y, en promedio, valores más altos de la segunda componente. Este patrón corresponde a viviendas de mayor precio, área y número de baños, ubicadas en estratos más altos. Su perfil coincide con el segmento de alta gama identificado en los centroides: precio mediano de 600 millones, área mediana de 216 m² y estrato superior al promedio.
El Conglomerado 3, amarillo: se concentra en la parte inferior derecha. Al igual que el conglomerado 2, presenta valores positivos de la primera componente, lo que indica viviendas grandes, con más baños y precios superiores al promedio. Sin embargo, se diferencia claramente por valores negativos de la segunda componente, asociados a una mayor cantidad de habitaciones y a estratos relativamente menores. Esto es coherente con su perfil: área mediana de 300 m², precio mediano de 430 millones y número de habitaciones muy por encima del promedio, aunque con estrato inferior al promedio.
Composición por tipo y zona
ggplot(
vivienda_kmeans,
aes(x = conglomerado, fill = tipo)
) +
geom_bar(position = "fill") +
scale_y_continuous(labels = percent) +
scale_fill_manual(
values = c(
"apartamento" = "#457B9D",
"casa" = "#E76F51"
)
) +
labs(
title = "Composición por tipo de vivienda",
subtitle = "Variable no utilizada para formar los conglomerados",
x = "Conglomerado",
y = "Proporción dentro del conglomerado",
fill = "Tipo"
)
Gráfico 31. Composición por tipo de vivienda
La composición por tipo de vivienda confirma la coherencia sustantiva de los conglomerados, aun cuando esta variable no fue utilizada en su construcción. El conglomerado 1 está conformado mayoritariamente por apartamentos, lo que coincide con su perfil de menor precio, área y dotación relativa. El conglomerado 2 presenta una distribución prácticamente equilibrada entre apartamentos y casas, indicando que el segmento de alta gama incluye ambos tipos de inmueble cuando comparten niveles elevados de precio, área, baños y estrato.
Por su parte, el conglomerado 3 está integrado casi exclusivamente por casas, resultado consistente con su caracterización como viviendas amplias y de alta capacidad habitacional.
Mapa de Conglomerados
ggplot(
vivienda_kmeans,
aes(
x = longitud,
y = latitud,
color = conglomerado
)
) +
geom_point(alpha = 0.40, size = 0.9) +
coord_equal() +
scale_color_viridis_d() +
labs(
title = "Distribución espacial de los conglomerados inmobiliarios",
subtitle = "Las coordenadas no participaron en k-means; se usan para interpretar la localización",
x = "Longitud",
y = "Latitud",
color = "Conglomerado"
)
Mapa 5. Distribución espacial de los conglomerados
inmobiliarios
El Mapa 5 evidencia que los conglomerados inmobiliarios presentan patrones espaciales diferenciados, aunque las coordenadas geográficas no fueron utilizadas en la estimación de k-means. El conglomerado 1, asociado con viviendas de menor precio, área y dotación relativa, se distribuye ampliamente en distintos sectores de la ciudad.
El conglomerado 2, correspondiente al segmento de alta gama, muestra agrupamientos territoriales más definidos, particularmente en áreas occidentales y del sur, lo que sugiere una asociación entre los perfiles de mayor valor y determinadas localizaciones urbanas. Por su parte, el conglomerado 3, caracterizado por viviendas amplias y con mayor capacidad habitacional, pero de estrato relativamente menor, presenta una distribución más dispersa. Aunque existe coexistencia de los tres segmentos en varias zonas, la distribución observada confirma que la heterogeneidad física y socioeconómica de la oferta inmobiliaria también posee una expresión territorial.
El análisis de conglomerados mediante k-means permitió segmentar la oferta inmobiliaria de Cali en tres perfiles diferenciados a partir del precio y área construida transformados logarítmicamente, el número de baños, habitaciones y estrato socioeconómico. La solución de tres grupos ofrece un equilibrio adecuado entre separación estadística e interpretabilidad, con una silhouette promedio cercana a 0,39, aunque debe entenderse como una segmentación exploratoria debido al solapamiento parcial entre algunos inmuebles.
El primer conglomerado, que reúne el 53,48% de la muestra, corresponde principalmente a una oferta de apartamentos compactos, con precio mediano de 228,5 millones de pesos y área mediana de 83 m². El segundo grupo, con 35,53% de los anuncios, representa el segmento de alta gama, caracterizado por precio mediano de 600 millones, área mediana de 216 m², mayor número de baños y estratos superiores, e incluye tanto casas como apartamentos. El tercer conglomerado, equivalente al 10,99% de la oferta, agrupa casi exclusivamente casas amplias y familiares, con área mediana de 300 m², elevado número de habitaciones y baños, y un precio mediano de 430 millones, aunque con estratos relativamente menores al segmento premium.
La distribución espacial diferenciada de los grupos, pese a que las coordenadas no se utilizaron en su estimación, confirma que la heterogeneidad física, socioeconómica y económica de la oferta inmobiliaria también presenta una expresión territorial.
En el mismo orden de las notas de clase, entendemos que el análisis de Correspondencia “es un método estadístico utilizado para representar posibles asociaciones entre variables categóricas, es decir la asociación entre sus categorías, con el fin establecer si existe, patrones o estructuras en los datos. Este método estadístico es de tipo exploratorio y complementario de otros tipos de análisis como los modelos de regresión logístico”.
En nuestro caso, el análisis de correspondencia debe responder a la pregunta ¿qué asociaciones existen entre tipo de vivienda, zona y barrio dentro de la oferta inmobiliaria?
Parte A: AC simple de tipo de vivienda y zona. Este análisis es el más fácil de comunicar y debe aparecer primero.
Paso 1: Tabla de contingencia
# ============================================================
# Asociación previa al ACM: chi-cuadrado y V de Cramér
# ============================================================
# Función para calcular chi-cuadrado y V de Cramér
prueba_chi_cramer <- function(x, y, nombre_relacion) {
tabla <- table(x, y)
prueba <- chisq.test(tabla, correct = FALSE)
n <- sum(tabla)
k <- min(nrow(tabla), ncol(tabla))
v_cramer <- sqrt(
unname(prueba$statistic) / (n * (k - 1))
)
tibble::tibble(
relacion = nombre_relacion,
chi_cuadrado = unname(prueba$statistic),
gl = unname(prueba$parameter),
p_valor_num = prueba$p.value,
p_valor = format.pval(prueba$p.value, digits = 3, eps = 0.001),
v_cramer = v_cramer,
frecuencia_esperada_minima = min(prueba$expected),
porcentaje_celdas_esperadas_menor_5 = mean(prueba$expected < 5) * 100
)
}
# Pruebas de independencia entre pares de variables
resultado_tipo_zona <- prueba_chi_cramer(
datos_acm$tipo,
datos_acm$zona,
"Tipo × zona"
)
resultado_tipo_estrato <- prueba_chi_cramer(
datos_acm$tipo,
datos_acm$estrato,
"Tipo × estrato"
)
resultado_zona_estrato <- prueba_chi_cramer(
datos_acm$zona,
datos_acm$estrato,
"Zona × estrato"
)
# Tabla consolidada
tabla_asociaciones <- dplyr::bind_rows(
resultado_tipo_zona,
resultado_tipo_estrato,
resultado_zona_estrato
) %>%
dplyr::mutate(
interpretacion_v = dplyr::case_when(
v_cramer < 0.10 ~ "Muy débil",
v_cramer < 0.20 ~ "Débil",
v_cramer < 0.30 ~ "Moderada",
v_cramer < 0.40 ~ "Moderada-alta",
TRUE ~ "Alta"
)
)
tabla_asociacionesControl de calidad previo. Antes de calcular el ACM, documenta el tamaño efectivo de la muestra y verifica las categorías. Esto evita que valores escritos de forma distinta —por ejemplo, “Sur” y “sur”— se interpreten como categorías diferentes.
Asociación antes del ACM. El ACM es exploratorio y descriptivo. Antes de interpretar el mapa, se verifican las asociaciones bivariadas entre pares de variables mediante chi-cuadrado y V de Cramér.
| Relación | Resultado | Interpretación |
|---|---|---|
| Tipo × zona | χ2=688,15\chi^2 = 688{,}15χ2=688,15, gl=4gl = 4gl=4, p<0,001p < 0{,}001p<0,001, V=0,289V = 0{,}289V=0,289 | Existe una asociación estadísticamente significativa y de magnitud moderada entre el tipo de vivienda y la zona. La proporción de casas y apartamentos cambia según la zona; algunas áreas concentran relativamente más casas y otras más apartamentos. |
| Tipo × estrato | χ2=215,44\chi^2 = 215{,}44χ2=215,44, gl=3gl = 3gl=3, p<0,001p < 0{,}001p<0,001, V=0,162V = 0{,}162V=0,162 | Existe asociación significativa, pero de intensidad débil. Aunque la distribución de casas y apartamentos varía entre estratos, el estrato por sí solo explica poco la diferencia en el tipo de vivienda. |
| Zona × estrato | χ2=3801,78\chi^2 = 3801{,}78χ2=3801,78, gl=12gl = 12gl=12, p<0,001p < 0{,}001p<0,001, V=0,392V = 0{,}392V=0,392 | Es la asociación más fuerte de las tres y puede interpretarse como moderada a relativamente alta. La composición por estrato cambia de forma marcada entre zonas, lo que evidencia una estructura socioespacial clara del mercado inmobiliario. |
Tabla 19B. Estadístico chi-cuadrado para la hipótesis de independencia
Así, Las pruebas de independencia muestran asociaciones estadísticamente significativas entre las variables tipo de vivienda, zona y estrato socioeconómico (𝑝<0,001 en todos los casos), lo que respalda la aplicación del análisis de correspondencia. La relación más marcada se observa entre zona y estrato (𝜒2=3801,78;𝑉de Cramér = 0,392), evidenciando que la distribución de los estratos presenta una diferenciación territorial importante.
En segundo lugar, tipo de vivienda y zona muestran una asociación de magnitud moderada (𝜒2=688,15; 𝑉=0,289, lo que indica que la presencia relativa de casas y apartamentos varía entre zonas. Finalmente, aunque la relación entre tipo de vivienda y estrato es significativa (𝜒2=215,44;𝑉=0,162), su intensidad es débil, por lo que el estrato explica solo parcialmente la composición de la oferta por tipo de inmueble.
En conjunto, los resultados sugieren una estructura socioespacial del mercado inmobiliario, donde la localización se asocia más fuertemente con el estrato que con el tipo de vivienda.
Ahora, ejecutamos el ACM guardando cinco dimensiones para poder revisar la estructura, aunque la presentación se centrará normalmente en las dos primeras.
Varianza explicada. En ACM se usa el término inercia en vez de varianza explicada. Como existen varias categorías, los porcentajes por eje pueden ser menores que en un ACP; por lo que no se usa un umbral rígido como 70%, se recomienda evaluar conjuntamente la inercia, contribuciones y legibilidad de la solución.
fviz_screeplot(
acm_tipo_zona_estrato,
addlabels = TRUE,
ylim = c(0, 100)
) +
labs(
title = "Inercia explicada por las dimensiones del ACM",
x = "Dimensión",
y = "Porcentaje de inercia"
)
Gráfico 33. Inercia explicada por las dimensiones del ACM
El análisis de valores propios (Gráfico 33) muestra que la estructura de asociación entre las variables categóricas se distribuye en varias dimensiones. La primera dimensión explica el 21,05% de la inercia total y la segunda aporta un 17,00% adicional, de modo que el plano factorial Dimensión 1–Dimensión 2 resume el 38,05% de la información asociativa.
Aunque este porcentaje permite identificar las principales tendencias y visualizar las asociaciones más relevantes entre categorías, no representa la totalidad de la estructura observada. Al incorporar la tercera dimensión, la inercia acumulada asciende a 52,32%, y las cinco primeras dimensiones explican en conjunto el 76,99%.
En consecuencia, el mapa bidimensional debe utilizarse como una aproximación exploratoria, complementándolo con el análisis de contribuciones y calidad de representación de las categorías para interpretar adecuadamente los ejes factoriales.
Visualización principal: mapa de categorías Este es el gráfico principal. Cada etiqueta corresponde a una categoría concreta: por ejemplo, tipo_casa, zona_sur o estrato_6.
fviz_mca_var(
acm_tipo_zona_estrato,
repel = TRUE,
col.var = "contrib",
gradient.cols = c("#457B9D", "#F4A261", "#D62828")
) +
labs(
title = "Patrones de oferta según tipo, zona y estrato",
subtitle = "Análisis de Correspondencia Múltiple",
color = "Contribución"
)
Gráfico 34. Patrones de oferta según tipo, zona y estrato
El Gráfico 34 confirma que la mayor heterogeneidad de la oferta inmobiliaria se explica por la estructura territorial de los estratos. Se distinguen, de manera exploratoria, tres configuraciones principales: un perfil asociado con occidente y estrato 6; otro vinculado con sur y estratos 4–5; y un tercero relacionado con centro-oriente y estrato 3.
El tipo de vivienda no define por sí mismo estos patrones, pues casas y apartamentos se ubican cerca del centro del plano y muestran una diferenciación limitada. Dado que el gráfico representa solo el 38,1% de la inercia, estas asociaciones deben complementarse con las contribucionesy las dimensiones posteriores antes de establecer conclusiones definitivas.
Contribuciones a Dimensión 1 y 2
fviz_contrib(
acm_tipo_zona_estrato,
choice = "var",
axes = 1,
top = 15
) +
labs(
title = "Categorías que más contribuyen a la Dimensión 1"
)
Gráfico 35A. Categorías que más contribuyen a la Dimensión
1
fviz_contrib(
acm_tipo_zona_estrato,
choice = "var",
axes = 2,
top = 15
) +
labs(
title = "Categorías que más contribuyen a la Dimensión 2"
)
Gráfico 35B. Categorías que más contribuyen a la Dimensión
2
Los Gráficos 35A y 35B muestra que las dos primeras dimensiones del Análisis de Correspondencia Múltiple están determinadas principalmente por la estructura territorial de los estratos socioeconómicos y no por el tipo de vivienda. La Dimensión 1 se explica principalmente por el estrato 3 y la zona oriente, seguidos por la zona oeste, las casas y el estrato 6, configurando una diferenciación entre el perfil oriente–estrato 3 y el patrón asociado con occidente–estrato 6.
Por su parte, la Dimensión 2 está dominada por la zona oeste y el estrato 6, con aportes adicionales del estrato 4 y de la zona sur, lo que contrapone el perfil occidente–estrato 6 frente al perfil sur–estrato 4. La baja contribución de casa y apartamento, particularmente en la segunda dimensión, confirma que la principal fuente de heterogeneidad de la oferta inmobiliaria se encuentra en la relación entre localización y estrato socioeconómico.
contrib_dim1 <- as.data.frame(
acm_tipo_zona_estrato$var$contrib[, 1]
) %>%
tibble::rownames_to_column("categoria") %>%
rename(contribucion_dim1 = 2) %>%
arrange(desc(contribucion_dim1))
contrib_dim2 <- as.data.frame(
acm_tipo_zona_estrato$var$contrib[, 2]
) %>%
tibble::rownames_to_column("categoria") %>%
rename(contribucion_dim2 = 2) %>%
arrange(desc(contribucion_dim2))
cos2_dim1 <- as.data.frame(
acm_tipo_zona_estrato$var$cos2[, 1]
) %>%
tibble::rownames_to_column("categoria") %>%
rename(cos2_dim1 = 2)
cos2_dim2 <- as.data.frame(
acm_tipo_zona_estrato$var$cos2[, 2]
) %>%
tibble::rownames_to_column("categoria") %>%
rename(cos2_dim2 = 2)
resumen_categorias_acm <- contrib_dim1 %>%
full_join(contrib_dim2, by = "categoria") %>%
full_join(cos2_dim1, by = "categoria") %>%
full_join(cos2_dim2, by = "categoria") %>%
mutate(
contribucion_total_12 =
contribucion_dim1 + contribucion_dim2,
cos2_total_12 =
cos2_dim1 + cos2_dim2
) %>%
arrange(desc(contribucion_total_12))
resumen_categorias_acmTabla 20. Contribuciones y cos2
La Tabla 20 muestra que el análisis de contribuciones y calidad de representación confirma que las dos primeras dimensiones del Análisis de Correspondencia Múltiple están definidas principalmente por la relación entre zona geográfica y estrato socioeconómico. La Dimensión 1 es construida fundamentalmente por el estrato 3 (30,65%) y la zona oriente (23,82%), mientras que la Dimensión 2 está dominada por la zona oeste (32,75%) y el estrato 6 (23,53%). Estas cuatro categorías presentan, además, una buena representación en el plano factorial, con valores de cos2 acumulado entre 0,51 y 0,71, lo que respalda la interpretación de los perfiles oriente–estrato 3 y occidente–estrato 6.
El estrato 4 y la zona sur contribuyen a la segunda dimensión, pero su representación es moderada, por lo que su asociación debe entenderse como una tendencia exploratoria. En contraste, casa, apartamento, zona norte, zona centro y estrato 5 muestran aportes y valores de cos2 reducidos, indicando que su comportamiento se explica parcialmente en dimensiones posteriores y que el tipo de vivienda no es el principal factor de diferenciación de la oferta en el plano analizado.
ggplot(
individuos_acm_muestra,
aes(
x = Dim1,
y = Dim2,
color = zona
)
) +
geom_point(alpha = 0.25, size = 0.9) +
stat_ellipse(
aes(group = zona),
linewidth = 0.8,
linetype = 2
) +
scale_color_viridis_d() +
labs(
title = "Inmuebles proyectados en las dos primeras dimensiones del ACM",
subtitle = "Muestra aleatoria para visualización; color según zona",
x = "Dimensión 1",
y = "Dimensión 2",
color = "Zona"
) +
theme_minimal()
Gráfico 36. Inmuebles proyectados en la dos primeras dimensiones del
ACM
La proyección de los inmuebles en las dos primeras dimensiones del Análisis de Correspondencia Múltiple evidencia patrones territoriales diferenciados, aunque con distintos niveles de definición. Las zonas occidente y oriente presentan agrupamientos relativamente compactos y separados del resto, confirmando su papel central en la construcción de las dimensiones factoriales: occidente se diferencia principalmente en la segunda dimensión y oriente en la primera.
La zona centro también aparece concentrada y próxima al perfil de oriente, pero esta interpretación debe asumirse con cautela debido a su baja calidad de representación en el plano. En contraste, las zonas norte y sur exhiben una mayor dispersión y una superposición considerable, lo que indica heterogeneidad interna y similitudes parciales en la combinación de tipo de vivienda y estrato. El Gráfico 36 refuerza que la oferta inmobiliaria presenta una estructura territorial, aunque el plano Dimensión 1–Dimensión 2, que resume el 38,05% de la inercia, no captura toda la variabilidad entre zonas.
inercia_larga <- tabla_inercia %>%
mutate(
dimension = factor(
dimension,
levels = dimension
)
) %>%
pivot_longer(
cols = c(
inercia_pct,
inercia_acumulada_pct
),
names_to = "medida",
values_to = "porcentaje"
)
ggplot(
inercia_larga,
aes(
x = dimension,
y = porcentaje,
group = medida,
color = medida
)
) +
geom_line(linewidth = 1) +
geom_point(size = 2.5) +
scale_color_manual(
values = c(
"inercia_pct" = "#457B9D",
"inercia_acumulada_pct" = "#E76F51"
),
labels = c(
"Inercia por dimensión",
"Inercia acumulada"
)
) +
labs(
title = "Inercia individual y acumulada del ACM",
x = "Dimensión",
y = "Porcentaje (%)",
color = NULL
)
Gráfico 37. Inercia individual y acumulada del ACM
El Gráfico 37 muestra que la estructura asociativa del Análisis de Correspondencia Múltiple se distribuye de manera gradual entre varias dimensiones: la Dimensión 1 explica cerca del 21,1% de la inercia, la Dimensión 2 aporta 17,0% adicional y ambas acumulan 38,1%, proporción suficiente para identificar los patrones territoriales y socioeconómicos principales, pero insuficiente para resumir por completo la heterogeneidad de la oferta inmobiliaria.
Al incorporar la tercera dimensión, la inercia acumulada supera el 52%, y con cinco dimensiones alcanza aproximadamente 77%, evidenciando que no existe un único eje dominante, sino varias fuentes complementarias de asociación entre zona, estrato y tipo de vivienda. En consecuencia, el plano Dimensión 1–Dimensión 2 debe interpretarse como una representación exploratoria de las tendencias más relevantes —especialmente los contrastes entre oriente–estrato 3, occidente–estrato 6 y sur–estrato 4—, mientras que una caracterización integral requiere considerar dimensiones posteriores.
Análisis de Componentes Principales (ACP). El ACP evidenció que la variabilidad de los inmuebles se concentra principalmente en un eje de escala y valor residencial, en el que precio, área construida, número de habitaciones y baños tienden a aumentar conjuntamente. Esto indica que el mercado no está compuesto por atributos aislados: los inmuebles más grandes y mejor dotados suelen tener precios más elevados. La reducción de dimensionalidad permite, por tanto, resumir la heterogeneidad cuantitativa del mercado en pocos factores, distinguiendo principalmente entre viviendas compactas y de menor valor relativo, inmuebles de alta gama y viviendas amplias orientadas a familias.
Análisis de conglomerados. La segmentación mediante k-means identificó tres perfiles inmobiliarios interpretables: un grupo mayoritario de viviendas compactas y de menor valor relativo, compuesto principalmente por apartamentos; un segmento de alta gama, con mayor precio, área, número de baños y estrato, que incluye tanto casas como apartamentos; y un tercer grupo de casas amplias, con muchas habitaciones y baños, orientadas a uso familiar. La presencia de patrones espaciales diferenciados, pese a que las coordenadas no se usaron para formar los grupos, respalda que la segmentación refleja una heterogeneidad real del mercado y no únicamente diferencias numéricas entre observaciones.
Análisis de Correspondencia Múltiple (ACM). El ACM mostró que las asociaciones entre variables categóricas están determinadas principalmente por la relación entre zona y estrato socioeconómico, más que por el tipo de vivienda. Los perfiles más visibles fueron la asociación relativa entre oriente y estrato 3, occidente y estrato 6, y sur y estrato 4; mientras tanto, casas y apartamentos aportaron menos a la diferenciación en las primeras dimensiones. Aunque el plano Dimensión 1–Dimensión 2 resume el 38,05% de la inercia y debe interpretarse de forma exploratoria, confirma que la estructura del mercado inmobiliario posee una marcada dimensión territorial y socioeconómica.
Notas de clase (2026). Curso de Modelos Estadísticos para la toma de decisiones. Brigthspace. Maestría en Ciencia de Datos, PUJ
Perplexity AI. (2026). Asesoría metodológica e interpretación de resultados para análisis multivariado de datos inmobiliarios [Chat de inteligencia artificial]. Perplexity.
Greenacre, M. (2017). Correspondence analysis in practice (3rd ed.). Chapman and Hall/CRC.
Husson, F., Lê, S., & Pagès, J. (2017). Exploratory multivariate analysis by example using R (2nd ed.). Chapman and Hall/CRC.
Jolliffe, I. T., & Cadima, J. (2016). Principal component analysis: A review and recent developments. Philosophical Transactions of the Royal Society A: Mathematical, Physical and Engineering Sciences, 374(2065), 20150202. https://doi.org/10.1098/rsta.2015.0202
Kaufman, L., & Rousseeuw, P. J. (2009). Finding groups in data: An introduction to cluster analysis. John Wiley & Sons.
Rousseeuw, P. J. (1987). Silhouettes: A graphical aid to the interpretation and validation of cluster analysis. Journal of Computational and Applied Mathematics, 20, 53–65. https://doi.org/10.1016/0377-0427(87)90125-7