Este informe presenta un análisis exhaustivo del mercado inmobiliario urbano, basado en una muestra de 8,322 propiedades. Mediante la aplicación de técnicas avanzadas de análisis estadístico y geoespacial, se han identificado patrones críticos de mercado, segmentos específicos de clientes y oportunidades estratégicas de inversión.
Se identificaron cuatro segmentos de mercado claramente diferenciados, con el segmento premium mostrando un diferencial de precio promedio de 900M sobre el segmento estándar.
La Base Aérea Marco Fidel Suárez genera un “anillo de depreciación” que afecta significativamente los valores inmobiliarios en la Zona Centro.
El análisis PCA reveló que el 78.45% de la variabilidad en el mercado puede explicarse por dos factores principales: “tamaño y lujo” (58.1%) y “espacio familiar vs. exclusividad” (20.4%).
La investigación se basa en:
# Cargar librerías necesarias
packages <- c("tidyverse", "magrittr", "dplyr", "FactoMineR", "factoextra",
"ca", "cluster", "leaflet", "corrplot", "missMDA", "VIM",
"htmlwidgets", "webshot")
# Instalar paquetes faltantes
new_packages <- packages[!(packages %in% installed.packages()[,"Package"])]
if(length(new_packages)) install.packages(new_packages)
# Cargar librerías
lapply(packages, require, character.only = TRUE)## [[1]]
## [1] TRUE
##
## [[2]]
## [1] TRUE
##
## [[3]]
## [1] TRUE
##
## [[4]]
## [1] TRUE
##
## [[5]]
## [1] TRUE
##
## [[6]]
## [1] TRUE
##
## [[7]]
## [1] TRUE
##
## [[8]]
## [1] TRUE
##
## [[9]]
## [1] TRUE
##
## [[10]]
## [1] TRUE
##
## [[11]]
## [1] TRUE
##
## [[12]]
## [1] TRUE
##
## [[13]]
## [1] TRUE
# Cargar datos
library(paqueteMODELOS)
data("vivienda")
# Preparación inicial de datos
vivienda_prep <- vivienda %>%
mutate(across(c(zona, tipo, barrio), as.factor),
piso = as.factor(piso)) %>%
mutate(across(c(preciom, areaconst, parqueaderos, banios, habitaciones, estrato), as.numeric))El análisis de datos faltantes revela:
# Visualización de datos faltantes
missing_analysis <- aggr(vivienda_prep, col=c('navyblue','red'), numbers=TRUE,
sortVars=TRUE, labels=names(vivienda_prep), cex.axis=.7,
gap=3, ylab=c("Proporción de NA","Patrón"))##
## Variables sorted by number of missings:
## Variable Count
## piso 0.3169911079
## parqueaderos 0.1928622927
## id 0.0003604903
## zona 0.0003604903
## estrato 0.0003604903
## areaconst 0.0003604903
## banios 0.0003604903
## habitaciones 0.0003604903
## tipo 0.0003604903
## barrio 0.0003604903
## longitud 0.0003604903
## latitud 0.0003604903
## preciom 0.0002403268
# Resumen de datos faltantes
missing_summary <- data.frame(
variable = names(vivienda_prep),
missing_count = colSums(is.na(vivienda_prep)),
missing_percentage = colMeans(is.na(vivienda_prep)) * 100
)
knitr::kable(missing_summary, caption = "Resumen de Datos Faltantes")| variable | missing_count | missing_percentage | |
|---|---|---|---|
| id | id | 3 | 0.0360490 |
| zona | zona | 3 | 0.0360490 |
| piso | piso | 2638 | 31.6991108 |
| estrato | estrato | 3 | 0.0360490 |
| preciom | preciom | 2 | 0.0240327 |
| areaconst | areaconst | 3 | 0.0360490 |
| parqueaderos | parqueaderos | 1605 | 19.2862293 |
| banios | banios | 3 | 0.0360490 |
| habitaciones | habitaciones | 3 | 0.0360490 |
| tipo | tipo | 3 | 0.0360490 |
| barrio | barrio | 3 | 0.0360490 |
| longitud | longitud | 3 | 0.0360490 |
| latitud | latitud | 3 | 0.0360490 |
La distribución de propiedades por zona muestra:
# Estadísticas por zona
stats_zona <- vivienda_prep %>%
group_by(zona) %>%
summarise(
n = n(),
precio_medio = mean(preciom, na.rm = TRUE),
precio_sd = sd(preciom, na.rm = TRUE),
area_media = mean(areaconst, na.rm = TRUE),
estrato_medio = mean(estrato, na.rm = TRUE)
)
knitr::kable(stats_zona, caption = "Estadísticas por Zona")| zona | n | precio_medio | precio_sd | area_media | estrato_medio |
|---|---|---|---|---|---|
| Zona Centro | 124 | 309.6935 | 162.1479 | 194.0424 | 3.201613 |
| Zona Norte | 1920 | 345.6083 | 240.8674 | 161.1222 | 4.281771 |
| Zona Oeste | 1198 | 677.5801 | 391.5828 | 196.3992 | 5.482471 |
| Zona Oriente | 351 | 228.5299 | 122.0641 | 192.3307 | 3.042735 |
| Zona Sur | 4726 | 426.5184 | 322.7229 | 173.3122 | 4.717097 |
| NA | 3 | 330.0000 | NA | NaN | NaN |
# Distribución de precios por zona
ggplot(vivienda_prep, aes(x = zona, y = preciom)) +
geom_boxplot(fill = "lightblue", alpha = 0.7) +
theme_minimal() +
labs(title = "Distribución de Precios por Zona",
x = "Zona",
y = "Precio (Millones)") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))El análisis revela:
# Histograma de precios
ggplot(vivienda_prep, aes(x = preciom)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black") +
theme_minimal() +
labs(title = "Distribución de Precios",
x = "Precio (Millones)",
y = "Frecuencia")# Matriz de correlación
vars_numericas <- vivienda_prep %>%
select(preciom, areaconst, parqueaderos, banios, habitaciones, estrato) %>%
na.omit()
correlation_matrix <- cor(vars_numericas)
corrplot(correlation_matrix, method = "color", type = "upper",
addCoef.col = "black", number.cex = 0.7,
title = "Matriz de Correlación - Variables Numéricas")datos_pca <- vivienda_prep %>%
select(preciom, areaconst, parqueaderos, banios, habitaciones, estrato) %>%
na.omit() %>%
scale()
pca_result <- PCA(datos_pca, graph = FALSE)
# Scree plot
fviz_eig(pca_result, addlabels = TRUE) +
labs(title = "Scree Plot - Varianza Explicada por Componentes")# Biplot
fviz_pca_biplot(pca_result,
col.ind = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE) +
theme_minimal() +
labs(title = "Biplot - Análisis de Componentes Principales")Los resultados del PCA muestran:
set.seed(123)
wss <- sapply(1:10, function(k) {
kmeans(datos_pca, centers = k, nstart = 25)$tot.withinss
})
# Método del codo
ggplot(data.frame(k = 1:10, wss = wss), aes(x = k, y = wss)) +
geom_line() +
geom_point() +
theme_minimal() +
labs(title = "Método del Codo",
x = "Número de Clusters",
y = "Suma de cuadrados dentro de grupos")Se identificaron 4 clusters principales:
# K-means
k <- 4
kmeans_result <- kmeans(datos_pca, centers = k, nstart = 25)
# Visualización de clusters
fviz_cluster(kmeans_result, data = datos_pca,
palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
ggtheme = theme_minimal(),
main = "Clustering de Propiedades")# Asegurarse de que tenemos datos válidos
vivienda_ca <- vivienda_prep %>%
filter(!is.na(zona) & !is.na(tipo))
# Crear tabla de contingencia
cont_table <- table(vivienda_ca$zona, vivienda_ca$tipo)
# Verificar si la tabla tiene suficientes datos para el análisis
if (sum(cont_table) > 0 &&
ncol(cont_table) > 1 &&
nrow(cont_table) > 1 &&
all(rowSums(cont_table) > 0) &&
all(colSums(cont_table) > 0)) {
# Realizar el análisis de correspondencia
tryCatch({
ca_result <- CA(cont_table, graph = FALSE)
# Visualizar solo si el análisis fue exitoso
if (!is.null(ca_result)) {
fviz_ca_biplot(ca_result,
repel = TRUE,
map = "symmetric") +
theme_minimal() +
labs(title = "Análisis de Correspondencia: Zona vs Tipo de Propiedad")
}
}, error = function(e) {
message("No se pudo realizar el análisis de correspondencia: ", e$message)
# Alternativamente, mostrar la tabla de contingencia
print(knitr::kable(cont_table,
caption = "Tabla de contingencia: Zona vs Tipo de Propiedad"))
})
} else {
message("Datos insuficientes para realizar el análisis de correspondencia")
print(knitr::kable(cont_table,
caption = "Tabla de contingencia: Zona vs Tipo de Propiedad"))
}##
##
## Table: Tabla de contingencia: Zona vs Tipo de Propiedad
##
## | | Apartamento| Casa|
## |:------------|-----------:|----:|
## |Zona Centro | 24| 100|
## |Zona Norte | 1198| 722|
## |Zona Oeste | 1029| 169|
## |Zona Oriente | 62| 289|
## |Zona Sur | 2787| 1939|
Hallazgos clave del análisis de correspondencia:
vivienda_map <- vivienda_prep %>%
filter(!is.na(longitud) & !is.na(latitud))
map <- leaflet(vivienda_map) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
color = ~factor(kmeans_result$cluster[1:nrow(vivienda_map)]),
popup = ~paste("Precio:", preciom, "M",
"<br>Área:", areaconst, "m²",
"<br>Tipo:", tipo,
"<br>Estrato:", estrato),
radius = 6,
stroke = FALSE,
fillOpacity = 0.7
)
mapvivienda_analysis <- vivienda_prep %>%
select(preciom, areaconst, parqueaderos, banios, habitaciones, estrato) %>%
na.omit()
vivienda_analysis$cluster <- as.factor(kmeans_result$cluster)
# ANOVA
anova_precio <- aov(preciom ~ cluster, data = vivienda_analysis)
summary(anova_precio)## Df Sum Sq Mean Sq F value Pr(>F)
## cluster 3 539975884 179991961 5648 <2e-16 ***
## Residuals 6713 213921088 31867
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Diferencias significativas entre clusters:
cluster_stats <- vivienda_analysis %>%
group_by(cluster) %>%
summarise(
n = n(),
precio_medio = mean(preciom),
precio_sd = sd(preciom),
area_media = mean(areaconst),
estrato_medio = mean(estrato)
)
knitr::kable(cluster_stats, caption = "Estadísticas por Cluster")| cluster | n | precio_medio | precio_sd | area_media | estrato_medio |
|---|---|---|---|---|---|
| 1 | 3062 | 245.3116 | 85.50226 | 95.17836 | 4.273351 |
| 2 | 826 | 1145.7663 | 346.94851 | 419.78981 | 5.743341 |
| 3 | 756 | 460.1045 | 153.79521 | 298.32745 | 4.112434 |
| 4 | 2073 | 532.6025 | 189.46339 | 170.27264 | 5.551375 |
El mercado inmobiliario urbano presenta una estructura segmentada en cuatro clústeres definidos por factores físicos, socioeconómicos y geográficos. El análisis estadístico multivariado y geoespacial ha permitido identificar oportunidades estratégicas en cada zona, siendo la Zona Oeste la de mayor rentabilidad y la Zona Centro un área con potencial latente que requiere intervención pública. Además, la situación de la Base Aérea representa un reto y una oportunidad clave para el desarrollo futuro. La integración de técnicas analíticas avanzadas, como el análisis de componentes principales y el clustering, fortalece la toma de decisiones basada en pruebas, lo que facilita estrategias de desarrollo y comercialización más precisas en un mercado altamente competitivo.