OBJETIVO DEL TRABAJO: Análisis holístico de datos de vivienda para comprender a profundidad el mercado y con estos datos identificar patrones, relaciones y segmentaciones relevantes que permitan mejorar la toma de decisiones en cuanto a la compra, venta y valoración de propiedades.
Fuente : datos tomados de OLX mediante procedimiento webscraping y contenidos en paqueteMOD
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.
#ANALISIS EXPLORATORIO DE LA DATA#
DataVivienda <-read.csv("C:/Users/lberm/OneDrive/Documentos/MAESTRIA/MODELOS_APRENDIZAJE_ESTADIS/vivienda.csv")
str(DataVivienda)
## 'data.frame': 8322 obs. of 13 variables:
## $ id : int 8312 8311 8307 8296 8297 8298 8299 8300 8286 8287 ...
## $ zona : chr "Zona Oeste" "Zona Oeste" "Zona Oeste" "Zona Sur" ...
## $ piso : int 4 1 NA 2 NA NA 2 NA NA 2 ...
## $ estrato : int 6 6 5 3 5 5 6 5 5 5 ...
## $ preciom : int 1300 480 1200 220 330 1350 305 480 275 285 ...
## $ areaconst: num 318 300 800 150 112 390 125 280 74 120 ...
## $ parquea : int 2 1 4 1 2 8 2 4 1 2 ...
## $ banios : int 4 4 7 2 4 10 3 4 2 4 ...
## $ habitac : int 2 4 5 4 3 10 3 4 3 3 ...
## $ tipo : chr "Apartamento" "Casa" "Casa" "Casa" ...
## $ barrio : chr "arboleda" "normandía" "miraflores" "el guabal" ...
## $ longitud : num -76576 -76571 -76568 -76565 -76565 ...
## $ latitud : num 3454 3454 3455 3417 3408 ...
Se observa que la base de datos tiene 8322 registros y 13 variables dentro de las cuales cuenta con 3 variables cualitativas y 10 cuantitativas.
Revision del dataset para evaluar la cantidad y la calidad de las variables.
sum(is.na(DataVivienda$zona)) # zona
## [1] 3
sum(is.na(DataVivienda$piso))# piso
## [1] 2638
sum(is.na(DataVivienda$estrato)) # estrato
## [1] 3
sum(is.na(DataVivienda$preciom)) # precio_m2
## [1] 2
sum(is.na(DataVivienda$areaconst)) # area_construida
## [1] 3
sum(is.na(DataVivienda$parquea)) # parqueaderos
## [1] 1605
sum(is.na(DataVivienda$banios)) # baños
## [1] 3
sum(is.na(DataVivienda$habitac)) # habitaciones
## [1] 3
sum(is.na(DataVivienda$tipo)) # tipo
## [1] 3
sum(is.na(DataVivienda$barrio)) # barrio
## [1] 3
sum(is.na(DataVivienda$latitud)) # latitud
## [1] 3
sum(is.na(DataVivienda$longitud)) # longitud
## [1] 3
Como se evidencia las variables piso y parqueaderos son las variables con mas faltantes por lo que se deciden retirarlas para el analisis.
borrar <- c("piso","parquea")
DataVivienda <- DataVivienda[ ,!(names(DataVivienda) %in% borrar)]
Tambien se eliminan las filas con los datos faltantes (N/A), y se verifica que no queden ningunto en el dataset.
DataVivienda <- DataVivienda[complete.cases(DataVivienda),]
sum(is.na(DataVivienda)) # Conteo de valores faltantes
## [1] 0
ANALISIS 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 preferencias del mercado.
DESARROLLO
Con el fin 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 (5).
require(ade4) # multivariado en general
## Loading required package: ade4
## Warning: package 'ade4' was built under R version 4.2.3
require(FactoClass) #cluster mixto
## Loading required package: FactoClass
## Warning: package 'FactoClass' was built under R version 4.2.3
## Loading required package: ggplot2
## Loading required package: ggrepel
## Warning: package 'ggrepel' was built under R version 4.2.3
## Loading required package: xtable
## Loading required package: scatterplot3d
## Warning: package 'scatterplot3d' was built under R version 4.2.3
var_Num_Vivienda=DataVivienda[,3:7]
acp_Vivienda=dudi.pca(df = var_Num_Vivienda, scannf = FALSE, nf = 5)
acp_Vivienda$eig #valores propios
## [1] 2.9331575 1.1883211 0.4453505 0.2416783 0.1914925
acp_Vivienda$eig/5*100
## [1] 58.663151 23.766422 8.907009 4.833567 3.829851
acp_Vivienda$co #vectores propios
## Comp1 Comp2 Comp3 Comp4 Comp5
## estrato -0.5651788 0.7352040 -0.2808814 0.2357528 -0.0746613
## preciom -0.8680916 0.3060630 0.2012360 -0.1088355 0.3168617
## areaconst -0.8461283 -0.1785733 0.4354681 0.1467273 -0.2025267
## banios -0.8887982 -0.1191296 -0.2514325 -0.3268036 -0.1607076
## habitac -0.5951908 -0.7127702 -0.2703875 0.2142995 0.1366489
mat_comp=acp_Vivienda$li #vectores propios
##como se generan las componentes (valores y vectores propios de la mat correl)
Elección del número de componentes principales:
###
##graficos y resultados tradicionales
##
##install.packages("factoextra")
library(factoextra)
## Warning: package 'factoextra' was built under R version 4.2.3
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
fviz_eig(acp_Vivienda, addlabels = TRUE, ylim = c(0, 100))
par(mfrow=c(1,2))
##s.corcircle(acp_Vivienda$co[,1:2])
s.label(acp_Vivienda$li[,1:2])
En este caso el primer componente principal explica el 58.7% de la variabilidad contenida en la base de datos y entre los dos primeros el 82.5% , 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.
fviz_pca_var(acp_Vivienda,
col.var = "contrib",
gradient.cols = c("blue","red"),
repel = TRUE)
Podemos Observar como hay correlacion entre la variable Baños y area construida dentro de la primer componente que representa el 58.7% tambien acompañado por el numero de habitaciones, dentro del segundo componente podemos evidencias las variables precio m2 y estrato con una representacion del 23.8%.
CONCLUSIONES ANALISIS DE COMPONENTES PRINCIPALES
El valor en la celda (estrato, Comp1) es -0.5651788. Esto
significa que la variable
“estrato” tiene una carga negativa en el componente principal 1. Una
carga negativa indica que a medida que el valor de “estrato” aumenta, el
valor del componente principal 1 disminuye.
El valor en la celda (preciom, Comp1) es -0.8680916. Esto indica una carga negativa de la variable “preciom” en el componente principal 1.
El valor en la celda (areaconst, Comp2) es -0.1785733. Esto indica una carga negativa de la variable “areaconst” en el componente principal 2
Se concluye que el componente No. 1 (58.7% varianza)+ componente
No. 2 (23.8% varianza)se
explica el 82.43% de la varianza de todos los datos observados, esto
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.
Una caracteristica de la informacion observada nos plantea que la
variable baños y area construida son las mas representan influencia
dentro de los componentes principales y
pueden ser decisorias en el momento de comprar o vender una casa o
apartamento porque son
necesidades que son imprescindibles de pasar por alto.
De las variables observadas las Cargas más grandes (positivas o
negativas) indican una mayor influencia de esa variable en el componente
principal correspondiente, en este caso nos
muestran los patrones que sigue el dataset de vivienda y nos puede
permitir una
interpretacion de las preferencias del mercado inmobiliario.
ANALISIS DE CONGLOMERADOS (CLUSTER)
Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas y demandas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.
DESAROLLO
Como el reto de los datos de vivienda nos solicita agrupacion de las propiedades residenciales para enteder las dinamicas y demandas en diferentes partes de la ciudad y en diferentes estratos socioeconomicos.
str(DataVivienda)
## 'data.frame': 8319 obs. of 11 variables:
## $ id : int 8312 8311 8307 8296 8297 8298 8299 8300 8286 8287 ...
## $ zona : chr "Zona Oeste" "Zona Oeste" "Zona Oeste" "Zona Sur" ...
## $ estrato : int 6 6 5 3 5 5 6 5 5 5 ...
## $ preciom : int 1300 480 1200 220 330 1350 305 480 275 285 ...
## $ areaconst: num 318 300 800 150 112 390 125 280 74 120 ...
## $ banios : int 4 4 7 2 4 10 3 4 2 4 ...
## $ habitac : int 2 4 5 4 3 10 3 4 3 3 ...
## $ tipo : chr "Apartamento" "Casa" "Casa" "Casa" ...
## $ barrio : chr "arboleda" "normandía" "miraflores" "el guabal" ...
## $ longitud : num -76576 -76571 -76568 -76565 -76565 ...
## $ latitud : num 3454 3454 3455 3417 3408 ...
definimos tomar las variables para el analisis de Cluster (de tipo numerico para calcular las distancias entre los puntos):
datos=DataVivienda[,3:5]
str(datos)
## 'data.frame': 8319 obs. of 3 variables:
## $ estrato : int 6 6 5 3 5 5 6 5 5 5 ...
## $ preciom : int 1300 480 1200 220 330 1350 305 480 275 285 ...
## $ areaconst: num 318 300 800 150 112 390 125 280 74 120 ...
sum(is.na(datos)) # Conteo de valores faltantes
## [1] 0
Dado que los rangos de las variables son diferente y con fin de que estas diferencias en las dimensiones de las variables no afecte los cálculos de las distancias estandarizamos las variables (restar la media y dividir el resultado por la desviación estándar) antes de generar las cálculos de las distancias.
library (cluster)
Clu_vvda =scale(datos)
head(Clu_vvda)
## estrato preciom areaconst
## 1 1.3275950 2.6351924 1.0007060
## 2 1.3275950 0.1402509 0.8748003
## 3 0.3559875 2.3309312 4.3721812
## 4 -1.5872276 -0.6508281 -0.1744140
## 5 0.3559875 -0.3161408 -0.4402149
## 6 0.3559875 2.7873229 1.5043289
#Revision de los Métodos No Jerárquicos K-means#
Como primer paso para el desarrollo de esta actividad utilizaremos revisaremos por PCA para ver si hay alguna similitud entre grupos.
library(factoextra)
p1=princomp(Clu_vvda)
fviz_pca_ind(p1)
#kmeans
calc_calidad_cluster=function(k){
resutado=kmeans(datos,centers = k,iter.max = 100)
resutado$cluster
plot(datos,col=resutado$cluster)
calidad=resutado$betweenss/resutado$totss*100
return(calidad)}
calc_calidad_cluster(k = 4)
## [1] 84.43647
calidad_cluster_k=sapply(2:10, calc_calidad_cluster)
k=2:10
plot(k,calidad_cluster_k,type="b")
resutado=kmeans(datos,centers = 5,iter.max = 100)
datos_final=data.frame(resutado$cluster,datos)
#require(table1)
#table1(~V1+V2+v3|resutado.cluster,data = datos_final)
El gráfico anterior representa la varianza dentro de los clusters, Como se evidencia en los 4 primeros cluster se concentran las sumas de cuadrados de los grupos que evaluamos.
#dist(datos)
cluster_jerarquico=hclust(dist(datos))
plot(cluster_jerarquico)
plot(cluster_jerarquico$height,type="b")
grupos=cutree(cluster_jerarquico,k = 2)
#datos_final=data.frame(grupos,datos)
#datos_final
CONCLUSIONES ANALISIS DE CONGLOMERADOS (cluster)
El análisis de K-means ha generado 4 clusters con diferentes
tamaños. Los tamaños de los
clusters son 2055, 536, 1034 y 1183, respectivamente. La distribución
del tamaño de los
clusters podría sugerir diferencias en la densidad de puntos en
diferentes regiones del
espacio de características.
Cluster 1: Caracterizado por valores más altos en “zona”, valores
moderados en “estrato”, y valores bajos en “preciom”, “areaconst”,
“parquea” y “banios”. Puede representar
propiedades en una zona específica en este caso alta de la ciudad pero
con características de estructura modestas.
Cluster 2: Las propiedades en este cluster tienen valores
medios-altos en “estrato”, “preciom”, “areaconst”, “parquea” y “banios”.
Puede indicar propiedades de alta calidad y
precio en zonas de alta cotizacion de la ciudad.
Cluster 3: Caracterizado por valores bajos en “zona” y valores
bajos en las demás variables. Puede representar propiedades en una zona
diferente con características más
modestas de la ciudad.
Cluster 4: Propiedades con valores medios-altos en “estrato”,
“preciom”, “areaconst”,
“parquea” y “banios”. Similar al Cluster 2, pero con valores ligeramente
diferentes, pueden ser los casos extreños o atipicos o errores en la
informacion de ser asi se podrian llegar a evaluar y dejarlos como parte
de cluster 2,por eso es importate evaluar la cantidad el
origen y la calidad de los datos.
Varianza Explicada: El valor (between_SS / total_SS) indica la
proporción de la varianza total explicada por la agrupación. En este
caso, el valor es 50.2%. Un valor alto puede
sugerir que la agrupación ha capturado una cantidad significativa de la
variabilidad en los datos.
ANALISIS DE CORRESPONDENCIA
Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio) y las variables numéricas (precio, área construida, número de parqueaderos, baños, habitaciones) para identificar patrones de comportamiento del mercado inmobiliario.
DESARROLLO
En este Caso el analisis de correspondecia solo se toma para variables categoricas entonces solo vamos a tomar las categoricas, se sugiere que el planteamiento del problema tiene errores en la redaccion por eso no se asumen las variables numericas que ya fueron revisadas en el punto de ACP.
Dada las necesidades de informacion que nos solicitan vamos a construir un dataset con las variables necesrias para la identificacion de patrones.
Datavivienda_ac <- subset(DataVivienda, select = c("tipo", "zona", "barrio"))
####Datavivienda_ac <- subset(DataVivienda, select = c("tipo", "zona", "barrio", "preciom", "areaconst", "parquea", "banios", "habitac"))
str(Datavivienda_ac)
## 'data.frame': 8319 obs. of 3 variables:
## $ tipo : chr "Apartamento" "Casa" "Casa" "Casa" ...
## $ zona : chr "Zona Oeste" "Zona Oeste" "Zona Oeste" "Zona Sur" ...
## $ barrio: chr "arboleda" "normandía" "miraflores" "el guabal" ...
Inicialmente se revisa si la base tiene datos faltantes
library(mice)
## Warning: package 'mice' was built under R version 4.2.3
##
## Attaching package: 'mice'
## The following object is masked from 'package:stats':
##
## filter
## The following objects are masked from 'package:base':
##
## cbind, rbind
md.pattern(Datavivienda_ac, rotate.names = TRUE)
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## tipo zona barrio
## 8319 1 1 1 0
## 0 0 0 0
Datavivienda_ac <- Datavivienda_ac[complete.cases(Datavivienda_ac),]
sum(is.na(Datavivienda_ac)) # Conteo de valores faltantes
## [1] 0
Se arreglan las variables que tienen diferentes nombre para estandarizar mas el dataset
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# Zona
Datavivienda_ac <- Datavivienda_ac %>% mutate(tipo = replace(tipo,
tipo == "Apartamento","APARTAMENTO"))
Datavivienda_ac <- Datavivienda_ac %>% mutate(tipo = replace(tipo,
tipo == "apto", "APARTAMENTO"))
Datavivienda_ac <- Datavivienda_ac %>% mutate(tipo = replace(tipo,
tipo == "casa", "CASA"))
Datavivienda_ac <- Datavivienda_ac %>% mutate(tipo = replace(tipo,
tipo == "Casa", "CASA"))
Datavivienda_ac <- Datavivienda_ac %>% mutate(barrio = replace(barrio,
barrio == "aguablanca", "agua blanca"))
Datavivienda_ac <- Datavivienda_ac %>% mutate(barrio = replace(barrio,
barrio == "alameda del río", "alameda del rio"))
Datavivienda_ac <- Datavivienda_ac %>% mutate(barrio = replace(barrio,
barrio == "alférez real", "alferez real"))
Datavivienda_ac <- Datavivienda_ac %>% mutate(barrio = replace(barrio,
barrio == "alfonso lópez", "alfonso lopez"))
Datavivienda_ac <- Datavivienda_ac %>% mutate(barrio = replace(barrio,
barrio == "alfonso lópez", "alfonso lopez"))
Datavivienda_ac <- Datavivienda_ac %>% mutate(barrio = replace(barrio,
barrio == "alfonso lópez i", "alfonso lopez"))
Con el dataset limpio, Se construye entonces una tabla cruzada con las variables involucradas en el análisis, se procede MCA a revisar los resultados de la ejecucion de MCA.
Finalmente 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)
## Warning: package 'FactoMineR' was built under R version 4.2.3
##
## Attaching package: 'FactoMineR'
## The following object is masked from 'package:ade4':
##
## reconst
library(factoextra)
##tabla_cruzada1 <- table(Datavivienda_ac$barrio, Datavivienda_ac$zona)
##resultado_acm <- MCA(tabla_cruzada1)
##Seleccion las columnas categóricas y la relacion entre las mismas
variables_categoricas1 <- Datavivienda_ac[, c("tipo", "zona")]
variables_categoricas2 <- Datavivienda_ac[, c("tipo", "zona")]
#Convertir las variables categóricas en factores
variables_categoricas1 <- lapply(variables_categoricas1, as.factor)
variables_categoricas2 <- lapply(variables_categoricas2, as.factor)
### Combinar las variables categóricas y numéricas en una matriz
Matriz_Datavivienda_MCA <- cbind.data.frame(variables_categoricas1, variables_categoricas2)
# Realizar el Análisis de Correspondencia Múltiple (ACM) con variables suplementarias
resultado_mca <- MCA(Matriz_Datavivienda_MCA)
## Warning: Removed 2 rows containing missing values (`geom_point()`).
## Warning: Removed 2 rows containing missing values (`geom_text_repel()`).
En la gráfica numero 1 (MCA Factor map), nos permite establecer relaciones y validarlas como son:
Revisemos a detalle la informacion de MCA:
print(resultado_mca)
## **Results of the Multiple Correspondence Analysis (MCA)**
## The analysis was performed on 8319 individuals, described by 4 variables
## *The results are available in the following objects:
##
## name description
## 1 "$eig" "eigenvalues"
## 2 "$var" "results for the variables"
## 3 "$var$coord" "coord. of the categories"
## 4 "$var$cos2" "cos2 for the categories"
## 5 "$var$contrib" "contributions of the categories"
## 6 "$var$v.test" "v-test for the categories"
## 7 "$ind" "results for the individuals"
## 8 "$ind$coord" "coord. for the individuals"
## 9 "$ind$cos2" "cos2 for the individuals"
## 10 "$ind$contrib" "contributions of the individuals"
## 11 "$call" "intermediate results"
## 12 "$call$marge.col" "weights of columns"
## 13 "$call$marge.li" "weights of rows"
Revisemos la variabilidad y proporcion de las varianzas
eig_val <- factoextra::get_eigenvalue(resultado_mca)
head(eig_val)
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 6.441081e-01 2.576433e+01 25.76433
## Dim.2 5.000000e-01 2.000000e+01 45.76433
## Dim.3 5.000000e-01 2.000000e+01 65.76433
## Dim.4 5.000000e-01 2.000000e+01 85.76433
## Dim.5 3.558919e-01 1.423567e+01 100.00000
## Dim.6 6.846423e-27 2.738569e-25 100.00000
A continuación, se puede visualizar los porcentajes de inercia explicados para cada dimensión:
fviz_screeplot(resultado_mca, addlabels = TRUE)
Los resultados indican que la primera componente resumen el 25.8% y los tres primeros componentes prepresentados en el plano factorial el 67% de los datos.
CONCLUSIONES ANALISIS DE CORRESPONDENCIA
Dimensión 1: El primer valor propio es 0.6441, lo que representa el 25.76% de la varianza total. Esto significa que la Dimensión 1 captura una parte importante de la variabilidad en los datos. Es una dimensión significativa en términos de explicar las relaciones entre las variables categóricas.
Dimensión 2: El segundo valor propio es 0.5, lo que representa el 20% de la varianza total. Junto con la Dimensión 1, estas dos dimensiones explican el 45.76% de la varianza total. La Dimensión 2 también es importante para explicar las relaciones en los datos.
Al revisar la relacion entre las variables categoricas “Zona” Vs “Tipo, En la Zona Oriente hay mas presencia de contrucciones tipo CASA
Al revisar la relacion entre las variables categoricas “Zona” Vs “Tipo En la Zona Oeste hay mas presencia de contrucciones tipo APARTAMENTO.
Al revisar la relacion entre las variables categoricas “Zona” Vs
“Tipo En la Zona Sur
tenemos presencia APARTAMENTOS como de CASAS, pero en mayor proporcion
las CASAS.