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.
## Warning in data(vivenda): data set 'vivenda' not found
## 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>
A través de Histogramas vamos a realizar reconocimiento de las variables para entender de qué e componen a nivel general
boxplot(x = vivienda$areaconst,
main = "Histograma de área construída",
col = "yellow") # Area Construidaboxplot(x = vivienda$habitaciones,
main = "Histograma de Número de Habitaciones",
col = "green") # habitacionesLa 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
## 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
## [1] "character"
## [1] "character"
## [1] "numeric"
## [1] "numeric"
## [1] "numeric"
## [1] "numeric"
## [1] "numeric"
## [1] "numeric"
## [1] "character"
## [1] "character"
## [1] "numeric"
## [1] "numeric"
## [1] 3
## [1] 2638
## [1] 3
## [1] 2
## [1] 3
## [1] 1605
## [1] 3
## [1] 3
## [1] 3
## [1] 3
## [1] 3
## [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.
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
Se transforman las variables categóricas en numéricas patra incluirlas en el modelo
##
## 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)##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.
Inicialmente se revisa la varianza de las variables
## 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
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.
## 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
## 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
## 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
## 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.
## 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
## 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
Nuevamente se realiza la elección del número de componentes principales
## 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
## Warning in data("vivienda1"): data set 'vivienda1' not found
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
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")
datoscasos1 <- 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