Una empresa inmobiliaria lĆder en una gran ciudad estĆ” buscando comprender en profundidad el mercado de viviendas urbanas para tomar decisiones estratĆ©gicas mĆ”s informadas. La empresa posee una base de datos extensa que contiene información detallada sobre diversas propiedades residenciales disponibles en el mercado. Se requiere realizar un anĆ”lisis holĆstico de estos datos para identificar patrones, relaciones y segmentaciones relevantes que permitan mejorar la toma de decisiones en cuanto a la compra, venta y valoración de propiedades.
data("vivienda")
df <- vivienda
#dplyr::glimpse(df)
tabla_glimpse <- data.frame(
Variable = names(df),
Tipo = sapply(df, function(x) class(x)[1]),
Ejemplo = sapply(df, function(x) {
paste(head(x, 3), collapse = ", ")
}),
row.names = NULL
)
tabla_glimpse %>%
knitr::kable("html", booktabs = TRUE,
caption = "<span style='font-size:13pt; font-weight:bold;'>Tabla 1. Resumen del tipo de dato</span>") %>%
kable_styling(full_width = FALSE,
position = "center",
bootstrap_options = c("striped", "hover")) %>%
column_spec(1, bold = TRUE, width = "8cm") %>%
row_spec(0, bold = TRUE, background = "#f2f2f2")
| Variable | Tipo | Ejemplo |
|---|---|---|
| id | numeric | 1147, 1169, 1350 |
| zona | character | Zona Oriente, Zona Oriente, Zona Oriente |
| piso | character | NA, NA, NA |
| estrato | numeric | 3, 3, 3 |
| preciom | numeric | 250, 320, 350 |
| areaconst | numeric | 70, 120, 220 |
| parqueaderos | numeric | 1, 1, 2 |
| banios | numeric | 3, 2, 2 |
| habitaciones | numeric | 6, 3, 4 |
| tipo | character | Casa, Casa, Casa |
| barrio | character | 20 de julio, 20 de julio, 20 de julio |
| longitud | numeric | -76.51168, -76.51237, -76.51537 |
| latitud | numeric | 3.43382, 3.43369, 3.43566 |
tabla_summary <- df %>%
select(-id, -longitud, -latitud) %>% # eliminar id si existe
select(where(is.numeric)) %>% # SOLO numƩricas
summarise(
across(
everything(),
list(
N = ~sum(!is.na(.x)),
Min = ~min(.x, na.rm = TRUE),
`1st Qu.` = ~quantile(.x, 0.25, na.rm = TRUE),
Median = ~median(.x, na.rm = TRUE),
Mean = ~mean(.x, na.rm = TRUE),
`3rd Qu.` = ~quantile(.x, 0.75, na.rm = TRUE),
Max = ~max(.x, na.rm = TRUE)
),
.names = "{.col}__{.fn}" # separador seguro
)
) %>%
pivot_longer(
cols = everything(),
names_to = c("Variable", ".value"),
names_pattern = "(.*)__(.*)"
) %>%
select(Variable, N, Min, `1st Qu.`, Median, Mean, `3rd Qu.`, Max)
# Ordenar columnas (Variable, N, resto)
tabla_summary <- tabla_summary %>%
select(Variable, N, Min, `1st Qu.`, Median, Mean, `3rd Qu.`, Max)
tabla_summary %>%
knitr::kable("html", booktabs = TRUE,
caption = "<span style='font-size:13pt; font-weight:bold;'>Tabla 2. Resumen de estadĆsticas descriptivas de variables numĆ©ricas</span>") %>%
kable_styling(full_width = FALSE,
position = "center",
bootstrap_options = c("striped", "hover")) %>%
column_spec(1, bold = TRUE, width = "8cm") %>%
row_spec(0, bold = TRUE, background = "#f2f2f2")
| Variable | N | Min | 1st Qu. | Median | Mean | 3rd Qu. | Max |
|---|---|---|---|---|---|---|---|
| estrato | 8319 | 3 | 4 | 5 | 4.633610 | 5 | 6 |
| preciom | 8320 | 58 | 220 | 330 | 433.891947 | 540 | 1999 |
| areaconst | 8319 | 30 | 80 | 123 | 174.934938 | 229 | 1745 |
| parqueaderos | 6717 | 1 | 1 | 2 | 1.835194 | 2 | 10 |
| banios | 8319 | 0 | 2 | 3 | 3.111311 | 4 | 10 |
| habitaciones | 8319 | 0 | 3 | 3 | 3.605361 | 4 | 10 |
tabla_na <- df %>%
select(-any_of("id")) %>%
summarise(
across(
everything(),
~sum(is.na(.x))
)
) %>%
t() %>%
as.data.frame()
tabla_na <- tabla_na %>%
tibble::rownames_to_column("Variable") %>%
rename(N_Faltantes = V1) %>% # <- aquĆ el cambio
mutate(
Total = nrow(df),
Porcentaje_NA = round((N_Faltantes / Total) * 100, 2)
)
tabla_na %>%
kable("html", booktabs = TRUE,
caption = "<span style='font-size:13pt; font-weight:bold;'>Tabla 3. Valores faltantes por variable</span>",
digits = 2) %>%
kable_styling(full_width = FALSE,
position = "center",
bootstrap_options = c("striped", "hover")) %>%
column_spec(1, bold = TRUE, width = "5cm") %>%
row_spec(0, bold = TRUE, background = "#f2f2f2")
| Variable | N_Faltantes | Total | Porcentaje_NA |
|---|---|---|---|
| zona | 3 | 8322 | 0.04 |
| piso | 2638 | 8322 | 31.70 |
| estrato | 3 | 8322 | 0.04 |
| preciom | 2 | 8322 | 0.02 |
| areaconst | 3 | 8322 | 0.04 |
| parqueaderos | 1605 | 8322 | 19.29 |
| banios | 3 | 8322 | 0.04 |
| habitaciones | 3 | 8322 | 0.04 |
| tipo | 3 | 8322 | 0.04 |
| barrio | 3 | 8322 | 0.04 |
| longitud | 3 | 8322 | 0.04 |
| latitud | 3 | 8322 | 0.04 |
De acuerdo con la tabla 3, las variables con mĆ”s valores faltantes son: piso y parqueaderos. La variable piso no se considerarĆ” para el presente estudio ya que presenta 31.70 % de valores faltantes frente al total de registros, y no se tiene una idea clara de quĆ© tipo de tĆ©cnica de imputación se podrĆa utilizar.
#Elimino valores faltantes en la columna zona (3)
df_sin_zona <- df %>%
filter(!is.na(zona))
df_num <- df_sin_zona %>%
select(where(is.numeric), -latitud, -longitud,-id, -estrato)
matriz_cor <- cor(df_num, use = "complete.obs", method = "pearson")
# Ajustar mƔrgenes (mƔs espacio abajo)
par(mar = c(3, 1, 2, 1))
corrplot(
matriz_cor,
method = "color", # colores
type = "upper", # solo triƔngulo superior (mƔs limpio)
addCoef.col = "black", # nĆŗmeros dentro de las celdas
tl.col = "black", # color de etiquetas
tl.srt = 45, # rotar nombres de variables
number.cex = 0.7, # tamaño de los números
col = colorRampPalette(c("blue", "white", "red"))(200), # paleta
diag = FALSE
)
Figura 1.0 Correlaciones de Pearson. Azul = relación negativa, rojo = positiva. Solo variables numéricas
De acuerdo con la figura 1, la variable preciom presenta correlaciones cercanas al 70 % con las variables: Ɣrea construida, parqueaderos y baƱos, por lo que se vislumbran como variables influyentes en el precio de la vivienda, y por tanto deben tenerse en cuenta dentro del presente estudio.
ggplot(df, aes(x = preciom)) +
geom_histogram(bins = 30, fill = "steelblue", color = "white") +
labs(
title = "Distribución del precio de las viviendas",
x = "Precio",
y = "Frecuencia",
caption = "Figura 2.0 Distribución del precio de la oferta inmobiliaria."
) +
theme_minimal() +
theme(
plot.caption = element_text(
hjust = 0.5,
face = "italic",
size = 10
)
)
La figura 2 muestra la distribución de los precios de las viviendas. En esta se observa una distribución asimĆ©trica con cola hacia la derecha, evidencia de precios muy altos que podrĆan considerarse como atĆpicos estadĆsticamente, pero plausibles en lo que respecta a este tipo de estudios inmobiliarios. La mayor concentración de observaciones se localiza en el rango de 100 a 400 unidades monetarias, con una frecuencia mĆ”xima superior a 1,200 viviendas.
ggplot(df, aes(x = zona, y = preciom)) +
geom_boxplot(fill = "skyblue") +
labs(
title = "Distribución del precio de las viviendas por zonas",
x = "Zona",
y = "Precio",
caption = "Figura 3.0 Distribución del precio de acuerdo con la zona"
) +
theme_minimal() +
theme(
plot.caption = element_text(
hjust = 0.5,
face = "italic",
size = 10
)
)
De acuerdo con la figura 3, se observa lo siguiente:
la Zona Oeste exhibe la mediana mĆ”s alta (aproximadamente 600 unidades) y el rango intercuartĆlico (IQR) mĆ”s amplio, indicando mayor heterogeneidad en la oferta y precios generalmente superiores.
Zona Oriente presenta la mediana mÔs baja (alrededor de 200 unidades) y la menor dispersión, sugiriendo un mercado mÔs homogéneo y accesible.
Zona Centro, Norte y Sur muestran medianas similares (200-300 unidades) con dispersiones comparables.
Lo anterior permite vislumbrar una fuerte influencia de la variable zona respecto del precio de las viviendas, por eso serĆ” incluida.
ggplot(df, aes(x = areaconst, y = preciom, color = tipo)) +
geom_point(alpha = 0.5) +
labs(
title = "Precio vs Ćrea Construida por tipo de vivienda",
x = "Ćrea (m2)",
y = "Precio",
caption = "Figura 4.0. Diagrama de dispersión: Precio vs Ćrea construida por tipo de vivienda"
) +
theme_minimal() +
theme(
plot.caption = element_text(
hjust = 0.5,
face = "italic",
size = 10
)
)
La figura 4.0 evidencia una relación positiva entre el Ć”rea construida y el precio, aunque con una dispersión creciente a medida que aumenta el tamaƱo del inmueble, lo que sugiere la influencia de factores adicionales como el estrato y la ubicación. Se observa una clara segmentación por tipo de vivienda: los apartamentos se concentran en Ć”reas menores y precios medios, mientras que las casas dominan el segmento de mayor tamaƱo y presentan mayor heterogeneidad de precios. Asimismo, se identifican valores atĆpicos que podrĆan corresponder a propiedades de lujo (precios muy altos con Ć”reas reducidas) o inconsistencias en los datos (precios bajos para viviendas con Ć”reas muy grandes), lo que justifica la aplicación de tĆ©cnicas de detección de outliers.
ggplot(df, aes(x = factor(habitaciones), y = preciom)) +
geom_boxplot(outlier.alpha = 0.3, fill = "skyblue") +
labs(
title = "Precio vs NĆŗmero de habitaciones",
x = "habitaciones",
y = "Precio",
caption = "Figura 5.0. Boxplot: Precio vs NĆŗmero de habitaciones"
) +
theme_minimal() +
theme(
plot.caption = element_text(
hjust = 0.5,
face = "italic",
size = 10
)
)
Al revisar los precios de viviendas de acuerdo con el nĆŗmero de habitaciones (figura 5.0), es preciso afirmar que las viviendas con 1 y 2 habitaciones son las de menor valor de la precio (mediana), sin embargo, se observan muchos valores extremos entre 2 y 7 habitaciones. Esto se podrĆa explicar por:
Mayor variedad de calidad y ubicación.
Influencia de estrato y Ɣrea construida.
Segmento de lujo mƔs diverso.
ggplot(df, aes(x = factor(estrato), y = preciom)) +
geom_boxplot(outlier.alpha = 0.3, fill = "skyblue") +
labs(
title = "Precio vs Estrato",
x = "Estrato",
y = "Precio",
caption = "Figura 6.0. Boxplot: Precio vs Estrato"
) +
theme_minimal() +
theme(
plot.caption = element_text(
hjust = 0.5,
face = "italic",
size = 10
)
)
La figura 6.0 refleja la influencia importante del estrato en el precio de la vivienda. Los estratos 5 y 6 presentan los precios mĆ”s altos. Es preciso mencionar que en todos los estratos se evidencian valores atĆpicos que pueden ser plausibles por la heterogeneidad de viviendas.
ggplot(df, aes(x = longitud, y = latitud,
color = estrato,
size = preciom)) +
geom_point(alpha = 0.6) +
scale_size_continuous(
range = c(1, 6), # puntos pequeƱos ā grandes bien diferenciados
name = "Precio"
) +
labs(
title = "Precio por ubicación geogrÔfica",
x = "Latitud",
y = "Longitud",
caption = "Figura 7.0. Precio por ubicación geogrÔfica y estrato"
) +
theme_minimal() +
theme(
plot.caption = element_text(
hjust = 0.5,
face = "italic",
size = 10
)
)
La figura 7.0 muestra que las viviendas de mayor precio (estratos: 5 y 6) se encuentran en el sur, oriente y occidente. En la zona centro se observa mayor heterogenidad de precios, esto se puede justificar por la variedad del tipo de vivienda: edificios, casas y apartamentos.
Se decide eliminar los registros 8320, 8321 y 8322, ya que no se tiene suficiente información.
Adicionalmente, se transforman a tipo factor las siguientes variables: parqueaderos, piso, zona, tipo y barrio. Finalmente, los valores faltantes de estas variables categóricas, se llenan como āNo informadoā.
#df_sin_zona
df_piso_parq <- df_sin_zona %>%
mutate(
piso = ifelse(is.na(piso), "No informado", piso),
parqueaderos = ifelse(is.na(parqueaderos), "No informado", parqueaderos),
piso = as.factor(piso),
parqueaderos = as.factor(parqueaderos),
zona = as.factor(zona),
tipo = as.factor(tipo),
barrio = as.factor(barrio)
)
id_vector <- df_piso_parq$id
df_sin_coord <- df_piso_parq %>%
select(-longitud, -latitud)
pca_model_FactorM <- PCA(
df_sin_coord %>% select(-id),
ncp = 5,
quali.sup = which(sapply(df_sin_coord %>% select(-id), is.factor)),
scale.unit = TRUE,
graph = FALSE
)
var <- get_pca_var(pca_model_FactorM)
corrplot::corrplot(var$cos2, is.corr=FALSE)
fviz_pca_var(pca_model_FactorM, col.var = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE # Avoid text overlapping
)
Figura 8.0. CĆrculo de correlaciones del AnĆ”lisis de Componentes Principales (PCA)
La figura 8 muestra que el primer componente principal estĆ” asociado al nivel general del inmueble, integrando variables de tamaƱo (Ć”rea construida, nĆŗmero de baƱos y habitaciones), precio y estrato socioeconómico. El segundo componente diferencia entre viviendas de mayor nĆŗmero de habitaciones y aquellas de mayor estrato, lo que sugiere la existencia de tipologĆas distintas dentro del mercado inmobiliario, como viviendas familiares amplias y propiedades de alto valor en estratos superiores con menor nĆŗmero de habitaciones. La proximidad entre las variables de Ć”rea construida y nĆŗmero de baƱos evidencia una alta correlación positiva, indicando que los inmuebles de mayor tamaƱo tienden a contar con mĆ”s servicios.
fviz_eig(pca_model_FactorM, addlabels = TRUE)
Figura 9.0. Explicación de la varianza
La figura 9 muestra que el 82.5 % de la varianza, se explica a travƩs de las dos primeras dimensiones, por lo que solo se tendrƔn en cuenta estas para el anƔlisis.
fviz_contrib(pca_model_FactorM,choice = "ind", axes=1, top = 10)
Figura 10. Contribuciones individuales de la dimensión 1
fviz_contrib(pca_model_FactorM,choice = "ind", axes=2, top = 10)
Figura 11. Contribuciones individuales de la dimensión 2
En las figuras 11 y 12 se observan las contribuciones individuales (10) para las dimensiones 1 y 2.
Para este apartado se usa la función: HCPC (Hierarchical Clustering on Principal Components), de la librerĆa FactoMineR, la cual combina reducción de dimensionalidad mediante PCA con clustering jerĆ”rquico y una optimización posterior por partición. El nĆŗmero de clusters se determinó automĆ”ticamente (nb.clust = -1) con base en la ganancia de inercia, permitiendo identificar segmentos homogĆ©neos del mercado inmobiliario sin imponer una estructura previa.
Cluster_viviendas <- HCPC(pca_model_FactorM,nb.clust=-1)
fviz_cluster(Cluster_viviendas,respel = T)#para generar grƔfico de cluster.
Figura 12. ClĆŗster generados por la librerĆa FactoMineR
Tabla 4. Descripción de cada clúster por variables cuantitativas
Cluster_viviendas$desc.var$quanti
## $`1`
## v.test Mean in category Overall mean sd in category Overall sd
## estrato -43.44906 4.162000 4.633610 0.8549785 1.029160
## habitaciones -48.30433 2.861838 3.605361 0.7381741 1.459449
## areaconst -55.11171 91.841900 174.934938 43.7281648 142.955533
## preciom -57.59277 234.279333 433.904436 100.0212103 328.645270
## banios -67.65133 2.092340 3.111311 0.6168498 1.428124
## p.value
## estrato 0
## habitaciones 0
## areaconst 0
## preciom 0
## banios 0
##
## $`2`
## v.test Mean in category Overall mean sd in category Overall sd
## banios 32.27378 3.805623 3.111311 0.8878737 1.428124
## habitaciones 30.42291 4.274210 3.605361 1.5358014 1.459449
## estrato 21.77490 4.971191 4.633610 0.9863013 1.029160
## areaconst 13.55570 204.126768 174.934938 83.3716172 142.955533
## preciom 10.73560 487.053107 433.904436 168.5907294 328.645270
## p.value
## banios 1.632046e-228
## habitaciones 2.734945e-203
## estrato 4.013585e-105
## areaconst 7.331275e-42
## preciom 6.926408e-27
##
## $`3`
## v.test Mean in category Overall mean sd in category Overall sd
## preciom 69.41544 1069.051030 433.904436 357.1253452 328.645270
## areaconst 61.84414 421.079391 174.934938 193.3465913 142.955533
## banios 54.09829 5.262310 3.111311 1.3408209 1.428124
## estrato 33.28343 5.587287 4.633610 0.6983415 1.029160
## habitaciones 28.32988 4.756491 3.605361 1.7476843 1.459449
## p.value
## preciom 0.000000e+00
## areaconst 0.000000e+00
## banios 0.000000e+00
## estrato 6.707168e-243
## habitaciones 1.481562e-176
El anĆ”lisis de conglomerados (Figura 12, tabla 4) permitió identificar tres segmentos claramente diferenciados en el mercado inmobiliario. El primer cluster corresponde a viviendas de bajo valor, caracterizadas por menor Ć”rea construida, menor nĆŗmero de baƱos y habitaciones y ubicadas en estratos socioeconómicos bajos. El segundo cluster representa el mercado medio, con viviendas de tamaƱo y precio moderado, orientadas a hogares familiares. El tercer cluster agrupa propiedades de alta gama, con mayor Ć”rea construida, mĆ”s servicios y ubicadas en estratos altos, presentando precios significativamente superiores al promedio. Las diferencias entre los clusters son estadĆsticamente significativas, lo que confirma la existencia de una estructura segmentada en la oferta inmobiliaria urbana.
Al realizar el anÔlisis entre zona y tipo, solo surge una dimensión, por lo que se decide realizar un anÔlisis tridimensional entre: zona, tipo y estrato.
df_cuali <- df_sin_coord %>%
mutate(estrato = factor(estrato))%>%
select(zona, tipo, estrato)
res_MCA <- MCA(df_cuali, graph = FALSE)
fviz_mca_biplot(
res_MCA,
repel = TRUE,
invisible = "ind", # oculta los 8319 puntos
col.var = "red", # categorĆas en rojo
pointsize = 3,
labelsize = 4,
title = "Mapa factorial - MCA: Zona, Tipo y Estrato"
) +
theme_minimal()
Figura 13. AnÔlisis de correspondencias múltiples
El anÔlisis de correspondencias múltiples (figura 13) evidencia una asociación entre el tipo de inmueble, la zona y el estrato socioeconómico. Se observa que los apartamentos se concentran principalmente en zonas del sur con estratos medios (4 y 5), mientras que las casas presentan mayor presencia en las zonas norte, centro y oriente, asociadas a estratos medios y bajos. La zona oeste se relaciona con el estrato 6, lo que sugiere una concentración de viviendas de alto nivel socioeconómico en esta Ôrea. Estos resultados confirman la existencia de una especialización territorial de la oferta inmobiliaria y complementan la segmentación identificada mediante el anÔlisis de conglomerados.
El mercado estÔ claramente segmentado en tres niveles: económico, medio y premium.
El tamaƱo y los servicios explican mĆ”s el precio que el estrato solo. El estrato influye, pero el valor real lo define el producto fĆsico.
El mercado medio es el mÔs relevante en volumen. Es el segmento con mayor número de propiedades de perfil familiar.
El segmento premium es pequeño pero de alto margen. Ideal para inversión exclusiva y proyectos diferenciados.
Existe zonificación del valor inmobiliario. Las zonas no son intercambiables, Oriente y Centro, precios altos. Sur y norte, mercado medio bajo. Esto impacta en la decisión de comprar viviendas o lotes.
Priorizar proyectos en segmento medio, mayor liquidez.
Mantener portafolio premium para rentabilidad.
Evitar sobreoferta en segmento bajo sin estrategia de volumen.
El anĆ”lisis multivariado evidenció una estructura segmentada del mercado inmobiliario urbano en tres niveles claramente diferenciados: económico, medio y premium. El valor de los inmuebles estĆ” determinado principalmente por el tamaƱo y la dotación (baƱos y habitaciones), mĆ”s que por el estrato de forma aislada. Asimismo, se identificaron patrones espaciales que vinculan zonas especĆficas con determinados niveles socioeconómicos y tipologĆas de vivienda.
Estos hallazgos permiten a la empresa optimizar su portafolio, focalizar la inversión en el segmento medio como motor de liquidez, desarrollar proyectos premium en zonas de alto valor y estructurar modelos de valoración basados en atributos fĆsicos del inmueble, generando una ventaja competitiva en la toma de decisiones estratĆ©gicas.
El dataset depurado contiene 8.319 registros y variables estructurales del inmueble, incluyendo atributos fĆsicos, socioeconómicos y espaciales. La tabla 5 permite explorar de forma interactiva la información utilizada en los anĆ”lisis multivariados.