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.

Retos

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:

0.1 Punto 1

Análisis de Componentes Principales: Reducir la dimensionalidad del conjunto de datos y visualizar la estructura de las variables en componentes principales para identificar características clave que influyen en la variación de precios y oferta del mercado.

library(paqueteMODELOS)
data(vivienda)                # base de datos
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id          : num [1:8322] 1147 1169 1350 5992 1212 ...
##  $ zona        : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ piso        : chr [1:8322] NA NA NA "02" ...
##  $ estrato     : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
##  $ preciom     : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
##  $ areaconst   : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
##  $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
##  $ banios      : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
##  $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
##  $ tipo        : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
##  $ barrio      : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
##  $ longitud    : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   id = col_double(),
##   ..   zona = col_character(),
##   ..   piso = col_character(),
##   ..   estrato = col_double(),
##   ..   preciom = col_double(),
##   ..   areaconst = col_double(),
##   ..   parqueaderos = col_double(),
##   ..   banios = col_double(),
##   ..   habitaciones = col_double(),
##   ..   tipo = col_character(),
##   ..   barrio = col_character(),
##   ..   longitud = col_double(),
##   ..   latitud = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>
#Análisis descriptivo de los datos

summary(vivienda)
##        id           zona               piso              estrato     
##  Min.   :   1   Length:8322        Length:8322        Min.   :3.000  
##  1st Qu.:2080   Class :character   Class :character   1st Qu.:4.000  
##  Median :4160   Mode  :character   Mode  :character   Median :5.000  
##  Mean   :4160                                         Mean   :4.634  
##  3rd Qu.:6240                                         3rd Qu.:5.000  
##  Max.   :8319                                         Max.   :6.000  
##  NA's   :3                                            NA's   :3      
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  30.0   Min.   : 1.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 : 2.000   Median : 3.000  
##  Mean   : 433.9   Mean   : 174.9   Mean   : 1.835   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  
##  NA's   :2        NA's   :3        NA's   :1605     NA's   :3       
##   habitaciones        tipo              barrio             longitud     
##  Min.   : 0.000   Length:8322        Length:8322        Min.   :-76.59  
##  1st Qu.: 3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median : 3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   : 3.605                                         Mean   :-76.53  
##  3rd Qu.: 4.000                                         3rd Qu.:-76.52  
##  Max.   :10.000                                         Max.   :-76.46  
##  NA's   :3                                              NA's   :3       
##     latitud     
##  Min.   :3.333  
##  1st Qu.:3.381  
##  Median :3.416  
##  Mean   :3.418  
##  3rd Qu.:3.452  
##  Max.   :3.498  
##  NA's   :3
library(psych)
psych::describe(vivienda)
##              vars    n    mean      sd  median trimmed     mad    min     max
## id              1 8319 4160.00 2401.63 4160.00 4160.00 3083.81   1.00 8319.00
## zona*           2 8319    3.92    1.33    5.00    4.04    0.00   1.00    5.00
## piso*           3 5684    3.77    2.61    3.00    3.37    1.48   1.00   12.00
## estrato         4 8319    4.63    1.03    5.00    4.67    1.48   3.00    6.00
## preciom         5 8320  433.89  328.65  330.00  374.43  207.56  58.00 1999.00
## areaconst       6 8319  174.93  142.96  123.00  149.15   84.51  30.00 1745.00
## parqueaderos    7 6717    1.84    1.12    2.00    1.62    1.48   1.00   10.00
## banios          8 8319    3.11    1.43    3.00    2.99    1.48   0.00   10.00
## habitaciones    9 8319    3.61    1.46    3.00    3.41    1.48   0.00   10.00
## tipo*          10 8319    1.39    0.49    1.00    1.36    0.00   1.00    2.00
## barrio*        11 8319  241.48  128.83  251.00  245.34  171.98   1.00  436.00
## longitud       12 8319  -76.53    0.02  -76.53  -76.53    0.02 -76.59  -76.46
## latitud        13 8319    3.42    0.04    3.42    3.42    0.05   3.33    3.50
##                range  skew kurtosis    se
## id           8318.00  0.00    -1.20 26.33
## zona*           4.00 -0.59    -1.36  0.01
## piso*          11.00  1.28     1.05  0.03
## estrato         3.00 -0.18    -1.11  0.01
## preciom      1941.00  1.85     3.67  3.60
## areaconst    1715.00  2.69    12.91  1.57
## parqueaderos    9.00  2.33     8.31  0.01
## banios         10.00  0.93     1.13  0.02
## habitaciones   10.00  1.63     3.98  0.02
## tipo*           1.00  0.46    -1.78  0.01
## barrio*       435.00 -0.09    -1.23  1.41
## longitud        0.13  0.65     0.58  0.00
## latitud         0.16  0.03    -1.15  0.00

En esta primera aproximación de los datos vemos datos faltantes, sin embargo esto se validará a continuación:

#Validación de datos faltantes

library(mice)
md.pattern(vivienda)

##      preciom id zona estrato areaconst banios habitaciones tipo barrio longitud
## 4808       1  1    1       1         1      1            1    1      1        1
## 1909       1  1    1       1         1      1            1    1      1        1
## 876        1  1    1       1         1      1            1    1      1        1
## 726        1  1    1       1         1      1            1    1      1        1
## 1          1  0    0       0         0      0            0    0      0        0
## 2          0  0    0       0         0      0            0    0      0        0
##            2  3    3       3         3      3            3    3      3        3
##      latitud parqueaderos piso     
## 4808       1            1    1    0
## 1909       1            1    0    1
## 876        1            0    1    1
## 726        1            0    0    2
## 1          0            0    0   12
## 2          0            0    0   13
##            3         1605 2638 4275
sum(is.na(vivienda))
## [1] 4275

Se observa que las variables piso y parqueaderos son las variables con mayor número de datos faltantes dentro de la base de datos. Por lo anterior, podemos aplicar dos opciones para continuar con el análisis: eliminar los na de la base de datos o realizar ponderaciones para reemplazar estos. Por facilidad y precisión de los resultados se balancea la base de datos por medio de la eliminación de los na.

0.1.1 Eliminación de datos faltantes

Eliminar los datos faltantes:

#Validación de datos faltantes

vivienda_op1 = vivienda

delete.na <- function(df, n=0) {
 df[rowSums(is.na(df)) <= n,]
}

vivienda_op1 = delete.na(vivienda_op1)

head(vivienda_op1,n=20)
## # A tibble: 20 × 13
##       id zona   piso  estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  5992 Zona … 02          4     400       280            3      5            3
##  2  1212 Zona … 01          5     260        90            1      2            3
##  3  1724 Zona … 01          5     240        87            1      3            3
##  4  2326 Zona … 01          4     220        52            2      2            3
##  5  4386 Zona … 01          5     310       137            2      3            4
##  6  1209 Zona … 02          5     320       150            2      4            6
##  7  1592 Zona … 02          5     780       380            2      3            3
##  8  4460 Zona … 02          4     625       355            3      5            5
##  9  6081 Zona … 02          5     750       237            2      6            6
## 10  7497 Zona … 02          6     520        98            2      2            2
## 11  7824 Zona … 02          4     600       160            1      4            5
## 12  7987 Zona … 02          5     420       200            4      4            5
## 13  3495 Zona … 03          5     490       118            2      4            4
## 14  5424 Zona … 03          4     320       108            2      3            3
## 15  6271 Zona … 03          5     385       103            2      2            3
## 16  3817 Zona … 04          3     175        80            1      2            3
## 17   509 Zona … 05          6     820       377            1      4            4
## 18  2323 Zona … 05          6     450       103            2      3            4
## 19  5098 Zona … 05          4     290        96            1      2            3
## 20  6043 Zona … 05          5     420       124            3      3            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Una vez eliminados los datos faltantes podemos analizar el comportamiento de la correlación entre las variables de la base de datos.

#Correlación

library(psych)
pairs.panels(vivienda_op1, 
             pch=20,
             stars=T,
             main="Gráfico de Correlación")  

# Red de correlaciones
library(corrr)
cor <- correlate(vivienda_op1) ; cor 
## # A tibble: 9 × 10
##   term             id estrato preciom areaconst parqueaderos banios habitaciones
##   <chr>         <dbl>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1 id          NA       0.392   0.326     0.161        0.237   0.240      0.0346 
## 2 estrato      0.392  NA       0.587     0.270        0.431   0.408     -0.0522 
## 3 preciom      0.326   0.587  NA         0.698        0.700   0.689      0.295  
## 4 areaconst    0.161   0.270   0.698    NA            0.604   0.681      0.556  
## 5 parqueader…  0.237   0.431   0.700     0.604       NA       0.598      0.308  
## 6 banios       0.240   0.408   0.689     0.681        0.598  NA          0.597  
## 7 habitacion…  0.0346 -0.0522  0.295     0.556        0.308   0.597     NA      
## 8 longitud    -0.958  -0.372  -0.286    -0.128       -0.207  -0.209     -0.0158 
## 9 latitud     -0.124  -0.155  -0.0725   -0.0355      -0.0946 -0.108      0.00718
## # ℹ 2 more variables: longitud <dbl>, latitud <dbl>
network_plot(cor)

Aunque estas herramientas no son tan dicientes, evidencian algunas relaciones más que interesantes entre variables.

Ahora, con el objetivo de evitar que las variables que tiene una escala con valores más grandes afecten las estimaciones realizadas (sesgos) se realiza la estandarización de las variables antes de proceder a realizar el proceso de estimación de los componentes principales.

library(tidyverse)
vivienda_op1Z= vivienda_op1[4:9] %>%
scale()
head(vivienda_op1Z) # primeros 6 registros
##         estrato    preciom  areaconst parqueaderos     banios habitaciones
## [1,] -0.9046263 -0.1756310  0.7609789    1.0779092  1.3178809   -0.4241459
## [2,]  0.1749079 -0.6055839 -0.6129041   -0.7415001 -0.9022913   -0.4241459
## [3,]  0.1749079 -0.6670057 -0.6345970   -0.7415001 -0.1622339   -0.4241459
## [4,] -0.9046263 -0.7284276 -0.8876807    0.1682046 -0.9022913   -0.4241459
## [5,]  0.1749079 -0.4520293 -0.2730489    0.1682046 -0.1622339    0.3272519
## [6,]  0.1749079 -0.4213184 -0.1790463    0.1682046  0.5778235    1.8300475

En la parte anterior, se utilizaron únicamente las variables númericas y no categoricas.

#Generación del APC
pca<-prcomp(vivienda_op1Z)
summary(pca)
## Importance of components:
##                           PC1    PC2     PC3     PC4     PC5     PC6
## Standard deviation     1.8866 1.0884 0.69530 0.58528 0.49647 0.42886
## Proportion of Variance 0.5932 0.1974 0.08057 0.05709 0.04108 0.03065
## Cumulative Proportion  0.5932 0.7906 0.87117 0.92827 0.96935 1.00000

Del resultado anterior, es importante resaltar la variable “Cumulative Proportion” la cual expresa la varianza explicada por cada uno de los componentes.

library(paqueteMODELOS)
library(factoextra)
fviz_eig(pca, addlabels = TRUE)

En este caso el primer componente principal explica el 59.3% de la variabilidad contenida en la base de datos y entre los dos primeros se casi el 80% de los datos (79.1), 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.

#Contribución de los componentes y dirección de los mismos

fviz_pca_var(pca,
col.var = "contrib", # Color by contributions to the PC
gradient.cols = c("#FF7F00",  "#034D94"),
repel = TRUE     # Avoid text overlapping
)

Al visualizar las variables en el plano de los componentes principales permite identificar el sentido y la caracterización de los componentes. En este ejercicio el primer componente principal está asociado principalmente con la variables precio, mientras que el segundo componente se puede asociar a la variable habitaciones.

# Componentes y tipo de vivienda
fviz_pca_biplot(pca, 
repel = TRUE,
habillage = vivienda_op1$tipo,
col.var = "#034A94", # Variables color
col.ind = c("#DEDEDE", "#034A94")  # Individuals color
)

La gráfica anterior muestra la insidencia de los dos primeros factores principales dado el tipo de vivienda.

0.2 Punto 2

Análisis de Conglomerados: Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas de las ofertas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.

0.2.1 Carácteristicas por zona

data(vivienda)
vivienda_op1 = vivienda

delete.na <- function(df, n=0) {
  df[rowSums(is.na(df)) <= n,]
}

vivienda_op1 = delete.na(vivienda_op1)

v1 = vivienda_op1[2]
v1<-replace(v1,v1=="Zona Sur","ZS")
v1<-replace(v1,v1=="Zona Norte","ZN")
v1<-replace(v1,v1=="Zona Centro","ZC")
v1<-replace(v1,v1=="Zona Oriente","ZOr")
v1<-replace(v1,v1=="Zona Oeste","ZOe")

v2 = vivienda_op1[5:9]
  
vivienda_f = data.frame(v2,v1)  
  
df <- data.frame(vivienda_f)
zona <- df[,6]

di=data.frame(df)
pairs(di[,1:5], col = palette(),lower.panel = NULL)

par(xpd = TRUE)

Lo anterior, muestra las relaciones entre la variables de la base de datos. Una vez hecho esto, es necesario validar el número de cluster que se deben construir en llave de las zonas que tiene la base de datos. Para esto, se usará una combinación entre k-meas y componentes principales.

#Combinación K-means y PCA

d2 <- scale(di[,1:5])
rownames(d2) <- di$zona
fviz_nbclust(x = d2, FUNcluster = kmeans, method = "wss", k.max = 15, 
             diss = get_dist(d2, method = "euclidean"), nstart = 50)

Con base en este resultado se observa que existe un cluster dominante, sin embargo se pueden probar estrategias visuales para ver como se comportan los cluster sobre un plano.

d2f=data.frame(d2)
km_clusters <- kmeans(x = d2f, centers = 3, nstart = 50)
fviz_cluster(object = km_clusters, data = d2f, show.clust.cent = TRUE,
             ellipse.type = "euclid", star.plot = TRUE, repel = TRUE,
             pointsize=0.05,outlier.color="darkred") +
  labs(title = "Resultados clustering K-means") +
  theme_bw() +  theme(legend.position = "none")

Dado el volumen de datos se hace necesario mejorar la visualización de los cluster y su relación frente al total de muestra.

# Comportamiento de los cluster de acuerdo a su número
require(cluster)
pam.res <- pam(d2f, 5)
# Visualización
fviz_cluster(pam.res, geom = "point", ellipse.type = "norm",
             show.clust.cent = TRUE,star.plot = TRUE)+
  labs(title = "Resultados clustering K-means")+ theme_bw()

En esta gráfica se observan cinco cluster, sin embargo se ve que varios de ellos se traslapan.

# Comportamiento de los cluster de acuerdo a su número
require(cluster)
pam.res <- pam(d2f, 4)
# Visualización
fviz_cluster(pam.res, geom = "point", ellipse.type = "norm",
             show.clust.cent = TRUE,star.plot = TRUE)+
  labs(title = "Resultados clustering K-means")+ theme_bw()

Con la reducción de un cluster se observa que los cluster 1 y 4 siguen traslapandose notariamente.

# Comportamiento de los cluster de acuerdo a su número
require(cluster)
pam.res <- pam(d2f, 3)
# Visualización
fviz_cluster(pam.res, geom = "point", ellipse.type = "norm",
             show.clust.cent = TRUE,star.plot = TRUE)+
  labs(title = "Resultados clustering K-means")+ theme_bw()

Aquí se observan mejor delimitados los clusters que los dos ejemplos previos, asimismo, guarda mejor relación con el resultado por componentes principales obtenido anteriormente.

Por otro lado, en esta gráfica se evidencia que hay cierto grado de conflicto entre los clusters, ya que tienen cierta área solapada. Estas representaciones mezclan cluster y PCA, pero no indican el grado de representación de cada variable en cada uno de los componentes. Por lo anterior, se incluirá una técnica adicional:

#Biplot PCA y K-Means para medir representatividad
# PCA
pca <- prcomp(vivienda_f[,-6], scale=TRUE)
df.pca <- pca$x
# Cluster over the three first PCA dimensions
kc <- kmeans(df.pca[,1:3], 3)
fviz_pca_biplot(pca, label="var", habillage=as.factor(kc$cluster)) +
  labs(color=NULL) + ggtitle("") +
  theme(text = element_text(size = 15),
        panel.background = element_blank(), 
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"),
        legend.key = element_rect(fill = "white"))

Aquí se observa que el número de cluster podría ser dos y no tres como se pensó inicialmente.

# Comportamiento de los cluster de acuerdo a su número
require(cluster)
pam.res <- pam(d2f, 2)
# Visualización
fviz_cluster(pam.res, geom = "point", ellipse.type = "norm",
             show.clust.cent = TRUE,star.plot = TRUE)+
  labs(title = "Resultados clustering K-means")+ theme_bw()

Por útlimo, se presenta un demograma de los datos.

vivienda_z =scale(vivienda_f[1:5])
vivienda_z = as.data.frame(vivienda_z)
head(vivienda_z, n=10)
##       preciom  areaconst parqueaderos     banios habitaciones
## 1  -0.1756310  0.7609789    1.0779092  1.3178809   -0.4241459
## 2  -0.6055839 -0.6129041   -0.7415001 -0.9022913   -0.4241459
## 3  -0.6670057 -0.6345970   -0.7415001 -0.1622339   -0.4241459
## 4  -0.7284276 -0.8876807    0.1682046 -0.9022913   -0.4241459
## 5  -0.4520293 -0.2730489    0.1682046 -0.1622339    0.3272519
## 6  -0.4213184 -0.1790463    0.1682046  0.5778235    1.8300475
## 7   0.9913841  1.4840752    0.1682046 -0.1622339   -0.4241459
## 8   0.5153648  1.3033011    1.0779092  1.3178809    1.0786497
## 9   0.8992513  0.4500474    0.1682046  2.0579382    1.8300475
## 10  0.1929001 -0.5550564    0.1682046 -0.9022913   -1.1755437
library(tidyverse)
# distancia euclidiana
dist_emp <- dist(vivienda_z, method = 'euclidean')

# Cluster jerarquico con el método complete
hc_emp <- hclust(dist_emp, method = 'complete')

plot(hc_emp, cex = 0.6, main = "Dendograma de Viviendas", las=1,
     ylab = "Distancia euclidiana", xlab = "Grupos")
rect.hclust(hc_emp, k = 2, border = 2:5)

0.3 Punto 3

Análisis de Correspondencia: Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio), para identificar patrones de comportamiento de la oferta en mercado inmobiliario.

#Comportamiento de los datos



library(FactoMineR)
library(ggplot2)
library(FactoClass)
library(factoextra)
library(Rcpp)
library(broom)
library(pander)
library(corrplot)
library(gridExtra)

DatosInicial <- subset(vivienda_op1, select = c("zona", "tipo", "barrio", "estrato") )

Zona <- DatosInicial$zona
Tipo <- DatosInicial$tipo
Barrio <- DatosInicial$barrio
Estrato <- DatosInicial$estrato

Datos <- cbind(DatosInicial,Zona,Tipo,Barrio,Estrato)
Datos[,1:4] <- NULL

summary(Datos)
##      Zona               Tipo              Barrio             Estrato     
##  Length:4808        Length:4808        Length:4808        Min.   :3.000  
##  Class :character   Class :character   Class :character   1st Qu.:4.000  
##  Mode  :character   Mode  :character   Mode  :character   Median :5.000  
##                                                           Mean   :4.838  
##                                                           3rd Qu.:6.000  
##                                                           Max.   :6.000
F1<-ggplot(Datos, aes(x=Zona)) + geom_bar(fill= "#DDB4EB")
F2<-ggplot(Datos, aes(x=Tipo)) + geom_bar(fill= "#FFD4A5")
F3<-ggplot(Datos, aes(x=Barrio)) + geom_bar(fill= "#41894A")
F4<-ggplot(Datos, aes(x=Estrato)) + geom_bar(fill= "#FFD4A5")
F5 <- grid.arrange(F1,F2,F3,F4, nrow = 4)

De acuerdo con los resultados previos, se observa el comportamiento de las variables zona, tipo y barrio. Este último, tiene muchas observaciones que veremos más adelante tienen ingerencia sobre algunos resultados interesantes.

Ahora, revisaremos si existen datos faltantes dentro del conjunto de información:

#Datos faltantes

library(mice)
grafico <-md.pattern(Datos, rotate.names = TRUE)
##  /\     /\
## {  `---'  }
## {  O   O  }
## ==>  V <==  No need for mice. This data set is completely observed.
##  \  \|/  /
##   `-----'

El resultado muestra que no hay datos faltantes, lógicamente por el ajuste y limpieza que se hizo previamente a los datos.

#Datos con que se va a trabajar

library(FactoMineR)
tabla <- table(Datos$Barrio, Datos$Zona)
head(tabla, n=10)
##                
##                 Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
##   3 de julio              0          0          0            0        1
##   acopi                   0         20          0            0        1
##   aguablanca              0          0          0            0        1
##   aguacatal               0          0         52            0        0
##   alameda                 3          0          0            0        1
##   alamos                  0          4          0            0        0
##   alférez real           0          0          0            0        2
##   alfonso lopez           0          0          0            1        0
##   alfonso lópez           0          0          0            7        0
##   alto jordán             0          0          0            0        1

Prueba de chi-cuadrado

chisq.test(tabla)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla
## X-squared = 18029, df = 1088, p-value < 2.2e-16

El resultado indica que se rechaza la hipótesis de independencia de las variables (p-value: 0.0000), indicando grado tipo de relación entre ellas.

A continuación, se muestra una tabla en la cual se observa la marcación de los barrios según la zona a la cual pertencen. Es así como, se procede a realizar el análisis de correspondencia que consistes en estimar las coordenadas para cada uno de los niveles de ambas variables y representarlas en un plano cartesiano

library(FactoMineR)
library(factoextra)
library(gridExtra)
resultados_ac <- CA(tabla)

plot.CA(resultados_ac)

Para medir el grado de representatividad del proceso calculas los valores de la varianza acumulada, utilizando para ellos los valores propios de la matriz de discrepancias

library(factoextra)
eig.val <- get_eigenvalue(resultados_ac)
eig.val
##       eigenvalue variance.percent cumulative.variance.percent
## Dim.1  0.9825352         26.20169                    26.20169
## Dim.2  0.9529849         25.41366                    51.61534
## Dim.3  0.9498563         25.33023                    76.94557
## Dim.4  0.8645164         23.05443                   100.00000
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 30))+ggtitle("")+
  ylab("Porcentaje de varianza explicado") + xlab("Ejes")

Los resultados indican que la primera componente resumen el 26.2% y los dos primeros componentes prepresentados en el plano factorial, mientras que los dos primeros ejes resumen un 51.6% de los datos. Esto no muestra un comportamiento marcado entre los componentes, dado que los componentes 3 y 4 tienen niveles similares al 1 y 2.

Adiconalmente, podemos hacer le análisis de correspondencia entre zona y estrato:

#Datos con que se va a trabajar

library(FactoMineR)
tabla <- table(Datos$Estrato, Datos$Zona)
head(tabla, n=10)
##    
##     Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
##   3          33        141         19           94      147
##   4           3        184         51            2      973
##   5           0        482        181            1     1195
##   6           0         79        502            0      721

Prueba de chi-cuadrado

chisq.test(tabla)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla
## X-squared = 2172.8, df = 12, p-value < 2.2e-16

El resultado indica que se rechaza la hipótesis de independencia de las variables (p-value: 0.0000), indicando grado tipo de relación entre ellas.

A continuación, se muestra una tabla en la cual se observa la marcación de los barrios según la zona a la cual pertencen. Es así como, se procede a realizar el análisis de correspondencia que consistes en estimar las coordenadas para cada uno de los niveles de ambas variables y representarlas en un plano cartesiano

library(FactoMineR)
library(factoextra)
library(gridExtra)
resultados_ac <- CA(tabla)

plot.CA(resultados_ac)

Para medir el grado de representatividad del proceso calculas los valores de la varianza acumulada, utilizando para ellos los valores propios de la matriz de discrepancias

library(factoextra)
eig.val <- get_eigenvalue(resultados_ac)
eig.val
##       eigenvalue variance.percent cumulative.variance.percent
## Dim.1 0.29526876        65.338252                    65.33825
## Dim.2 0.13919088        30.800716                    96.13897
## Dim.3 0.01744831         3.861032                   100.00000
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
  ylab("Porcentaje de varianza explicado") + xlab("Ejes")

Se observa la correspondencia entre la zona Oeste y el estrato 6.

0.4 Punto 4

Visualización de resultados: Presentar gráficos, mapas y otros recursos visuales para comunicar los hallazgos de manera clara y efectiva a la dirección de la empresa.

Uno de los resultados más importantes es haber encontrao dos cluster en los datos, entonces podemos revisar que pasa con las demás variables dentro de estos:

cluster<-pam.res$clustering

x <-data.frame(vivienda_op1,cluster)

summary(x)
##        id           zona               piso              estrato     
##  Min.   :   1   Length:4808        Length:4808        Min.   :3.000  
##  1st Qu.:2479   Class :character   Class :character   1st Qu.:4.000  
##  Median :4474   Mode  :character   Mode  :character   Median :5.000  
##  Mean   :4427                                         Mean   :4.838  
##  3rd Qu.:6413                                         3rd Qu.:6.000  
##  Max.   :8316                                         Max.   :6.000  
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  40.0   Min.   : 1.000   Min.   : 0.000  
##  1st Qu.: 244.5   1st Qu.:  85.0   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 350.0   Median : 123.0   Median : 2.000   Median : 3.000  
##  Mean   : 457.2   Mean   : 174.8   Mean   : 1.815   Mean   : 3.219  
##  3rd Qu.: 560.0   3rd Qu.: 225.0   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1999.0   Max.   :1500.0   Max.   :10.000   Max.   :10.000  
##   habitaciones        tipo              barrio             longitud     
##  Min.   : 0.000   Length:4808        Length:4808        Min.   :-76.59  
##  1st Qu.: 3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median : 3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   : 3.564                                         Mean   :-76.53  
##  3rd Qu.: 4.000                                         3rd Qu.:-76.52  
##  Max.   :10.000                                         Max.   :-76.46  
##     latitud         cluster     
##  Min.   :3.333   Min.   :1.000  
##  1st Qu.:3.378   1st Qu.:1.000  
##  Median :3.408   Median :2.000  
##  Mean   :3.414   Mean   :1.531  
##  3rd Qu.:3.451   3rd Qu.:2.000  
##  Max.   :3.498   Max.   :2.000

Es importante recordar que para el ejercicio se validó que tan solo existían dos cluster y con el summary de información se observa que ambos cluster tienen casi la misma cantidad de observaciones.

Aquí se observa la diferencia entre los precios promedio del metro cuadro por cada uno de los cluster. Gráficamente esto se puede ver así:

boxplot(x$preciom~x$cluster,
        main = "Distribución del precio del metro cuadrado por cluster",
        ylab="Precio del metro cuadrado",
        xlab = "Cluster", las=1,
        col=c("#f4d35e","#ee964b"))

Por otro lado, es importante identificar que zonas hacen parte de cual cluster, dado que esto permitiria la estrategia de precios en términos de los inmuebles se ajuste dado que ese grupo tiene características similares.

conteo <- table(x$cluster,x$zona)
barplot(conteo, main="Tipo de vivienda por zona",  
        xlab="Categorías",
        col=c("#0d3b66","#f4d35e"),
        legend = rownames(conteo),
        las=1, ylim = c(0,5000), 
        names.arg=c("Zona Centro","Zona Norte","Zona Oeste","Zona Oriente","Zona Sur"))

Se observa que las zonas Sur y Norte se relacionan en mayor medida con el cluster 2. Así las cosas, se podría pensar en una estrategia para ajustar los precios del metro cuadrado de las viviendas de dichas zonas. Por otro lado, la zona Oeste tiene mayor relación con el cluster 1. En cuando a las zonas Centro y Oriente, estas se dividen casi proporcionalmente entre los cluster de análisis. Sin embargo, esta información le permitiría a la gerencia ajustar precios de dichos inmuebles.

En términos de tipo de inmueble cual es su relación con los clusters:

conteo <- table(x$cluster,x$tipo)
barplot(conteo, main="Tipo de inmueble",  
        xlab="Categorías",
        col=c("#0d3b66","#f4d35e"),
        legend = rownames(conteo),
        las=1, ylim = c(0,5000), 
        names.arg=c("Casa","Apartamento"))

Aquí se observa que las casas están relacionadas principalmente con el cluster 2 y los apartamentos con el cluster 1. Así las cosas, este resultado puede explicar el comportamiento de los precios promedio de los cluster y dar herramientas para que la gerencia pueda ajustar precios a estos inmuebles.

En relación con el estrato socioeconomico, existe la siguiente relación con el cluster al que pertenecen:

conteo <- table(x$cluster,x$estrato)
barplot(conteo, main="Tipo de vivienda estrato",  
        xlab="Categorías",
        col=c("#0d3b66","#f4d35e"),
        legend = rownames(conteo),
        las=1, ylim = c(0,5000), 
        names.arg=c("Estrato 3", "Estrato 4", "Estrato 5", "Estrato 6"))

Se observa que el estrato 6 está relacionado con el cluster 1 y que a medida que el estrato baja el bluster 2 tiene mayor presencia entre los inmuebles de dicho estrato. Este resultado puede ayudar a realizar ajuste en los precios y hacer estartegias de nicho para la oferta de bienes raíces por cluster.

0.5 Recomendaciones

Revisar la clasificación de cluster dentro de las zonas de la ciudad, esto puede dar indicios de proyectos que pueden mejorar la rentabilidad y el retorno de las inversiones de la empresa. Es posible que por desconocimiento se esté pensando que ciertas zonas de la ciudad no pueden adquirir inmuebles de mayor cuantía.