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:
skim(creditos)
Name | creditos |
Number of rows | 8322 |
Number of columns | 13 |
_______________________ | |
Column type frequency: | |
character | 4 |
numeric | 9 |
________________________ | |
Group variables | None |
Variable type: character
skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
---|---|---|---|---|---|---|---|
zona | 3 | 1.00 | 8 | 12 | 0 | 5 | 0 |
piso | 2638 | 0.68 | 2 | 2 | 0 | 12 | 0 |
tipo | 3 | 1.00 | 4 | 11 | 0 | 2 | 0 |
barrio | 3 | 1.00 | 4 | 29 | 0 | 436 | 0 |
Variable type: numeric
skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
---|---|---|---|---|---|---|---|---|---|---|
id | 3 | 1.00 | 4160.00 | 2401.63 | 1.00 | 2080.50 | 4160.00 | 6239.50 | 8319.00 | ▇▇▇▇▇ |
estrato | 3 | 1.00 | 4.63 | 1.03 | 3.00 | 4.00 | 5.00 | 5.00 | 6.00 | ▅▆▁▇▆ |
preciom | 2 | 1.00 | 433.89 | 328.65 | 58.00 | 220.00 | 330.00 | 540.00 | 1999.00 | ▇▂▁▁▁ |
areaconst | 3 | 1.00 | 174.93 | 142.96 | 30.00 | 80.00 | 123.00 | 229.00 | 1745.00 | ▇▁▁▁▁ |
parqueaderos | 1605 | 0.81 | 1.84 | 1.12 | 1.00 | 1.00 | 2.00 | 2.00 | 10.00 | ▇▁▁▁▁ |
banios | 3 | 1.00 | 3.11 | 1.43 | 0.00 | 2.00 | 3.00 | 4.00 | 10.00 | ▇▇▃▁▁ |
habitaciones | 3 | 1.00 | 3.61 | 1.46 | 0.00 | 3.00 | 3.00 | 4.00 | 10.00 | ▂▇▂▁▁ |
longitud | 3 | 1.00 | -76.53 | 0.02 | -76.59 | -76.54 | -76.53 | -76.52 | -76.46 | ▁▅▇▂▁ |
latitud | 3 | 1.00 | 3.42 | 0.04 | 3.33 | 3.38 | 3.42 | 3.45 | 3.50 | ▃▇▅▇▅ |
El conjunto de datos tiene un tamaño de 13 columnas y 8,322 registros.
Este conjunto de datos contiene 9 variables numéricas y 4 variables tipo cadena de texto.
Se observa una cantidad representativa de datos faltantes en las variables parqueaderos (1,605) y piso (2,638). En las demás variables no se observa un valor mayor a 3 registros faltantes. Se realiza limpieza de datos eliminando los registros con todas las variables faltantes; a la variable parqueaderos se le asigna el valor cero a los datos faltantes, indicando que los predios no cuentan con parqueadero; a la variable piso no se le realizó tratamiento, conservándose los registros faltantes y utilizándose con criterio limitado en el análisis.
creditos <- creditos %>% # Se borran registros con NA en todas las filas.
filter(!if_all(everything(), is.na))
creditos$parqueaderos[is.na(creditos$parqueaderos)] <- 0 # Remplazar NA por cero: ningun parquadero.
creditos <- creditos[-8320, ] # linea con valores NA.
Para iniciar el análisis de componentes principales (PCA), se seleccionaron las variables cuantitativas preciom, areaconst, parqueadero, banios y habitaciones. Posteriormente, se realizó el proceso de estandarización de los datos para asegurar que todas las variables tuvieran la misma escala. A continuación, se generaron las gráficas correspondientes a:
La varianza explicada por cada componente principal.
La contribución de cada variable en las distintas dimensiones del PCA.
Las variables en el plano de los componentes principales.
credi_clear= scale(creditos[, 5:9])
res.pca <- prcomp(credi_clear) #Análisis de Componentes Principales (PCA)
fviz_eig(res.pca, addlabels = TRUE) # Varianza explicada
fviz_contrib(res.pca, choice = "var", axes = 1)
fviz_contrib(res.pca, choice = "var", axes = 2)
fviz_pca_var(res.pca,
col.var = "contrib",
gradient.cols = c("#B3E0A6", "#DECC66", "#9E3D22"),
repel = TRUE
)
Sumando PC1 (62,6%) y PC2 (18,4%), se explica aproximadamente el 81% de la varianza total; por lo tanto, PC1 y PC2 son suficientes para representar la mayor parte de la información.
La variable con mayor contribución a la dimensión Dim-1 es banios (~25%), mientras que, para la Dim-2, la más representativa es la variable habitaciones (~60%).
La gráfica de variables en el plano de dimensiones permite evidenciar que la variable con mayor contribución es habitaciones, seguida de banios y preciom. Las variables agrupadas revelan una correlación positiva, como es el caso de parqueaderos–preciom y areaconst–banios. Un ángulo de 90 grados entre variables representa una correlación nula, como se observa en la relación entre parqueaderos-habitaciones.
Para iniciar el análisis de conglomerados, se seleccionaron como variables cuantitativas: preciom, areaconst, parqueadero, baños y habitaciones.Adicionalmente, se incluyeron en el análisis las variables categóricas estrato y tipo, realizando las siguientes transformaciones:
Estrato: se agruparon los niveles 3 y 4 en una sola categoría, y los niveles 5 y 6 en otra.
Tipo: indica si la propiedad corresponde a un apartamento o a una casa.
Con el fin de evitar que la diferencia de escalas entre variables numéricas afectara la formación de conglomerados, se aplicó un proceso de estandarización a las variables cuantitativas, garantizando que todas presentaran media cero y desviación estándar igual a uno.
A continuación, se generaron las gráficas correspondientes a:
Diagrama de índice Silhouette.
Dendrogramas de los grupos.
Diagrama de dispersión de variables preciom y areaconst vs Cluster.
cre_casa_3_4<- creditos[creditos$tipo == "Casa",]
cre_casa_3_4<- cre_casa_3_4[cre_casa_3_4$estrato == 3|cre_casa_3_4$estrato == 4,]
cre_casa_3_4= scale(cre_casa_3_4[, 5:9])
cre_casa_3_4 <- as.data.frame(cre_casa_3_4)
cre_casa_5_6<- creditos[creditos$tipo == "Casa",]
cre_casa_5_6<- cre_casa_5_6[cre_casa_5_6$estrato == 5|cre_casa_5_6$estrato == 6,]
cre_casa_5_6= scale(cre_casa_5_6[, 5:9])
cre_casa_5_6 <- as.data.frame(cre_casa_5_6)
cre_apt_3_4<- creditos[creditos$tipo == "Apartamento",]
cre_apt_3_4<- cre_apt_3_4[cre_apt_3_4$estrato == 3|cre_apt_3_4$estrato == 4,]
cre_apt_3_4= scale(cre_apt_3_4[, 5:9])
cre_apt_3_4 <- as.data.frame(cre_apt_3_4)
cre_apt_5_6<- creditos[creditos$tipo == "Apartamento",]
cre_apt_5_6<- cre_apt_5_6[cre_apt_5_6$estrato == 5|cre_apt_5_6$estrato == 6,]
cre_apt_5_6= scale(cre_apt_5_6[, 5:9])
cre_apt_5_6 <- as.data.frame(cre_apt_5_6)
p1 <- fviz_nbclust(cre_casa_3_4, hcut, method = "silhouette")+
ggtitle("Casas estratos 3 y 4")
p2 <- fviz_nbclust(cre_casa_5_6, hcut, method = "silhouette")+
ggtitle("Casas estratos 5 y 6")
p3 <- fviz_nbclust(cre_apt_3_4, hcut, method = "silhouette")+
ggtitle("Apartamentos estratos 3 y 4")
p4 <- fviz_nbclust(cre_apt_5_6, hcut, method = "silhouette")+
ggtitle("Apartamentos estratos 5 y 6")
((p1 | p2) / (p3 | p4)) +
plot_annotation(title = "Número óptimo de clusters (método Silhouette)",
theme = theme(plot.title = element_text(size = 14, face = "bold", hjust = 0.5)))
# Casas 3-4
dist_prop <- dist(cre_casa_3_4, method = "euclidean")
hc_prop1 <- hclust(dist_prop, method = "ward.D2")
p1 <- fviz_dend(hc_prop1, show_labels = FALSE, main = "Casas estratos 3 y 4")
# Casas 5-6
dist_prop <- dist(cre_casa_5_6, method = "euclidean")
hc_prop2 <- hclust(dist_prop, method = "ward.D2")
p2 <- fviz_dend(hc_prop2, show_labels = FALSE, main = "Casas estratos 5 y 6")
# Aptos 3-4
dist_prop <- dist(cre_apt_3_4, method = "euclidean")
hc_prop3 <- hclust(dist_prop, method = "ward.D2")
p3 <- fviz_dend(hc_prop3, show_labels = FALSE, main = "Aptos estratos 3 y 4")
# Aptos 5-6
dist_prop <- dist(cre_apt_5_6, method = "euclidean")
hc_prop4 <- hclust(dist_prop, method = "ward.D2")
p4 <- fviz_dend(hc_prop4, show_labels = FALSE, main = "Aptos estratos 5 y 6")
# Combinar en panel
((p1 | p2) / (p3 | p4)) +
plot_annotation(
title = "Dendrogramas",
theme = theme(plot.title = element_text(size = 14, face = "bold", hjust = 0.5))
)
grupo <- cutree(hc_prop1, k = 2)
datos_cluster <- cre_casa_3_4 %>% mutate(cluster = as.factor(grupo))
p1 <- ggplot(datos_cluster, aes(x = preciom, y = areaconst, color = cluster)) +
geom_point(alpha = 0.5) +
theme_minimal() +
ggtitle("Casas estratos 3 y 4")
grupo <- cutree(hc_prop2, k = 2)
datos_cluster <- cre_casa_5_6 %>% mutate(cluster = as.factor(grupo))
p2 <- ggplot(datos_cluster, aes(x = preciom, y = areaconst, color = cluster)) +
geom_point(alpha = 0.5) +
theme_minimal()+
ggtitle("Casas estratos 5 y 6")
grupo <- cutree(hc_prop3, k = 10)
datos_cluster <- cre_apt_3_4 %>% mutate(cluster = as.factor(grupo))
p3 <- ggplot(datos_cluster, aes(x = preciom, y = areaconst, color = cluster)) +
geom_point(alpha = 0.5) +
theme_minimal()+
ggtitle("Apartamentos estratos 3 y 4")
grupo <- cutree(hc_prop4, k = 2)
datos_cluster <- cre_apt_5_6 %>% mutate(cluster = as.factor(grupo))
p4 <- ggplot(datos_cluster, aes(x = preciom, y = areaconst, color = cluster)) +
geom_point(alpha = 0.5) +
theme_minimal()+
ggtitle("Apartamentos estratos 5 y 6")
# Combinar en panel
((p1 | p2) / (p3 | p4)) +
plot_annotation(
title = "Diagramas de dispersión: preciom Vs areaconst",
theme = theme(plot.title = element_text(size = 14, face = "bold", hjust = 0.5))
)
El método del coeficiente de Silhouette sugiere que, para casas estratos 3 y 4, casas estratos 5 y 6 y apartamentos estratos 5 y 6, el número óptimo de clústeres es k = 2, con valores de Silhouette alrededor de 0,34–0,36, lo que indica una separación aceptable entre grupos. En apartamentos estratos 3 y 4, el máximo teórico del coeficiente se da en k = 10, reflejando mayor heterogeneidad interna.
Los dendrogramas muestran que en tres de los cuatro conjuntos de datos existen dos grandes grupos principales, consistentes con el resultado de Silhouette. En apartamentos estratos 3 y 4 se observa una estructura más fragmentada, con múltiples subdivisiones a alturas relativamente bajas, lo que confirma la mayor diversidad interna.
En todos los casos, los clústeres se diferencian principalmente por preciom y areaconst: un grupo concentra inmuebles más grandes y caros, y el otro agrupa propiedades más pequeñas y económicas. En apartamentos estratos 3 y 4, la presencia de múltiples clústeres sugiere subsegmentos de mercado más definidos, posiblemente influenciados por factores adicionales como ubicación o características internas.
Para iniciar el análisis de correspondencia, se seleccionaron las variables cualitativas zona y estrato. Posteriormente, se tomó una muestra de 4.150 registros y se verificó si había datos faltantes.
A continuación, se generaron las gráficas correspondientes a:
Diagrama de verificación de datos faltantes.
Tabla cruzada de las variables zona y estrato.
Mapa factorial del análisis de correspondencia.
Varianza explicada por cada componente principal.
creditos <- as.data.frame(creditos)
set.seed(123)
credi_muetra <- sample_n(creditos, 4150)
credi_muetra$estrato <- as.factor(credi_muetra$estrato)
credi_muetra <-credi_muetra [c("estrato","zona")]
colSums(is.na(credi_muetra ))
estrato zona
0 0
tabla <- table(credi_muetra$zona, credi_muetra$estrato)
colnames(tabla) <- c("Estrato_3", "Estrato_4", "Estrato_5", "Estrato_6" )
tabla
Estrato_3 Estrato_4 Estrato_5 Estrato_6
Zona Centro 57 7 2 1
Zona Norte 289 206 346 89
Zona Oeste 32 41 141 382
Zona Oriente 168 4 2 1
Zona Sur 208 795 848 531
chisq.test(tabla)
Pearson's Chi-squared test
data: tabla
X-squared = 1823.1, df = 12, p-value < 2.2e-16
resul_ca <- CA(tabla)
fviz_screeplot(resul_ca, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
Los dos primeros ejes explican el 98.5% de la varianza, esto indica: El mapa factorial de 2D es altamente confiable para interpretar las relacionesy no se necesitan más dimensiones para explicar los datos
Existe una asociación estadísticamente significativa (p < 0.001) entre la zona geográfica y el estrato socioeconómico, confirmada por la prueba de Chi-cuadrado.
El análisis estadístico y gráfico confirma una clara relación entre la ubicación geográfica y el estrato socioeconómico. Los resultados muestran que el Estrato 6, correspondiente al nivel más alto, se concentra predominantemente en la Zona Oeste, como lo evidencia tanto la tabla de contingencia (382 casos) como su cercana asociación en el mapa factorial. Por otro lado, los Estratos 4 y 5, están principalmente ubicados en las Zonas Sur y Norte, destacándose la Zona Sur con los mayores registros (795 casos en Estrato 4 y 848 en Estrato 5). Finalmente, el Estrato 3, de nivel socioeconómico más bajo, predomina en las Zonas Oriente y Centro, donde la Zona Oriente registra 168 casos en este estrato y casi ninguna presencia en los estratos superiores.