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

  1. 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.

  2. El valor en la celda (preciom, Comp1) es -0.8680916. Esto indica una carga negativa de la variable “preciom” en el componente principal 1.

  3. El valor en la celda (areaconst, Comp2) es -0.1785733. Esto indica una carga negativa de la variable “areaconst” en el componente principal 2

  4. 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.

  5. 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.

  6. 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.

Analisis cluster jerarquico

#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)

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

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

  1. En la Zona Oriente hay mas presencia de contrucciones tipo CASA
  2. En la Zona Oeste hay mas presencia de contrucciones tipo APARTAMENTO.
  3. En la Zona Sur tenemos presencia APARTAMENTOS como de CASAS, pero en mayor proporcion las CASAS-

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

  1. 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.

  2. 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.

  3. Al revisar la relacion entre las variables categoricas “Zona” Vs “Tipo, En la Zona Oriente hay mas presencia de contrucciones tipo CASA

  4. Al revisar la relacion entre las variables categoricas “Zona” Vs “Tipo En la Zona Oeste hay mas presencia de contrucciones tipo APARTAMENTO.

  5. 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.