Actividad 1

Evaluación del mercado inmobiliario urbano

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.

Base de datos y variables:

library(paqueteMODELOS)
data(vivenda)
## Warning in data(vivenda): data set 'vivenda' not found
str(vivienda)
## Classes 'spec_tbl_df', 'tbl_df', 'tbl' and 'data.frame': 8322 obs. of  13 variables:
##  $ id          : num  1147 1169 1350 5992 1212 ...
##  $ zona        : chr  "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ piso        : chr  NA NA NA "02" ...
##  $ estrato     : num  3 3 3 4 5 5 4 5 5 5 ...
##  $ preciom     : num  250 320 350 400 260 240 220 310 320 780 ...
##  $ areaconst   : num  70 120 220 280 90 87 52 137 150 380 ...
##  $ parqueaderos: num  1 1 2 3 1 1 2 2 2 2 ...
##  $ banios      : num  3 2 2 5 2 3 2 3 4 3 ...
##  $ habitaciones: num  6 3 4 3 3 3 3 4 6 3 ...
##  $ tipo        : chr  "Casa" "Casa" "Casa" "Casa" ...
##  $ barrio      : chr  "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
##  $ longitud    : num  -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num  3.43 3.43 3.44 3.44 3.46 ...
##  - attr(*, "spec")=List of 3
##   ..$ cols   :List of 13
##   .. ..$ id          : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ zona        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ piso        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ estrato     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ preciom     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ areaconst   : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ parqueaderos: list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ banios      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ habitaciones: list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ tipo        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ barrio      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ longitud    : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ latitud     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   ..$ default: list()
##   .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
##   ..$ delim  : chr ";"
##   ..- attr(*, "class")= chr "col_spec"
##  - attr(*, "problems")=<externalptr>
head(vivienda,10)

Reconocimiento de las variables

A través de Histogramas vamos a realizar reconocimiento de las variables para entender de qué e componen a nivel general

boxplot(x = vivienda$preciom,
        main = "Histograma de precio",
        col = "red") # Precio

boxplot(x = vivienda$areaconst,
        main = "Histograma de área construída",
        col = "yellow") # Area Construida

boxplot(x = vivienda$banios,
        main = "Histograma de Número de baños",
        col = "blue") # Baños

boxplot(x = vivienda$habitaciones,
        main = "Histograma de Número de Habitaciones",
        col = "green") # habitaciones

Resumen y transformación

La tabla cuenta con información de 8,322 viviendas medidas en 12 variables: zona, piso, estrato, preciom, areaconst, parqueaderos, baños, habitaciones, tipo, barrio, longitud y latitud.

Realizamos una revisión de el contenido de estas variables

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

Revisión del tipo de datos

class(vivienda$zona) # tipo variable zona
## [1] "character"
class(vivienda$piso) # tipo variable piso
## [1] "character"
class(vivienda$estrato) # tipo variable estrato
## [1] "numeric"
class(vivienda$preciom) # tipo variable preciom
## [1] "numeric"
class(vivienda$areaconst) # tipo variable areaconst
## [1] "numeric"
class(vivienda$parqueaderos) # tipo variable parqueaderos
## [1] "numeric"
class(vivienda$banios) # tipo variable baños
## [1] "numeric"
class(vivienda$habitaciones) # tipo variable habitaciones
## [1] "numeric"
class(vivienda$tipo) # tipo variable tipo
## [1] "character"
class(vivienda$barrio) # tipo variable barrio
## [1] "character"
class(vivienda$longitud) # tipo variable longitud
## [1] "numeric"
class(vivienda$latitud) # tipo variable latitud
## [1] "numeric"

Revisión de NA

sum(is.na(vivienda$zona)) # NA en zona
## [1] 3
sum(is.na(vivienda$piso)) # NA en  piso
## [1] 2638
sum(is.na(vivienda$estrato)) # NA en estrato
## [1] 3
sum(is.na(vivienda$preciom)) # NA en preciom
## [1] 2
sum(is.na(vivienda$areaconst)) # NA en areaconst
## [1] 3
sum(is.na(vivienda$parqueaderos)) # NA en parqueaderos
## [1] 1605
sum(is.na(vivienda$banios)) # NA en baños
## [1] 3
sum(is.na(vivienda$habitaciones)) # NA en habitaciones
## [1] 3
sum(is.na(vivienda$tipo)) # NA en tipo
## [1] 3
sum(is.na(vivienda$barrio)) # NA en barrio
## [1] 3
sum(is.na(vivienda$longitud)) # NA en longitud
## [1] 3
sum(is.na(vivienda$latitud)) # NA en latitud
## [1] 3

Se decide no imputar la moda o media en los valores NA ya que puede cambiar la variabilidad de la muestra lo que puede afectar los resultados del PCA.

Base para trabajar

Se cambia el nombre de la base para realizar los ajustes sobre una base nueva

vivienda1 <- vivienda
head(vivienda1,10)

Resumen y transformación de las variables

Se inicia un tratamiento de la base de datos para realizar el modelamiento de los datos. Estos ajustes se detallan a continuación:

Se eliminan las variables que mas NA presentan que son parqueaderos y piso y adicional 3 variables que inicialmente no se espera que aporten al análisis final.

borrar <- c("piso","parqueaderos","barrio", "longitud", "latitud")
vivienda1 <- vivienda1[ ,!(names(vivienda1) %in% borrar)]
head(vivienda1,10)

Se eliminan las filas que tienen datos faltantes

vivienda1 <- vivienda1[complete.cases(vivienda1),]
sum(is.na(vivienda1)) # Conteo de valores faltantes
## [1] 0

Se cambia el nombre de las filas por el ID de los casos y se quita la variable ID de el data frame

rownames(vivienda1) <- vivienda1$id
vivienda1$id <- NULL

Se transforman las variables categóricas en numéricas patra incluirlas en el modelo

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
vivienda1 <- vivienda1 %>% mutate(zona = replace(zona,
                                               zona == "Zona Centro", 1))
vivienda1 <- vivienda1 %>% mutate(zona = replace(zona,
                                               zona == "Zona Norte", 2))
vivienda1 <- vivienda1 %>% mutate(zona = replace(zona,
                                               zona == "Zona Oeste", 3))
vivienda1 <- vivienda1 %>% mutate(zona = replace(zona,
                                               zona == "Zona Oriente",
                                               4))
vivienda1 <- vivienda1 %>% mutate(zona = replace(zona,
                                               zona == "Zona Sur", 5))
vivienda1$zona <- as.numeric(vivienda1$zona)

vivienda1 <- vivienda1 %>% mutate(tipo = replace(tipo,
                                               tipo == "Casa", 1))
vivienda1 <- vivienda1 %>% mutate(tipo = replace(tipo,
                                               tipo == "Apartamento", 2))
vivienda1$tipo <- as.numeric(vivienda1$tipo)

head(vivienda1,10)

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 preferencias del mercado.

Varianza

Inicialmente se revisa la varianza de las variables

apply(vivienda1, 2, var)
##         zona      estrato      preciom    areaconst       banios habitaciones 
## 1.762895e+00 1.059298e+00 1.080207e+05 2.043874e+04 2.039784e+00 2.130248e+00 
##         tipo 
## 2.372472e-01

Elección componentes

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.

library(tidyverse)
## Warning: package 'ggplot2' was built under R version 4.2.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats   1.0.0     ✔ readr     2.1.4
## ✔ ggplot2   3.4.2     ✔ stringr   1.5.0
## ✔ lubridate 1.9.2     ✔ tibble    3.2.0
## ✔ purrr     1.0.1     ✔ tidyr     1.3.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
vivienda_1= vivienda1[1:7] %>%
  scale()
head(vivienda_1) # primeros 6 registros
##             zona    estrato    preciom  areaconst      banios habitaciones
## [1,]  0.06192582 -1.5872276 -0.5595498 -0.7339949 -0.07793773    1.6406840
## [2,]  0.06192582 -1.5872276 -0.3465670 -0.3842568 -0.77811479   -0.4147626
## [3,]  0.06192582 -1.5872276 -0.2552886  0.3152194 -0.77811479    0.2703863
## [4,]  0.81508501 -0.6156201 -0.1031580  0.7349051  1.32241640   -0.4147626
## [5,] -1.44439256  0.3559875 -0.5291236 -0.5940997 -0.77811479   -0.4147626
## [6,] -1.44439256  0.3559875 -0.5899759 -0.6150839 -0.07793773   -0.4147626
##            tipo
## [1,] -1.2586312
## [2,] -1.2586312
## [3,] -1.2586312
## [4,] -1.2586312
## [5,]  0.7944184
## [6,]  0.7944184
prcomp(vivienda_1)
## Standard deviations (1, .., p=7):
## [1] 1.7964600 1.2157043 1.0021146 0.7176276 0.5896915 0.4914690 0.4316173
## 
## Rotation (n x k) = (7 x 7):
##                      PC1         PC2          PC3         PC4         PC5
## zona         -0.04643706  0.10078567 -0.983129845  0.03472704 -0.13735908
## estrato      -0.24775997  0.66654914 -0.001581231 -0.07808217  0.48672432
## preciom      -0.44918450  0.35262674  0.126340874  0.19071335 -0.27110569
## areaconst    -0.48400565 -0.05398507  0.085962667  0.34611788 -0.54237179
## banios       -0.49088084  0.05158751 -0.011572716 -0.38151942  0.17839055
## habitaciones -0.37321799 -0.43705988 -0.039958799 -0.63133426 -0.05404702
## tipo          0.34666229  0.47393237  0.091493044 -0.54072915 -0.58465562
##                      PC6         PC7
## zona          0.01400561  0.02952821
## estrato      -0.48364093 -0.13198035
## preciom       0.21908528  0.70714738
## areaconst    -0.29000474 -0.50731358
## banios        0.66473052 -0.37012684
## habitaciones -0.43806861  0.27328036
## tipo          0.00483955 -0.11228873

Hasta este punto el primer componente no explica de manera contundente la variabilidad de los datos. Así mismo hay dos variables que se explican menos en el primer componente así que decido eliminar del modelo la variable tipo de inmueble y dejar solo el estrato para ver si se explican mejor los componentes

borrar <- c("zona")
vivienda1 <- vivienda1[ ,!(names(vivienda1) %in% borrar)]

borrar <- c("tipo")
vivienda1 <- vivienda1[ ,!(names(vivienda1) %in% borrar)]

head(vivienda1,10)

Se revisa la varianza de las variables de nuevo

apply(vivienda1, 2, var)
##      estrato      preciom    areaconst       banios habitaciones 
## 1.059298e+00 1.080207e+05 2.043874e+04 2.039784e+00 2.130248e+00

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_2= vivienda1[1:5] %>%
  scale()
head(vivienda_2) # primeros 6 registros
##         estrato    preciom  areaconst      banios habitaciones
## [1,] -1.5872276 -0.5595498 -0.7339949 -0.07793773    1.6406840
## [2,] -1.5872276 -0.3465670 -0.3842568 -0.77811479   -0.4147626
## [3,] -1.5872276 -0.2552886  0.3152194 -0.77811479    0.2703863
## [4,] -0.6156201 -0.1031580  0.7349051  1.32241640   -0.4147626
## [5,]  0.3559875 -0.5291236 -0.5940997 -0.77811479   -0.4147626
## [6,]  0.3559875 -0.5899759 -0.6150839 -0.07793773   -0.4147626
prcomp(vivienda_2)
## Standard deviations (1, .., p=5):
## [1] 1.7126464 1.0901014 0.6673458 0.4916079 0.4375986
## 
## Rotation (n x k) = (5 x 5):
##                    PC1        PC2        PC3        PC4        PC5
## estrato      0.3300032 -0.6744363  0.4208934 -0.4795545  0.1706159
## preciom      0.5068715 -0.2807656 -0.3015468  0.2213868 -0.7240921
## areaconst    0.4940473  0.1638135 -0.6525373 -0.2984641  0.4628138
## banios       0.5189619  0.1092831  0.3767649  0.6647648  0.3672488
## habitaciones 0.3475270  0.6538568  0.4051685 -0.4359154 -0.3122700

Elección componentes

Nuevamente se realiza la elección del número de componentes principales

library(factoextra) # Librería
## 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
data("vivienda1")
## Warning in data("vivienda1"): data set 'vivienda1' not found
vivienda_2= scale(vivienda1[1:5]) 
res.pca <- prcomp(vivienda_2)
fviz_eig(res.pca, addlabels = TRUE)

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 casi el 83% de los datos, lo cual indicaría que con solo una variable (CP1) que se obtiene mediante una combinación lineal de las variables y se puede resumir gran parte de la variabilidad que contiene la base de datos.

Se realiza la graficación de los componentes en las dimensiones que lo explican

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

Se observa que las variables de area construida, baños y precio están más asociadas al componente 1 mientras que para el componente 2 se explica mejor las variables habitaciones y estrato

Revisión de casos

Revisamos 4 casos para entender mejor el sentido de ejes

datos<- rbind(vivienda1[5720,], # ok
              vivienda1[3388,],
              vivienda1[724,],
              vivienda1[8073,])

datos <- as.data.frame(datos)
rownames(datos) = c("5720","3388","724","8073")
datos
casos1 <- rbind(res.pca$x[5720,1:2],res.pca$x[3388,1:2]) # CP1
rownames(casos1) = c("5720","3388")
casos1 <- as.data.frame(casos1)

casos2 <- rbind(res.pca$x[724,1:2], res.pca$x[8073,1:2]) # CP2
rownames(casos2) = c("724","8073")
casos2 <- as.data.frame(casos2)

fviz_pca_ind(res.pca, col.ind = "#DEDEDE", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07")) +
  geom_point(data = casos1, aes(x = PC1, y = PC2), color = "red", size = 3) +
  geom_point(data = casos2, aes(x = PC1, y = PC2), color = "blue", size = 3)

Se puede observar que mientras la vivienda 8073 presenta un área construida de 1440 y precio de 370 la vivienda 3388 tiene un área construida de 235 y precio de 1800 Esto establece que los puntos ubicados en la parte inferior del gráfico son viviendas más costosas en relación area construida y precio mientras en la parte superior se ubican las más favorables en la misma relación

También podemos ver que las viviendas ubicadas a la derecha de la gráfica tienen más área construida que las que están a la izquierda