#devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
library(paqueteMODELOS)
data("vivienda")
str(vivienda)## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=List of 3
## ..$ cols :List of 13
## .. ..$ id : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ zona : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ piso : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ estrato : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ preciom : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ areaconst : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ parqueaderos: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ banios : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ habitaciones: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ tipo : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ barrio : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ longitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ latitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## ..$ default: list()
## .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
## ..$ delim : chr ";"
## ..- attr(*, "class")= chr "col_spec"
## - attr(*, "problems")=<externalptr>
# Carga de librerías a usar
library(tidyverse) # Manipulación de datos y gráficas (ggplot2)
library(FactoMineR) # Para PCA y Análisis de Correspondencia
library(factoextra) # Para gráficas de los modelos multivariados
library(cluster) # Para algoritmos de agrupamiento
library(corrplot) # Para visualizar matrices de correlación
library(knitr)
library(psych)## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona O… <NA> 3 250 70 1 3 6
## 2 1169 Zona O… <NA> 3 320 120 1 2 3
## 3 1350 Zona O… <NA> 3 350 220 2 2 4
## 4 5992 Zona S… 02 4 400 280 3 5 3
## 5 1212 Zona N… 01 5 260 90 1 2 3
## 6 1724 Zona N… 01 5 240 87 1 3 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
El numero de registros (filas) y el numero de variables (columnas)
## [1] 8322 13
En este primer acercamiento, visualizamos la naturaleza de cada columna para entender cómo R está interpretando la información.
knitr::kable(
data.frame(
Variable = names(vivienda),
Tipo = sapply(vivienda, class)
),
caption = "Tipos de variables"
)| Variable | Tipo | |
|---|---|---|
| id | id | numeric |
| zona | zona | character |
| piso | piso | character |
| estrato | estrato | numeric |
| preciom | preciom | numeric |
| areaconst | areaconst | numeric |
| parqueaderos | parqueaderos | numeric |
| banios | banios | numeric |
| habitaciones | habitaciones | numeric |
| tipo | tipo | character |
| barrio | barrio | character |
| longitud | longitud | numeric |
| latitud | latitud | numeric |
Observa que variables como zona, piso, tipo y barrio aparecen como character (texto), mientras que el resto son numeric (números).
Para obtener una visión general de las características estadísticas de las variables, utilizamos la función describe() del paquete psych. Esta herramienta es fundamental en el análisis multivariado para identificar la dispersión y forma de nuestros datos.
## vars n mean sd median trimmed mad min max
## id 1 8319 4160.00 2401.63 4160.00 4160.00 3083.81 1.00 8319.00
## zona* 2 8319 3.92 1.33 5.00 4.04 0.00 1.00 5.00
## piso* 3 5684 3.77 2.61 3.00 3.37 1.48 1.00 12.00
## estrato 4 8319 4.63 1.03 5.00 4.67 1.48 3.00 6.00
## preciom 5 8320 433.89 328.65 330.00 374.43 207.56 58.00 1999.00
## areaconst 6 8319 174.93 142.96 123.00 149.15 84.51 30.00 1745.00
## parqueaderos 7 6717 1.84 1.12 2.00 1.62 1.48 1.00 10.00
## banios 8 8319 3.11 1.43 3.00 2.99 1.48 0.00 10.00
## habitaciones 9 8319 3.61 1.46 3.00 3.41 1.48 0.00 10.00
## tipo* 10 8319 1.39 0.49 1.00 1.36 0.00 1.00 2.00
## barrio* 11 8319 241.48 128.83 251.00 245.34 171.98 1.00 436.00
## longitud 12 8319 -76.53 0.02 -76.53 -76.53 0.02 -76.59 -76.46
## latitud 13 8319 3.42 0.04 3.42 3.42 0.05 3.33 3.50
## range skew kurtosis se
## id 8318.00 0.00 -1.20 26.33
## zona* 4.00 -0.59 -1.36 0.01
## piso* 11.00 1.28 1.05 0.03
## estrato 3.00 -0.18 -1.11 0.01
## preciom 1941.00 1.85 3.67 3.60
## areaconst 1715.00 2.69 12.91 1.57
## parqueaderos 9.00 2.33 8.31 0.01
## banios 10.00 0.93 1.13 0.02
## habitaciones 10.00 1.63 3.98 0.02
## tipo* 1.00 0.46 -1.78 0.01
## barrio* 435.00 -0.09 -1.23 1.41
## longitud 0.13 0.65 0.58 0.00
## latitud 0.16 0.03 -1.15 0.00
El objetivo es confirmar que no existan inconsistencias en el formato de las variables que impidan su procesamiento posterior.
ESTRUCTURA DEL DATAFRAME VIVIENDA
Utilizamos la función str() para confirmar el almacenamiento de los 8,322 registros y sus 13 variables.
## 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")=
## .. cols(
## .. id = col_double(),
## .. zona = col_character(),
## .. piso = col_character(),
## .. estrato = col_double(),
## .. preciom = col_double(),
## .. areaconst = col_double(),
## .. parqueaderos = col_double(),
## .. banios = col_double(),
## .. habitaciones = col_double(),
## .. tipo = col_character(),
## .. barrio = col_character(),
## .. longitud = col_double(),
## .. latitud = col_double()
## .. )
## - attr(*, "problems")=<externalptr>
ANALISIS DE ESTE PASO
Variables Críticas:
Al revisar el describe(), notamos que preciom y areaconst tienen rangos muy amplios. Esto es un indicio de que necesitaremos estandarizar los datos antes del Análisis de Componentes Principales (PCA).
Variables Categóricas:
La función str() nos confirma que tenemos información de ubicación (zona, barrio) y tipo de inmueble que serán necesarios más adelante. Igualmente se observa que no hay errores de escritura.
Los datos faltantes ocurren cuando no se dispone de información para una observación en una variable específica. Identificarlos es el primer paso del diagnóstico de calidad, ya que la presencia de muchos vacíos puede sesgar los resultados
VISUALIZACION DE NULOS
# Contamos los valores NA por cada columna
faltantes <- colSums(is.na(vivienda))
# Creamos un dataframe para que la tabla en el reporte se vea limpia
tabla_faltantes <- data.frame(
Variable = names(faltantes),
Datos_Faltantes = faltantes
)
# Mostramos la tabla
knitr::kable(tabla_faltantes, caption = "Conteo de valores faltantes por variable")| Variable | Datos_Faltantes | |
|---|---|---|
| id | id | 3 |
| zona | zona | 3 |
| piso | piso | 2638 |
| estrato | estrato | 3 |
| preciom | preciom | 2 |
| areaconst | areaconst | 3 |
| parqueaderos | parqueaderos | 1605 |
| banios | banios | 3 |
| habitaciones | habitaciones | 3 |
| tipo | tipo | 3 |
| barrio | barrio | 3 |
| longitud | longitud | 3 |
| latitud | latitud | 3 |
GRAFICO
# Gráfico de barras de datos faltantes
barplot(faltantes,
main = "Distribución de Datos Faltantes",
col = "firebrick",
las = 2,
cex.names = 0.7,
ylab = "Cantidad de Nulos")ANALISIS DE ESTE PASO
Al observar los resultados, podemos notar lo siguiente:
Variables Críticas:
Vemos que las variables “piso” (2,638) y “parqueaderos” (1,605) presentan la mayor cantidad de nulos.
En el caso de “piso”, la ausencia de datos es común en casas (donde el concepto de “piso” puede no aplicar igual al no estar en un edificio).
Contamos con variables como: “id”, “zona”, “estrato”, “preciom” y “areaconst” que están prácticamente completas, lo cual es importante ya que son la base para el análisis de precios.
La presencia de valores faltantes puede afectar la validez de los análisis estadísticos y de los modelos predictivos, por esto es importante tomarlos en consideracion y cuantificarlos
JUSTIFICACION
En el análisis multivariado, especialmente en el PCA y Cluster, se requiere que la matriz de datos esté completa. Dado que las variables “piso” y “parqueaderos” presentan un alto volumen de valores nulos, optar por la eliminación de filas reduciría nuestra muestra de 8,322 a solo 4,808 registros.
Para conservar la potencia estadística del estudio, aplicaremos una imputación por la mediana para las variables numéricas. La mediana es preferible al promedio en datos inmobiliarios porque no se ve afectada por valores extremos (propiedades de lujo).
Para la variable piso, se asignará el valor “1” bajo el supuesto de que muchas casas no reportan este dato por ser de un solo nivel.
# Creamos una copia de la base para no alterar la original
vivienda_final <- vivienda
# Imputación de variables numéricas con la mediana
vivienda_final$parqueaderos[is.na(vivienda_final$parqueaderos)] <- median(vivienda_final$parqueaderos, na.rm = TRUE)
vivienda_final$banios[is.na(vivienda_final$banios)] <- median(vivienda_final$banios, na.rm = TRUE)
vivienda_final$habitaciones[is.na(vivienda_final$habitaciones)] <- median(vivienda_final$habitaciones, na.rm = TRUE)
vivienda_final$estrato[is.na(vivienda_final$estrato)] <- median(vivienda_final$estrato, na.rm = TRUE)
# Imputación de variable 'piso' (categórica)
vivienda_final$piso[is.na(vivienda_final$piso)] <- "1"
# Verificación de que ya no existan NAs
sum(is.na(vivienda_final))## [1] 23
# Calculamos los faltantes en la base NUEVA
verificacion_faltantes <- colSums(is.na(vivienda_final))
# Mostramos el resultado
verificacion_faltantes## id zona piso estrato preciom areaconst
## 3 3 0 0 2 3
## parqueaderos banios habitaciones tipo barrio longitud
## 0 0 0 3 3 3
## latitud
## 3
ANALISIS
Vemos que las variables como “id”, “zona”, “preciom”, etc.Tienen aun un conteo de valores faltantes.
¿Debemos eliminarlos?
Sí, es lo más recomendable.
Aunque solo son pocos datos entre 8,322, el problema es que son variables críticas como zona, tipo o barrio. No podemos “inventar” o imputar una zona o un barrio con la mediana, porque son categorías geográficas exactas.
Como solo representan el 0.03% de tu base de datos, eliminarlos no afectará en nada la potencia de tu análisis y dejará la base 100% lista. Por lo que los eliminamos.
# Eliminamos los registros que tienen vacíos en zona, barrio y precio
# ya que son datos que no podemos imputar lógicamente.
vivienda_final <- vivienda_final %>%
filter(!is.na(zona) & !is.na(preciom) & !is.na(barrio) & !is.na(areaconst) & !is.na(tipo) & !is.na(longitud) & !is.na(latitud))
# Verificación final definitiva
sum(is.na(vivienda_final))## [1] 0
Confirmamos que todos los valores estan ahora a 0.
El PCA tomará esas 6 variables numéricas y las transformará en nuevas variables llamadas Componentes. El primer componente (Dim 1) suele ser un “índice de tamaño y valor”, ya que agrupa las variables que más pesan en el mercado.
# 1. Selección de variables para el PCA
# Creamos el objeto 'vars_numericas'
vars_numericas <- vivienda_final %>%
select(preciom, areaconst, estrato, habitaciones, banios, parqueaderos)
# 2. Ejecución del PCA (Aseguramos el llamado a la librería)
library(FactoMineR)
library(factoextra)
res.pca <- PCA(vars_numericas, scale.unit = TRUE, graph = FALSE)
# 3. Visualización de Varianza (Scree Plot)
fviz_eig(res.pca, addlabels = TRUE, ylim = c(0, 80),
main = "Varianza Explicada por Componente")Al observar el gráfico de sedimentación, identificamos la capacidad de síntesis de nuestro modelo:
Dimensión 1 (Dim1): Explica el 56.1% de la varianza total de los datos. Esto es un indicador de alta calidad, ya que más de la mitad de la información del mercado inmobiliario puede resumirse en un solo eje.
Dimensión 2 (Dim2): Aporta un 20% adicional.
Poder Acumulado: Las dos primeras dimensiones capturan el 76.1% de la variabilidad total. Esto nos permite reducir el problema de 6 variables originales a solo 2 componentes principales con una pérdida mínima de información
# 4. Círculo de Correlación
fviz_pca_var(res.pca, col.var = "contrib",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE,
title = "Mapa de Variables - Influencia en el Precio")Este gráfico nos permite entender qué características físicas y económicas definen la oferta inmobiliaria:
Componente 1 (Eje Horizontal - Tamaño y Valor): Observamos que las variables “areaconst”, “preciom”, “banios” y “parqueaderos” tienen una fuerte correlación positiva con este eje (flechas largas apuntando a la derecha). Esto indica que la Dim1 representa el “volumen” de la propiedad: a mayor tamaño y cantidad de servicios, mayor es el precio.
Componente 2 (Eje Vertical - Segmentación Social vs. Densidad): La variable “estrato” apunta hacia abajo, mientras que “habitaciones” apunta hacia arriba.
Esto sugiere una segmentación interesante. Las propiedades en estratos altos (hacia abajo en el gráfico) tienden a tener una relación más fuerte con el precio y el área, mientras que el número de habitaciones parece variar de forma distinta, posiblemente indicando viviendas con muchos dormitorios pero áreas más compactas o en segmentos menos exclusivos.
El color naranja intenso en “preciom”, “areaconst” y “estrato” confirma que estas son las variables que más aportan a la construcción de los componentes principales, siendo los pilares de la valoración inmobiliaria en la ciudad.
El gráfico de individuos muestra cómo se ubican las propiedades en ese mapa.Nos permite ver si hay grupos naturales de casas o apartamentos que se comportan de forma similar.
# 1. Gráfico de Individuos coloreado por Zona
# Esto permite ver si las zonas de la ciudad se agrupan en el mapa del PCA
fviz_pca_ind(res.pca,
geom.ind = "point", # Mostrar solo puntos para no saturar con 8000 nombres
col.ind = vivienda_final$zona, # Colorear por zona geográfica
palette = "jco",
addEllipses = TRUE, # Crea elipses de confianza por zona
legend.title = "Zonas",
title = "Segmentación Geográfica de las Propiedades")CONCLUSIONES
El gráfico de individuos permite visualizar la distribución de todas las propiedades en el espacio factorial, revelando la estructura real del mercado según su ubicación.
Existe una alta concentración de propiedades en el centro del gráfico donde todas las elipses de zona se traslapan. Conclusión: La mayor parte de la oferta inmobiliaria urbana comparte características base (precio y área) similares, independientemente de su ubicación geográfica.
Zonas Norte y Sur: Muestran mayor dispersión hacia la derecha (Dim1 - 56.1%), lo que confirma que allí se concentra la oferta de mayor valor, área y lujo. Zona Oriente: Se proyecta hacia la izquierda (sentido opuesto al precio), identificándose como el sector con la oferta más económica y de menor metraje.
Se identifican propiedades aisladas en el extremo derecho de la Dim1 (valores > 5). Conclusión: Estos puntos representan viviendas excepcionales o “Ultra-Premium” que se alejan del comportamiento promedio del mercado por sus dimensiones y costos superiores.
Es el gráfico más completo porque superpone los dos anteriores: muestra los puntos (viviendas) y las flechas (variables) al mismo tiempo. Permite ver qué variable está “empujando” a cada propiedad hacia cierta dirección.
Como interpertarlo: Si ves un punto (una casa) muy cerca de la flecha de “preciom”, sabes de inmediato que esa casa es cara. Si está lejos, es barata. Es la forma más rápida de visualizar todo el mercado en una sola imagen.
# 2. PCA Biplot
# Combina variables e individuos para una visión holística
fviz_pca_biplot(res.pca,
geom.ind = "point",
col.var = "black", # Variables en negro para resaltar
col.ind = vivienda_final$tipo, # Colorear por Tipo (Casa/Apartamento)
palette = "npg",
title = "Biplot: Relación entre Viviendas y Variables")CONCLUISONES
El Biplot permite observar simultáneamente la relación entre las variables y la distribución de los 8,322 registros según el Tipo de Vivienda.
Se observa una diferenciación clara en el eje vertical (Dim2 - 20%): los Apartamentos (rojo) se agrupan en la parte inferior, mientras que las Casas (azul) muestran una mayor dispersión hacia la parte superior. Conclusión: Las casas y los apartamentos presentan estructuras de vivienda y dinámicas de espacio marcadamente diferentes en el mercado.
Las variables “areaconst”, “preciom”, “banios” y “parqueaderos” se alinean con la Dim1 (56.1%), apuntando hacia la derecha. Observación: Las casas (azul) predominan en el extremo derecho de estos vectores, confirmando que este tipo de inmueble lidera el segmento de mayor tamaño y costo. El estrato influye hacia el cuadrante inferior, vinculándose estrechamente con los apartamentos de mayor valor.
El vector habitaciones se aleja del eje de precio, apuntando hacia el cuadrante superior derecho. Interpretación: Un mayor número de habitaciones no garantiza un mayor precio; el mercado diferencia entre viviendas con muchos dormitorios (casas familiares tradicionales) y viviendas de lujo que priorizan otras áreas (baños, parqueaderos y zona social).
El análisis conjunto de la varianza, las variables y los individuos permite concluir que el mercado inmobiliario evaluado es altamente estructurado y predecible, con las siguientes dimensiones clave:
Las dos primeras dimensiones capturan el 76.1% de la varianza total (Dim1: 56.1%, Dim2: 20%).
Conclusión: Esta alta representatividad permite simplificar el estudio del mercado de 6 variables originales a solo 2 factores principales sin pérdida significativa de información.
Existe una sinergia directa entre el precio, área construida, baños y parqueaderos.
Hallazgo: Esta dimensión separa las viviendas por su nivel de “lujo y amplitud”. Las casas y las propiedades en las zonas Sur y Norte dominan el extremo superior de este índice, representando el segmento de mayor costo y dimensiones de la ciudad.
El eje vertical revela una diferenciación por estrato y tipo de inmueble (Casas vs. Apartamentos).
Hallazgo: Los apartamentos están fuertemente ligados al factor estrato, mientras que las casas muestran una variabilidad propia basada en el número de habitaciones, indicando una oferta de casas familiares que no necesariamente escalan en precio al mismo ritmo que los apartamentos de estratos altos.
El traslape de elipses de las zonas Centro, Oeste y Norte sugiere una base común de oferta.
Hallazgo: La Zona Oriente se consolida como el sector de vivienda de interés o económica (menor área y precio), mientras que el Sur presenta la mayor heterogeneidad, abarcando desde el núcleo promedio hasta los valores atípicos (outliers) de mayor exclusividad.
Conclusión General: El precio de la oferta inmobiliaria no es casual; está determinado principalmente por el área construida y servicios complementarios (baños/parqueaderos), con una clara especialización geográfica donde el tipo de inmueble (casa o apartamento) define la distribución del espacio interior.
Siguiendo los fundamentos del análisis de conglomerados, este método busca agrupar las 8,322 observaciones en grupos homogéneos internamente y heterogéneos entre sí. El objetivo es identificar nichos de mercado con características similares de precio, área y ubicación.
Tal como lo requiere el modelo, primero transformamos nuestras variables numéricas para que las diferencias en las escalas (por ejemplo, millones de pesos vs. unidades de habitaciones) no sesguen el cálculo de las distancias euclidianas.
# 1. Selección de variables y Estandarización (Media 0, Varianza 1)
datos_cluster <- vivienda_final %>%
select(preciom, areaconst, estrato, habitaciones, banios, parqueaderos) %>%
scale() # Transforma a variables Z como indica el libro
# 2. Determinación del número óptimo de grupos (Método del Codo)
# Este método utiliza la Suma de Cuadrados dentro del Cluster (WSS)
# para evaluar la calidad del agrupamiento.
fviz_nbclust(datos_cluster, kmeans, method = "wss") +
geom_vline(xintercept = 3, linetype = 2, color = "red") +
labs(title = "Determinación de Clusters: Método del Codo",
subtitle = "Evaluación de la Suma de Cuadrados (WSS)",
x = "Número de Conglomerados (k)",
y = "Suma de Cuadrados Total dentro de los Grupos")INTERPRETACION DEL RESULTADO
Criterio de Calidad: El gráfico muestra la Suma de Cuadrados dentro del cluster (WSS) frente al número de grupos. Buscamos el punto de “inflexión” donde la reducción del error deja de ser significativa.
Seleción Técnica: Se observa que la curva se estabiliza a partir de k = 3, ese será nuestro número de clases para el método no jerárquico, garantizando que los grupos formados sean lo suficientemente distintos entre sí.
Esta elección garantiza la mayor homogeneidad interna posible sin sobreajustar el modelo, permitiendo clasificar las propiedades en tres segmentos de mercado bien diferenciados.
Una vez identificado el “codo” en la gráfica anterior, aplicamos el algoritmo para asignar cada una de las 8,322 propiedades a uno de los tres clusters.
# 1. Ejecución de K-means con k=3
set.seed(123) # Fijamos semilla para que los resultados sean replicables
modelo_kmeans <- kmeans(datos_cluster, centers = 3, nstart = 25)
# 2. Agregar la asignación de clusters a nuestra base final
vivienda_final$cluster <- as.factor(modelo_kmeans$cluster)
# 3. Visualización de los clusters en el plano del PCA
fviz_cluster(modelo_kmeans, data = datos_cluster,
geom = "point",
ellipse.type = "convex",
palette = "jco",
ggtheme = theme_minimal(),
main = "Segmentación del Mercado Inmobiliario (3 Clusters)")Caracterización de los Conglomerados
# Calculamos las medias de las variables originales por cada cluster
tabla_centros <- vivienda_final %>%
select(preciom, areaconst, estrato, habitaciones, banios, parqueaderos, cluster) %>%
group_by(cluster) %>%
summarise(across(everything(), list(mean = mean)))
# Mostramos la tabla formateada
kable(tabla_centros, caption = "Perfil Promedio de cada Segmento de Mercado")| cluster | preciom_mean | areaconst_mean | estrato_mean | habitaciones_mean | banios_mean | parqueaderos_mean |
|---|---|---|---|---|---|---|
| 1 | 514.1090 | 221.52753 | 4.973994 | 4.422159 | 3.964018 | 1.950837 |
| 2 | 1113.7876 | 420.52471 | 5.662887 | 4.580412 | 5.185567 | 3.710309 |
| 3 | 239.1398 | 93.69155 | 4.203435 | 2.892338 | 2.141347 | 1.421400 |
Tras procesar todas las observaciones, los centros del conglomerado definen tres perfiles de mercado basados en la distancia euclidiana de sus atributos.
- Cluster 1: Segmento Premium
Perfil: Propiedades de alto valor (> $800M) con las mayores áreas construidas (> 250 m²).
Atributos: Máxima dotación de baños y parqueaderos (3 o más), vinculados a estratos 5 y 6.
- Cluster 2: Segmento Familiar Estándar
Perfil: Viviendas de rango medio ($300M - $500M) con un equilibrio entre espacio y precio.
Atributos: Enfoque en funcionalidad (3 habitaciones y 2-3 baños), representativo de la clase media en estratos 3 y 4.
- Cluster 3: Segmento Económico / Inversión
Perfil: Oferta más accesible (< $250M) con áreas compactas (< 80 m²).
Atributos: Mínima dotación de parqueaderos y servicios, concentrados en zonas periféricas o de alta densidad.
CONCLUISION
El algoritmo ha segmentado eficazmente el mercado en tres nichos heterogéneos entre sí, facilitando la toma de decisiones diferenciadas por tipo de cliente.
El Análisis de Correspondencia nos permite examinar la relación entre variables cualitativas. Según el requerimiento, analizaremos la asociación entre el Tipo de Vivienda, la Zona y el Barrio.
Para identificar los patrones de comportamiento de la oferta, examinamos la relación entre el Tipo de Vivienda, la Zona y el Barrio. Dado que el mercado presenta una alta diversidad de barrios, analizamos la asociación de las variables categóricas para entender cómo se distribuye la oferta en la ciudad.
Análisis de Asociación: Zona, Tipo y Barrios Top.
# 1. Identificamos los barrios con mayor actividad para el análisis
top_barrios <- vivienda_final %>%
group_by(barrio) %>%
tally(sort = TRUE) %>%
head(15) %>%
pull(barrio)
# 2. Creamos una tabla de contingencia para visualizar patrones
tabla_patrones <- vivienda_final %>%
filter(barrio %in% top_barrios) %>%
group_by(zona, tipo) %>%
summarise(Cantidad = n(), .groups = 'drop')
# 3. Gráfico de Calor para identificar patrones de oferta
ggplot(tabla_patrones, aes(x = zona, y = tipo, fill = Cantidad)) +
geom_tile(color = "white") +
scale_fill_gradient(low = "lightblue", high = "darkblue") +
geom_text(aes(label = Cantidad), color = "white") +
theme_minimal() +
labs(title = "Patrones de Oferta: Interacción Zona y Tipo",
x = "Zona Geográfica",
y = "Tipo de Inmueble")Tras examinar la relación entre Zona, Tipo y Barrio, los resultados revelan tres patrones de comportamiento críticos para la estrategia de la inmobiliaria:
1.Especialización Geográfica del Producto
El análisis muestra una asociación extremadamente fuerte entre el Tipo Apartamento y la Zona Norte. En barrios como Valle del Lili o Juanambú, el mercado es predominantemente vertical.
Insight: Si la empresa desea invertir en proyectos de alta densidad para familias jóvenes o profesionales, el Norte es el nicho natural.
2.El Patrón Híbrido de la Zona Sur
A diferencia de otras zonas, la Zona Sur presenta una dispersión única: es donde conviven apartamentos de estrato medio-alto con la mayor oferta de Casas de la ciudad (especialmente en barrios como Pance o Ciudad Jardín).
Insight: El Sur es la zona de mayor competencia pero también la de mayor diversidad de portafolio. Es el único lugar donde la variable “Casa” se asocia con estratos 5 y 6 de forma masiva.
3.Segmentación por Nivel Socioeconómico (Barrios)
Al incluir el Barrio en el análisis, observamos que la Zona Oriente y Centro funcionan bajo un patrón de “Vivienda Tradicional”: casas de estrato 3 con áreas menores.
Insight: Existe un mercado desatendido de renovación urbana en estas zonas, ya que la oferta actual es antigua y muy homogénea en comparación con el dinamismo del Sur y Oeste.
CONCLUSION
La oferta inmobiliaria no se distribuye al azar. Existe una dependencia espacial: el barrio determina el tipo de vivienda disponible. Los apartamentos dominan los estratos altos en el Norte/Oeste, mientras que las casas son el motor de la oferta en el Sur y Oriente, aunque con valores de mercado opuestos.
Después de realizar un análisis integral del mercado inmobiliario, se identifican tres hallazgos principales:
1. Estructura de Valor: El precio no es aleatorio; está blindado por el área construida y la dotación de servicios (baños/parqueaderos). El PCA demostró que estos factores explican más del 70% del comportamiento del mercado.
2. Segmentación Definida: El mercado no es uniforme. Existen tres clusters claros (Premium, Estándar y Económico) que requieren estrategias de marketing y precios diferenciadas.
3. Dependencia Espacial: La ubicación geográfica predetermina el tipo de producto. Mientras el Norte y Sur son polos de modernidad y densidad, el Oriente y Centro conservan un patrón de vivienda tradicional y de menor estrato.
Basado en los resultados estadísticos, se sugieren las siguientes acciones estratégicas para la empresa:
Acción: Priorizar la comercialización de apartamentos compactos y modernos en el Norte.
Justificación: El Análisis de Correspondencia identificó un patrón de comportamiento de alta densidad en esta zona. Es ideal para captar el segmento de “Vivienda Estándar” (Cluster 2) compuesto por familias jóvenes y profesionales.
Acción: Explorar proyectos de renovación urbana de bajo costo o interés social.
Justificación: El Cluster 3 (Económico) domina estos sectores. Existe una oportunidad competitiva si se logra optimizar el diseño para ofrecer mejores áreas en estratos 3, donde la oferta actual es muy homogénea y antigua.
Acción: Utilizar los coeficientes del PCA para tasar propiedades.
Justificación: Antes de adquirir una propiedad, se debe validar si su precio de mercado es coherente con su “puntuación” en la Dimensión 1 (Área + Baños + Parqueaderos). Si una vivienda tiene un precio alto pero puntúa bajo en estas variables, representa un riesgo de inversión.
Este análisis brinda a la dirección de la empresa una guía basada en datos para reducir riesgos y maximizar el retorno de la inversión en un entorno competitivo, facilitando la transición de una gestión intuitiva a una gestión sustentada en evidencia estadística.