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.
library(paqueteMODELOS)
## Loading required package: boot
## Loading required package: broom
## Loading required package: GGally
## Loading required package: ggplot2
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
## Loading required package: gridExtra
## Loading required package: knitr
## Loading required package: summarytools
## Warning in fun(libname, pkgname): couldn't connect to display ":0"
## system might not have X11 capabilities; in case of errors when using dfSummary(), set st_options(use.x11 = FALSE)
library(cluster)
library(factoextra)
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(tidyr)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:gridExtra':
##
## combine
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(naniar)
vivienda<-data.frame(vivienda)
dim(vivienda)
## [1] 8322 13
names(vivienda)
## [1] "id" "zona" "piso" "estrato" "preciom"
## [6] "areaconst" "parqueaderos" "banios" "habitaciones" "tipo"
## [11] "barrio" "longitud" "latitud"
names(vivienda)<-c("Id", "Zona", "Piso", "Estrato", "PrecioM2",
"AreaConstruida", "NParqueaderos", "NBaños","NHabitaciones",
"TipoVivienda", "Barrio", "Longitud", "Latitud")
El conjunto de datos con el que se está trabajando está compuesto por 8322 filas y 13 columnas, lo que se traduce en 8322 observaciones (viviendas) con 13 variables para cada una de ellas.
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
## PrecioM2 AreaConstruida NParqueaderos NBaños
## 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
## NHabitaciones TipoVivienda 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
Se procede a validar el número de faltantes por cada variable
faltantes <- colSums(is.na(vivienda)) %>% # dataframe de faltantes por variable
as.data.frame()
faltantes
## .
## Id 3
## Zona 3
## Piso 2638
## Estrato 3
## PrecioM2 2
## AreaConstruida 3
## NParqueaderos 1605
## NBaños 3
## NHabitaciones 3
## TipoVivienda 3
## Barrio 3
## Longitud 3
## Latitud 3
Las variables Piso y la Variable Número de parqueaderos son las que representan el mayor número de faltantes con 32% y un 19% respectivamente
missing_data <- vivienda %>%
summarise_all(~ mean(is.na(.)) * 100) %>%
gather(key = "variable", value = "percent_missing")
# gráfico
ggplot(missing_data, aes(x = reorder(variable, -percent_missing), y = percent_missing, fill = percent_missing)) +
geom_bar(stat = "identity", show.legend = FALSE) +
geom_text(aes(label = paste0(round(percent_missing, 1), "%")),
vjust = -0.5, size = 3, color = "black") +
scale_fill_gradient(low = "lightblue", high = "red") +
labs(title = "Porcentaje de valores faltantes por variable",
x = "Variable",
y = "Porcentaje de valores faltantes") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 10))
Se procede con la variable Piso para tratar los valores faltantes con la mediana,para ello se toma la decisión de dividir los faltantes por la variable tipo de vivienda, teniendo en cuenta que las casas y apartamentos tienen una estructura de pisos diferente.
vivienda$Piso<- as.numeric(
as.factor(vivienda$Piso))
# valor variable cuando es apartamento
piso_aparta <- subset(vivienda, TipoVivienda == "Apartamento" & is.na(Piso))
dim(piso_aparta)
## [1] 1381 13
piso_aparta2 <- subset(vivienda, TipoVivienda == "Apartamento" & !is.na(Piso))
dim(piso_aparta2)
## [1] 3719 13
mediana_piso_apartamento <- median(piso_aparta2$Piso, na.rm = TRUE)
vivienda$Piso[vivienda$TipoVivienda == "Apartamento" & is.na(vivienda$Piso)] <-mediana_piso_apartamento
#valor variable cuando es casa
piso_casa <- subset(vivienda, TipoVivienda == "Casa" & is.na(Piso))
dim(piso_casa)
## [1] 1254 13
piso_casa2 <- subset(vivienda, TipoVivienda == "Casa" & !is.na(Piso))
dim(piso_casa2)
## [1] 1965 13
mediana_piso_casa <- median(piso_casa2$Piso, na.rm = TRUE)
vivienda$Piso[vivienda$TipoVivienda == "Casa" & is.na(vivienda$Piso)] <-mediana_piso_casa
Los faltantes correspondientes a la variable Parqueadero se aborda, asumiendo que los valores nulos indican que no se tiene parquedero por lo que se imputan con valor 0
vivienda$NParqueaderos[is.na(vivienda$NParqueaderos)] <- 0
faltantes <- colSums(is.na(vivienda)) %>% # dataframe de faltantes por variable
as.data.frame()
faltantes
## .
## Id 3
## Zona 3
## Piso 3
## Estrato 3
## PrecioM2 2
## AreaConstruida 3
## NParqueaderos 0
## NBaños 3
## NHabitaciones 3
## TipoVivienda 3
## Barrio 3
## Longitud 3
## Latitud 3
gg_miss_var(vivienda)
vivienda_final<-na.omit(vivienda)
gg_miss_var(vivienda_final)
dim(vivienda_final)
## [1] 8319 13
Despues del tratamiento de datos faltantes, el conjunto de datos cuenta con 8319 registros.
vivienda_final_scaled <- vivienda_final %>%
select(Piso, PrecioM2, AreaConstruida, NParqueaderos, NBaños, NHabitaciones, Longitud, Latitud) %>%
mutate_all(scale)
Matriz de correlación
library(corrplot)
## corrplot 0.95 loaded
cor_matrix <- cor(vivienda_final_scaled)
# Matriz de correlación
corrplot(cor_matrix, method = "color", col = colorRampPalette(c("blue", "white", "red"))(200),
addCoef.col = "black",
tl.col = "black", tl.srt = 45,
number.cex = 0.7,
cl.pos = "r")
res.pca <- prcomp(vivienda_final_scaled)
fviz_eig(res.pca, addlabels = TRUE)
# visualización en el plano
fviz_pca_var(res.pca,
col.var = "contrib", # Color by contributions to the PC
gradient.cols = c("#FF7F00", "#034D94"),
repel = TRUE # Avoid text overlapping
)
Para el análisis de conglomerado se selecciona el algoritmo de kmeans y se procede con el metodo del codo para evaluar el número optimo de centroides.
set.seed(123) # Asegura resultados reproducibles
wss <- vector() # Lista vacía para guardar los resultados
for (k in 1:10) {
kmeans_model <- kmeans(vivienda_final_scaled, centers = k, nstart = 25)
wss[k] <- kmeans_model$tot.withinss # Suma de errores
}
# Graficar el método del codo
plot(1:10, wss, type = "b", pch = 19, frame = FALSE,
xlab = "Número de Clusters (K)", ylab = "Suma de errores dentro del cluster",
main = "Método del Codo para determinar K")
De acuerdo a la grafica del Codo se procede a tener 6 centroides o
clusters
#Kmean con 6 centroides
set.seed(123)
km_result <- kmeans(vivienda_final_scaled, centers = 6, nstart = 25)
# Agregar la clasificación de clusters al dataset original
dfkmean <- vivienda_final_scaled
dfkmean <- as.data.frame(dfkmean)
dfkmean$cluster <- as.factor(km_result$cluster)
Revisión de los clusters en relación al precio por metro cuadrado y el area construida
ggplot(dfkmean, aes(x = PrecioM2, y = AreaConstruida, color = cluster)) +
geom_point() +
labs(title = "Resultados de K-means")
Revisión de los clusters en relación al precio por metro cuadrado y el número de habitaciones
ggplot(dfkmean, aes(x = PrecioM2, y =NHabitaciones , color = cluster)) +
geom_point() +
labs(title = "Resultados de K-means")
Variables zona-estrato
library(FactoMineR)
library(gridExtra)
tabla <- table(vivienda_final$Zona, vivienda_final$Estrato)
colnames(tabla) <- c("Estrato3", "Estrato4", "Estrato5", "Estrato6" )
tabla
##
## Estrato3 Estrato4 Estrato5 Estrato6
## Zona Centro 105 14 4 1
## Zona Norte 572 407 769 172
## Zona Oeste 54 84 290 770
## Zona Oriente 340 8 2 1
## Zona Sur 382 1616 1685 1043
chisq.test(tabla)
##
## Pearson's Chi-squared test
##
## data: tabla
## X-squared = 3830.4, df = 12, p-value < 2.2e-16
resultados_ac <- CA(tabla)
Revisión varianza
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")
Revisión variables zona-tipo vivienda
tabla2 <- table(vivienda_final$Zona, vivienda_final$TipoVivienda)
colnames(tabla2) <- c("Apartamento","Casa")
tabla2
##
## Apartamento Casa
## Zona Centro 24 100
## Zona Norte 1198 722
## Zona Oeste 1029 169
## Zona Oriente 62 289
## Zona Sur 2787 1939
chisq.test(tabla2)
##
## Pearson's Chi-squared test
##
## data: tabla2
## X-squared = 690.93, df = 4, p-value < 2.2e-16
resultados_ac2 <- CA(tabla2)
Revisión varianza
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, 90))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
Revisión de variables Estrato-tipo vivienda
tabla3 <- table(vivienda_final$Estrato, vivienda_final$TipoVivienda)
colnames(tabla3) <- c("Apartamento","Casa")
tabla3
##
## Apartamento Casa
## 3 639 814
## 4 1404 725
## 5 1766 984
## 6 1291 696
chisq.test(tabla3)
##
## Pearson's Chi-squared test
##
## data: tabla3
## X-squared = 224.33, df = 3, p-value < 2.2e-16
library(gridExtra)
library(FactoMineR)
library(factoextra)
resultados_ac3 <- CA(tabla3)
Revisión varianza
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, 90))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
De acuerdo al PCA, se evidencia que los componentes del 1 al 5 capturan el 89% de la varianza del total de conjuntos de datos. Así mismo se puede inferir que las variables Precio, Área construida, Número de baños, Número de habitaciones son las que más contribuyen a los componentes principales. Esta inferencia también es evidente en la matriz de correlación.
De acuerdo al análisis de conglomerados, se envidencia que el número de clusters con lo que se puede ver diferencias significativa en el conjunto de datos, es de 6. Dentro de este análisis podemos inferir que para el cluster 6 concentra las viviendas con mayor costo y mayor tamaño por metro cuadrado, así mismo los clusters 1,2 y 3 cuentan con menor número de habitaciones y por ende su costo también tiende a ser menor.
El Análisis de correspondencia nos permite inferir que las zonas de las ciudad tienen una alta relación con el estrato socioeconomico de las viviendas, dando como ejemplo que la zona Oeste concentra el estrato 6 y la zona Sur el estrato 4 y 5.
Otro hallazgo que evidencia el análisis de correspondencia es que la zona Sur es la que mayor número de casas y apartamentos tiene respecto a las demas zonas, en contraste con la zona centro la cual cuenta con el menor número de viviendas dentro del conjunto de datos.
Por último se puede evidenciar que el estrato 5 es el estrato que mas número de viviendas tiene en la ciudad en comparación del estrato 3, de acuerdo al conjunto de datos.