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:
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.
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.
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.
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)
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.
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.
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.