Evaluación de la oferta inmobiliaria urbana

Problema:

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.

1. Preparación de la base de de datos

1.1. Reconocimento de las variables.

data=vivienda
names(vivienda)
##  [1] "id"           "zona"         "piso"         "estrato"      "preciom"     
##  [6] "areaconst"    "parqueaderos" "banios"       "habitaciones" "tipo"        
## [11] "barrio"       "longitud"     "latitud"

1.2. Recorte de la data.

No se realizará el análisis sobre las variables id, barrio, longitud y latitud.

data1= data[, c("tipo","zona", "piso", "estrato", "preciom", "areaconst", "parqueaderos", "banios", "habitaciones")]

1.3. Imputación de NAs.

colSums(is.na(data1))
##         tipo         zona         piso      estrato      preciom    areaconst 
##            3            3         2638            3            2            3 
## parqueaderos       banios habitaciones 
##         1605            3            3
#Eliminación de tres filas sin información de la data
data1 <- data1[!is.na(data1$tipo), ]
#Imputación de NA por cero (propiedades sin parqueadero)
data1$parqueaderos[is.na(data1$parqueaderos)] <- 0
#Imputación de NA por uno (propiedades de un piso)
data1$piso[is.na(data1$piso)] <- 1

#Transformar los piso de caracteres (01 a 09) a números (1 al 9)
data1$piso <- ifelse(data1$piso == "01", 1, data1$piso)
data1$piso <- ifelse(data1$piso == "02", 2, data1$piso)
data1$piso <- ifelse(data1$piso == "03", 3, data1$piso)
data1$piso <- ifelse(data1$piso == "04", 4, data1$piso)
data1$piso <- ifelse(data1$piso == "05", 5, data1$piso)
data1$piso <- ifelse(data1$piso == "06", 6, data1$piso)
data1$piso <- ifelse(data1$piso == "07", 7, data1$piso)
data1$piso <- ifelse(data1$piso == "08", 8, data1$piso)
data1$piso <- ifelse(data1$piso == "09", 9, data1$piso)
data1$piso <- as.numeric(data1$piso)

colSums(is.na(data1))
##         tipo         zona         piso      estrato      preciom    areaconst 
##            0            0            0            0            0            0 
## parqueaderos       banios habitaciones 
##            0            0            0

1.4. Resumen de variables.

summary(data1)
##      tipo               zona                piso           estrato     
##  Length:8319        Length:8319        Min.   : 1.000   Min.   :3.000  
##  Class :character   Class :character   1st Qu.: 1.000   1st Qu.:4.000  
##  Mode  :character   Mode  :character   Median : 2.000   Median :5.000  
##                                        Mean   : 2.893   Mean   :4.634  
##                                        3rd Qu.: 4.000   3rd Qu.:5.000  
##                                        Max.   :12.000   Max.   :6.000  
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  30.0   Min.   : 0.000   Min.   : 0.000  
##  1st Qu.: 220.0   1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 330.0   Median : 123.0   Median : 1.000   Median : 3.000  
##  Mean   : 433.9   Mean   : 174.9   Mean   : 1.482   Mean   : 3.111  
##  3rd Qu.: 540.0   3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1999.0   Max.   :1745.0   Max.   :10.000   Max.   :10.000  
##   habitaciones   
##  Min.   : 0.000  
##  1st Qu.: 3.000  
##  Median : 3.000  
##  Mean   : 3.605  
##  3rd Qu.: 4.000  
##  Max.   :10.000

1.5. Analisis de correlaciones.

No existe una correlación alta (0.8) entre las variables, sin embargo se notan ciertos comportamientos de tendencias e las relaciones.

data2= data1[, c("piso", "preciom", "areaconst", "parqueaderos", "banios", "habitaciones")]

#Matriz de correlaciones
corrplot::corrplot.mixed(cor(data2), lower="ellipse", upper="number", order="hclust")

2. Análisis de Componentes Principales (PCA)

2.1. Estandarización de datos.

dataZ = scale(data2)
summary(dataZ)
##       piso            preciom          areaconst        parqueaderos    
##  Min.   :-0.7523   Min.   :-1.1437   Min.   :-1.0138   Min.   :-1.1920  
##  1st Qu.:-0.7523   1st Qu.:-0.6508   1st Qu.:-0.6640   1st Qu.:-0.3876  
##  Median :-0.3549   Median :-0.3161   Median :-0.3633   Median :-0.3876  
##  Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000  
##  3rd Qu.: 0.4398   3rd Qu.: 0.3228   3rd Qu.: 0.3782   3rd Qu.: 0.4169  
##  Max.   : 3.6187   Max.   : 4.7620   Max.   :10.9822   Max.   : 6.8521  
##      banios          habitaciones    
##  Min.   :-2.17847   Min.   :-2.4702  
##  1st Qu.:-0.77812   1st Qu.:-0.4148  
##  Median :-0.07794   Median :-0.4148  
##  Mean   : 0.00000   Mean   : 0.0000  
##  3rd Qu.: 0.62224   3rd Qu.: 0.2704  
##  Max.   : 4.82330   Max.   : 4.3813

2.2. Datos faltantes.

colSums(is.na(dataZ))
##         piso      preciom    areaconst parqueaderos       banios habitaciones 
##            0            0            0            0            0            0

2.3. Análisis de componentes principales.

El primer componente principal explica el 52.5% de la variabilidad contenida en la base de datos y entre los dos primeros el 71.1% de los datos, lo cual indicaría que con solo una variable (CP1), que se obtiene mediante una combinación lineal de las variables, se puede resumir gran parte de la variabilidad que contiene la base de datos.

res.pca = prcomp(dataZ)
fviz_eig(res.pca, addlabels = TRUE)

2.4. Plano de los componentes principales.

pcainmo=PCA(dataZ, ncp = 2, graph = FALSE)
fviz_pca_var(pcainmo, col.var = "contrib", gradient.cols = c("blue", "orange"),repel = TRUE) + labs(colour="Contribución")

El primer componente principal está asociado principalmente con la variables Precio, Área y baños, mientras que el segundo componente se puede asociar a la variable Piso, por su parte la variables Habitaciones y Parqueaderos se representan en ambos componentes principales.

pcainmo$var$contrib
##                   Dim.1       Dim.2
## piso          0.8745164 60.09876452
## preciom      22.4652154  6.81152321
## areaconst    23.4743619  0.73870833
## parqueaderos 16.2054901 13.90902683
## banios       24.3347559  0.02054239
## habitaciones 12.6456603 18.42143472

Las características clave que influyen en la variación de precios de las propiedades son principalmente su área y la cantidad de baños. En menor medida se encuentran la cantidad de parqueaderos y habitaciones.

3. Análisis de Conglomerados

3.1. Estandarización de datos.

Detaresumen <- data1 %>%
  group_by(estrato) %>%
  summarise(piso = mean(piso),preciom = mean(preciom),areaconst = mean(areaconst),
    parqueaderos = mean(parqueaderos),banios = mean(banios),habitaciones = mean(habitaciones))

data3= Detaresumen[, c("piso", "preciom", "areaconst", "parqueaderos", "banios", "habitaciones")]
rownames(data3) = c("E3","E4","E5","E6")
## Warning: Setting row names on a tibble is deprecated.
data3Z =scale(data3)

3.2. Distancias euclidianas

dist_estrato = dist(data3Z, method = "euclidean")
dist_estrato
##          E3       E4       E5
## E4 3.126768                  
## E5 3.284412 1.524669         
## E6 5.107045 4.005564 2.642896

3.3. Distribución de los individuos por distancias

# Clúster jerárquico con el método complete
hc_estrato = hclust(dist_estrato, method = 'complete')

# Determinamos a dónde pertenece cada observación
cluster_assigments = cutree(hc_estrato, k = 4)

# asignamos los clusters
data3Z = as.data.frame(data3Z)
assigned_cluster <- data3Z %>% mutate(cluster = as.factor(cluster_assigments))


# gráfico de puntos
ggplot(assigned_cluster, aes(x = preciom, y = areaconst, color = cluster)) +
geom_point(size = 4) +
geom_text(aes(label = cluster), vjust = -.8) + # Agregar etiquetas del clúster
theme_classic()

3.4. Dendograma para los estratos.

plot(hc_estrato, cex = 0.6, main = "Dendograma de Estratos", las=1, ylab = "Distancia euclidiana", xlab = "Grupos")

Se calcula que los estratos que más se parecen (menor distancia euclidiana) son E4 y E5 (d= 1.524669), conformando estos dos estratos un primer clúster. Ya en el dendograma se valida ese supuesto donde se observan 3 conglomerados (E4 y E5), (E3) y (E6).

3.5. Clasificación de los estratos

dendograma <- hclust(dist_estrato, method = "average")
grp <- cutree(dendograma, k = 3)
grp
## E3 E4 E5 E6 
##  1  2  2  3

3.6. Elección del número de conglomerados

barplot(sort(dendograma$height, decreasing = TRUE), horiz = TRUE, 
main = "Agregaciones (distancias euclidianas)",
col = "lightblue", ylab = "Nodo", xlab = "Peso", xlim = c(0, 4))

3.7. Índice de Silhouette promedio

cluster_assigments <- cutree(hc_estrato, k = 3)
sil <- silhouette(cluster_assigments, dist(data3Z))
sil_avg <- mean(sil[,3])
sil_avg
## [1] 0.2338722

El valor más alto del índice de Silhouette se dio al usar tres conglomerados K=3.

Con esto se podría sugerir que las propiedades que están en estrato 4 y 5 pueden tener más característica en común (Piso, Precio, Área, baños, Parqueaderos y Habitaciones) respecto a las propiedades en estrato 3 y 6.

4. Análisis de Correspondencia

4.1. Vefificación de datos faltantes Na.

colSums(is.na(data1))
##         tipo         zona         piso      estrato      preciom    areaconst 
##            0            0            0            0            0            0 
## parqueaderos       banios habitaciones 
##            0            0            0
tabla = table(data1$zona, data1$estrato)
chisq.test(tabla)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla
## X-squared = 3830.4, df = 12, p-value < 2.2e-16

El resultado del análisis indica que se rechaza la hipótesis de independencia de las variables (p-value: 0.0000), un p-valor tan bajo te sugiere que estas dos variables están asociadas de alguna forma (es decir, una puede influir o estar relacionada con la otra).

4.2. Análisis de correspondencia.

resultados_ac = CA(tabla, graph = FALSE)
fviz_ca_biplot(resultados_ac, repel = TRUE)

El gráfico nos permite establecer relaciones como:

El estrato 6 se encuentra ubicado en la Zona Oeste

Los estratos 4 y 5 están ubicados principalmente en la Zona Sur y Norte

El estrato 3 está presente en las Zonas Oriente y Centro

4.3. Grado de representatividad.

valores_prop = resultados_ac$eig ; valores_prop
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.32215213              69.965515                          69.96551
## dim 2 0.12745096              27.680002                          97.64552
## dim 3 0.01084108               2.354483                         100.00000
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")

Se observa que la primera componente resumen el 70%, mientras que los primeros dos ejes (dim 1 y dim 2) explican un 97.65% de la variabilidad de los datos, lo que significa que son altamente representativos de la estructura general de los datos.

5. Conclusiones

  1. Las características clave que influyen en la variación de precios de las propiedades son principalmente su área y la cantidad de baños. En menor medida se encuentran la cantidad de parqueaderos y habitaciones.

  2. Las propiedades que están en estrato 4 y 5 pueden tener más característica en común (Piso, Precio, Área, baños, Parqueaderos y Habitaciones) respecto a las propiedades en estrato 3 y 6.

  3. El estrato 6 se encuentra ubicado en la Zona Oeste. Los estratos 4 y 5 están ubicados principalmente en la Zona Sur y Norte. El estrato 3 está presente en las Zonas Oriente y Centro.