Actividad 1. Evaluación de la oferta inmobiliaria urbana

Análisis exploratorio de datos

library(paqueteMODELOS)
library(naniar)
data(vivienda)
datos <- vivienda
#visualizar datos faltantes
print(faltantes <- colSums(is.na(datos)) %>%
  as.data.frame()) 
##                 .
## id              3
## zona            3
## piso         2638
## estrato         3
## preciom         2
## areaconst       3
## parqueaderos 1605
## banios          3
## habitaciones    3
## tipo            3
## barrio          3
## longitud        3
## latitud         3
gg_miss_var(datos)  # Muestra la proporción de datos faltantes por cada variable

#Las variables 'piso' y 'parqueadero' presentan gran cantidad de datos faltantes, por ende, se deciden eliminar estas variables. A su vez, se decide por eliminar las variables 'id' y 'barrio' que no son relevantes en el análisis.
datos <- subset(datos, select = -c(id, piso, parqueaderos, barrio))
# Posteriormente, se eliminan filas con valores faltantes
datos <- datos[complete.cases(datos), ]
# Se visualiza la efectividad de los procesos de eliminación de datos faltantes
print(colSums(is.na(datos)) %>%
  as.data.frame()) 
##              .
## zona         0
## estrato      0
## preciom      0
## areaconst    0
## banios       0
## habitaciones 0
## tipo         0
## longitud     0
## latitud      0
print(datos)
## # A tibble: 8,319 × 9
##    zona     estrato preciom areaconst banios habitaciones tipo  longitud latitud
##    <chr>      <dbl>   <dbl>     <dbl>  <dbl>        <dbl> <chr>    <dbl>   <dbl>
##  1 Zona Or…       3     250        70      3            6 Casa     -76.5    3.43
##  2 Zona Or…       3     320       120      2            3 Casa     -76.5    3.43
##  3 Zona Or…       3     350       220      2            4 Casa     -76.5    3.44
##  4 Zona Sur       4     400       280      5            3 Casa     -76.5    3.44
##  5 Zona No…       5     260        90      2            3 Apar…    -76.5    3.46
##  6 Zona No…       5     240        87      3            3 Apar…    -76.5    3.37
##  7 Zona No…       4     220        52      2            3 Apar…    -76.5    3.43
##  8 Zona No…       5     310       137      3            4 Apar…    -76.5    3.38
##  9 Zona No…       5     320       150      4            6 Casa     -76.5    3.48
## 10 Zona No…       5     780       380      3            3 Casa     -76.5    3.49
## # ℹ 8,309 more rows

Posterior de la eliminación de las columnas ‘id’, ‘piso’, ‘barrio’ y ‘parqueadero’, y las filas con datos faltantes, la base de datos limpia consta de 8319 filas y 9 columnas.Por otra parte, se codifican las columnas categóricas (‘zona’ y ‘tipo’) para transformarlas a categórias numéricas.

library(dplyr)
#Códificación de la variable 'zona'
datos <- datos %>% mutate(zona = replace(zona, 
                                               zona == "Zona Centro", 1))
datos <- datos %>% mutate(zona = replace(zona, 
                                               zona == "Zona Norte", 2))
datos <- datos %>% mutate(zona = replace(zona, 
                                               zona == "Zona Oeste", 3))
datos <- datos %>% mutate(zona = replace(zona, 
                                               zona == "Zona Oriente",
                                               4))
datos <- datos %>% mutate(zona = replace(zona, 
                                               zona == "Zona Sur", 5))
datos$zona <- as.numeric(datos$zona)

# Codificación de la variable 'tipo'                         
datos <- datos %>% mutate(tipo = replace(tipo, 
                                               tipo == "Casa", 1))
datos <- datos %>% mutate(tipo = replace(tipo, 
                                               tipo == "Apartamento", 2))
datos$tipo <- as.numeric(datos$tipo)
# Visualzación de las primeras filas de la tabla
head(datos, 5)
## # A tibble: 5 × 9
##    zona estrato preciom areaconst banios habitaciones  tipo longitud latitud
##   <dbl>   <dbl>   <dbl>     <dbl>  <dbl>        <dbl> <dbl>    <dbl>   <dbl>
## 1     4       3     250        70      3            6     1    -76.5    3.43
## 2     4       3     320       120      2            3     1    -76.5    3.43
## 3     4       3     350       220      2            4     1    -76.5    3.44
## 4     5       4     400       280      5            3     1    -76.5    3.44
## 5     2       5     260        90      2            3     2    -76.5    3.46

Por otra parte, se genera una matriz de correlación para analizar la incidencia entre sí de las variables.

options(repos = c(CRAN = "https://cloud.r-project.org"))
install.packages("psych")
## package 'psych' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\diego\AppData\Local\Temp\RtmpSMjix8\downloaded_packages
install.packages("corrplot")
## package 'corrplot' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\diego\AppData\Local\Temp\RtmpSMjix8\downloaded_packages
library(psych)
library(corrplot)
correlacion <- cor(datos, use = "complete.obs")
corrplot(correlacion, method = "number", col = colorRampPalette(c("purple", "yellow"))(200))

A partir de la matriz de correlacción es apreciable que a medida que el estrato de la vivienda aumenta, también lo hace el precio. Se observa una relación positiva entre el precio de la vivienda y el área construida. Las viviendas con un área mayor tienden a incrementar su precio. Asimismo, las viviendas con mayor cantidad de baños tienden a ser más costosas.

Análisis de componentes principales

#Se Selecciona el subconjunto de variables a escalar
vivienda_z <- datos[, 2:6] %>%
  scale()
# Se presentan los primeros registros
head(vivienda_z)
##         estrato    preciom  areaconst      banios habitaciones
## [1,] -1.5872276 -0.5595498 -0.7339949 -0.07793773    1.6406840
## [2,] -1.5872276 -0.3465670 -0.3842568 -0.77811479   -0.4147626
## [3,] -1.5872276 -0.2552886  0.3152194 -0.77811479    0.2703863
## [4,] -0.6156201 -0.1031580  0.7349051  1.32241640   -0.4147626
## [5,]  0.3559875 -0.5291236 -0.5940997 -0.77811479   -0.4147626
## [6,]  0.3559875 -0.5899759 -0.6150839 -0.07793773   -0.4147626
# Se realiza el Análisis de Componentes Principales
prcomp(vivienda_z)
## Standard deviations (1, .., p=5):
## [1] 1.7126464 1.0901014 0.6673458 0.4916079 0.4375986
## 
## Rotation (n x k) = (5 x 5):
##                    PC1        PC2        PC3        PC4        PC5
## estrato      0.3300032 -0.6744363  0.4208934 -0.4795545  0.1706159
## preciom      0.5068715 -0.2807656 -0.3015468  0.2213868 -0.7240921
## areaconst    0.4940473  0.1638135 -0.6525373 -0.2984641  0.4628138
## banios       0.5189619  0.1092831  0.3767649  0.6647648  0.3672488
## habitaciones 0.3475270  0.6538568  0.4051685 -0.4359154 -0.3122700

Se revisará el número de componentes principales

library(factoextra)
# Realizar ACP y visualizar el gráfico 
res.pca <- prcomp(vivienda_z)
fviz_eig(res.pca, addlabels = TRUE)

Es preciso observar que el primer componente principal explica el 58.7% de la variabilidad total y los dos primeros componentes principales explican en conjunto el 82.5% de la variabilidad total.,La primera componente principal supera la mitad de la variabilidad total.

# Visualización del gráfico
fviz_pca_var(res.pca,
              col.var = "contrib",
              gradient.cols = c("#FF7F00",  "#034D94"),
              repel = TRUE,)

A partir del gráfico se aprecia que las variables que están sobre el primer cuadrante corresponden a características asociadas a la infraestructura de la vivienda, mientras que las variables en el cuarto cuadrante corresponden a variables de valorización del inmueble. Posteriormente, se crean dos representaciones gráficas para determinar qué componentes tienen un impacto en las direcciones de la primera y segunda componente.

# Contribuciones en las componentes
fviz_contrib(res.pca, choice = "var", axes = 1, top = 10) 

fviz_contrib(res.pca, choice = "var", axes = 2, top = 10)

get_pca_var(res.pca)$contrib[,1:2]
##                 Dim.1     Dim.2
## estrato      10.89021 45.486434
## preciom      25.69187  7.882934
## areaconst    24.40828  2.683486
## banios       26.93215  1.194279
## habitaciones 12.07750 42.752867

Se aprecia que la cantidad de baños es la característica que influye en la primera componente, junto con el precio de vivienda y el área construida. Por otro lado, en la segunda componente, son el estrato y la cantidad de habitaciones las que presentan mayor influencia.

Análisis de conglomerados

# Se toman las siguientes variables: estrato, preciom, areacons, banios y habitaciones
vivienda_2 <- datos[2:6]
vivienda_2_est <- scale(vivienda_2)
vivienda_2_est <- as.data.frame(vivienda_2_est)
head(vivienda_2_est,5)
##      estrato    preciom  areaconst      banios habitaciones
## 1 -1.5872276 -0.5595498 -0.7339949 -0.07793773    1.6406840
## 2 -1.5872276 -0.3465670 -0.3842568 -0.77811479   -0.4147626
## 3 -1.5872276 -0.2552886  0.3152194 -0.77811479    0.2703863
## 4 -0.6156201 -0.1031580  0.7349051  1.32241640   -0.4147626
## 5  0.3559875 -0.5291236 -0.5940997 -0.77811479   -0.4147626
set.seed(0)
# Agrupamiento
modelo_kmeans <- kmeans(vivienda_2_est, 3)
vivienda_2_est <- data.frame(vivienda_2_est,
                             modelo_kmeans$cluster) 
aggregate(vivienda_2,
          by = list(vivienda_2_est$modelo_kmeans.cluster),
          FUN = median) 
##   Group.1 estrato preciom areaconst banios habitaciones
## 1       1       4     185        75      2            3
## 2       2       5     780       324      5            5
## 3       3       5     370       118      3            3
# Distribución de datos por cluster
table(vivienda_2_est$modelo_kmeans.cluster)
## 
##    1    2    3 
## 3035 1873 3411
fviz_cluster(list(data = vivienda_2_est[,1:5], 
                  cluster = vivienda_2_est$modelo_kmeans.cluster),
             palette = c("#FF7F00",  "#034D94", "#9d008c"),
             ellipse.type = "convex",repel = F, 
             show.clust.cent = FALSE, ggtheme = theme_minimal())

Se presenta un análisis con un modelo de agrupamiento no jerárquico y con base a los resultado de las medianas se puede decir que el primer cluster se distingue por relacionar viviendas con precios, áreas y estratos más bajos. Por el contrario, las viviendas vinculadas al segundo cluster son aquellas con los precios y áreas más altos. La característica resaltada en el cluster 3 es que abarca viviendas con un estrato 5. A pesar de que las propiedades no tienen un área extensa, el precio es el doble al de las viviendas del primer cluster.

# Se emplea un método jerárquico de agrupación.
# con el objetivo de seleccionar el número adecuado de clusters se emplea el coeficiente de Silhouette
#El valor indicado para k es el más cercano a 1
set.seed(0)
dist_eu <- dist(vivienda_2_est[,1:6],method = "euclidean")
modelo_jer <- hclust(dist_eu, method = "ward.D") 
library(tidyverse)
library(cluster)

cluster_assigments_k2 <- cutree(modelo_jer, k = 2) # Cluster
sil_1_k2 <- silhouette(cluster_assigments_k2, dist(vivienda_2_est[,1:6]))
sil_1_avg_k2 <- mean(sil_1_k2[,3])
cat("Coeficiente de Silhouette promedio k=2 : ", sil_1_avg_k2)
## Coeficiente de Silhouette promedio k=2 :  0.3649906
cluster_assigments_k3 <- cutree(modelo_jer, k = 3) # Cluster
sil_1_k3 <- silhouette(cluster_assigments_k3, dist(vivienda_2_est[,1:6]))
sil_1_avg_k3 <- mean(sil_1_k3[,3])
cat("Coeficiente de Silhouette promedio k=3 : ", sil_1_avg_k3)
## Coeficiente de Silhouette promedio k=3 :  0.429883
cluster_assigments_k4 <- cutree(modelo_jer, k = 4) # Cluster
sil_1_k4 <- silhouette(cluster_assigments_k4, dist(vivienda_2_est[,1:6]))
sil_1_avg_k4 <- mean(sil_1_k4[,3])
cat("Coeficiente de Silhouette promedio k=4 : ", sil_1_avg_k4) 
## Coeficiente de Silhouette promedio k=4 :  0.4453488
cluster_assigments_k5 <- cutree(modelo_jer, k = 5) # Cluster
sil_1_k5 <- silhouette(cluster_assigments_k5, dist(vivienda_2_est[,1:6]))
sil_1_avg_k5 <- mean(sil_1_k5[,3])
cat("Coeficiente de Silhouette promedio k=5 : ", sil_1_avg_k5)
## Coeficiente de Silhouette promedio k=5 :  0.3105849
cluster_assigments_k6 <- cutree(modelo_jer, k = 6) # Cluster
sil_1_k6 <- silhouette(cluster_assigments_k6, dist(vivienda_2_est[,1:6]))
sil_1_avg_k6 <- mean(sil_1_k6[,3])
cat("Coeficiente de Silhouette promedio k=6 : ", sil_1_avg_k6)
## Coeficiente de Silhouette promedio k=6 :  0.2480993
cluster_assigments_k7 <- cutree(modelo_jer, k = 7) # Cluster
sil_1_k7 <- silhouette(cluster_assigments_k7, dist(vivienda_2_est[,1:6]))
sil_1_avg_k7 <- mean(sil_1_k7[,3])
cat("Coeficiente de Silhouette promedio k=7 : ", sil_1_avg_k7)
## Coeficiente de Silhouette promedio k=7 :  0.2625557
cluster_jer <- cutree(modelo_jer, k = 4)
vivienda_2_est <- data.frame(vivienda_2_est,cluster_jer)
table(vivienda_2_est$cluster_jer)
## 
##    1    2    3    4 
## 2976 3394  942 1007
aggregate(vivienda_2,
          by = list(vivienda_2_est$cluster_jer),
          FUN = median)
##   Group.1 estrato preciom areaconst banios habitaciones
## 1       1     4.0     180     75.00      2            3
## 2       2     5.0     366    118.00      3            3
## 3       3     4.5     500    316.39      5            6
## 4       4     6.0    1100    322.42      5            4
fviz_cluster(list(data = vivienda_2_est[,1:5], 
                  cluster = vivienda_2_est$cluster_jer),
             palette = c("#2E9FDF",  "#E7B800", "#9d008c", "#0e9d00"),
             ellipse.type = "convex",repel = F, 
             show.clust.cent = FALSE, ggtheme = theme_minimal())

Estos resultados indican una mejor agrupación cuando se eligen k con 4 conglomerados, ya que valores más cercanos a 1 indican un agrupamiento más coherente.

A partir de los valores de las medianas para cada grupo se observa que en el primer cluster el precio es relativamente bajo y las viviendas son más pequeñas. Para el segundo grupo el precio es un poco mayor y las viviendas tienen un tamaño de 118. El cluster 3 el precio incrementa a 500 y las viviendas tienen una extensión de 316.39. En el cuarto grupo el precio es el más alto y las viviendas son las más grandes. Generalmente, a mayor estrato aumenta el precio junto con el tamaño de la construcción y tienen las características más grandes.

Los números de clusters indicados por los métodos jerárquico y no jerárquico son diferentes, lo cual indica que propiedades carecen de información suficiente para determinar patrones o características adicionales para generar clusters con una estructura más específica, en lugar de una estructura general.

Estas agrupaciones podrían utilizarse para un análisis estadístico más exhaustivo en cada uno de los grupos,reconociendo las características compartidas, los patrones y diferencias entre grupos similares. También podría considerarse nuevas medidas y adicionar nuevos datos a la tabla para generar clusters con estructuras sólidas.

Análisis de correspondencia

#se contruye una tabla cruzada para las variables categóricas tipo de vivienda, zona y barrio
library(FactoMineR)
tabla <- table(datos$zona, datos$estrato)
resultados_ac <- CA(tabla)

valores_prop <-resultados_ac$eig 

library(factoextra)
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")

Las dos primeras dimensiones juntas explican el 97.7% de la varianza total en los datos, indicando que las dos primeras dimensiones son suficientes para capturar la mayor parte de la información presentada por los datos.

Por medio del análisis del plano se puede concluir que las viviendas que están en la Zona oeste son estrato 6. Por otro lado, las viviendas que están ubicadas en las zonas norte y sur pertenecen a estratos 4 y 5, y las viviendas que están ubicadas en las zonas Oriente y Centro son mayoritariamente de estrato 3.

Conclusiones

En primer lugar, la aplicación del Análisis de Componentes Principales se logra reducir la dimensión de los datos para identificar las variables más influyentes que explican la variabilidad en el mercado de vivienda. Esto permite comprender los elementos claves que se relacionan con el valor y la oferta, como el área de construcción, los precios y características específicas del mercado.

El Análisis de Conglomerados permite agrupar propiedades con características similares para facilitar la segmentación de mercado e identificar patrones de oferta y demanda, lo cual es crucial para tomar decisiones estratégicas.

Por otra parte, el Análisis de Correspondencia permite reconocer relaciones entre categorías cualitativas, como el tipo o características del entorno, con el fin de facilizar una comprensión de la distribución de las preferencias del mercado.

Recomendaciones

Los resultados obtenidos del Análisis de Conglomerados pueden utilizarse para adaptar estrategias de marketing para cada grupo de inmuebles, considerando la ubicación como un elemento importante para establecer precios y estrategias de venta. A su vez, es importante el monitoreo continuo y los análisis detallados para verificar que las estrategias sean relevantes y efectivas.