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 oferta del mercado.
#install.packages("devtools")
#devtools::install_github("dgonxalex80/paqueteMODELOS", force = TRUE)
library(paqueteMODELOS)
## Cargando paquete requerido: boot
## Cargando paquete requerido: broom
## Cargando paquete requerido: GGally
## Cargando paquete requerido: ggplot2
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
## Cargando paquete requerido: gridExtra
## Cargando paquete requerido: knitr
## Cargando paquete requerido: summarytools
data(vivenda)
## Warning in data(vivenda): data set 'vivenda' not found
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 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>
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
Teniendo en cuenta los resultados del resument estadístico presentado anteriormente, es importante evidenciar que las viviendas se encuentran distribuidas hacia un nivel socioeconómico alto, ya que la media es de 4.63, aunqe el estrato mínimo sea de 3 y el más alto de 6.
En cuanto al precio promedio, se identifica una alta variabilidad, con un rango entre 58 y 1.999 y una media de 433.9.
Por otro lado, también se visualiza una gran variabilidad de los metros cuadrados de las viviendas, ya que se encuentran entre 30 y 1.745, con una media de 174.9 m2.
La mayoría de las viviendas tienen entre 2 a 4 baños, así como entre 3 y 4 habitaciones.
head(vivienda)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona O… <NA> 3 250 70 1 3 6
## 2 1169 Zona O… <NA> 3 320 120 1 2 3
## 3 1350 Zona O… <NA> 3 350 220 2 2 4
## 4 5992 Zona S… 02 4 400 280 3 5 3
## 5 1212 Zona N… 01 5 260 90 1 2 3
## 6 1724 Zona N… 01 5 240 87 1 3 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
Se revisan el tipo de datos de cada variable, en donde se evidencia que “piso” es de tipo character; por lo tanto, es importante más adelante modificarlo a a tipo numérico, ya que de esta forma será posible utilizar cálculos para realizar comparaciones y análisis estadísticos, permitiendo realizar operaciones como promedios, distribuciones, etc.
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 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>
Con el código a continuación, se evidencian las variables con datos faltantes, en donde “piso” y “parqueaderos” cuentan con mayor registros sin datos, siendo estos de 2.638 y 1.605 respectivamente.
n_nas_por_columna <- colSums(is.na(vivienda))
print(n_nas_por_columna)
## id zona piso estrato preciom areaconst
## 3 3 2638 3 2 3
## parqueaderos banios habitaciones tipo barrio longitud
## 1605 3 3 3 3 3
## latitud
## 3
Teniendo en cuenta que hay datos faltantes mayoritarios en las variables piso y parqueaderos, se revisa a profundidad la información de las variables tipo, zona y estrato, con el fin de poder crear un nuevo data frame con la moda, teniendo en cuenta estas tres variables.
Se crea nueva base llamado vivienda_modificado_2
vivienda_modificado_2 <- vivienda
library(dplyr)
##
## Adjuntando el paquete: '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
# Función para calcular la moda
moda <- function(x) {
uniq_x <- unique(x[!is.na(x)])
uniq_x[which.max(tabulate(match(x, uniq_x)))]
}
# Calcular la moda para 'piso' y 'parqueadero' en cada combinación de 'tipo', 'zona', y 'estrato'
moda_imputacion <- vivienda_modificado_2 %>%
group_by(tipo, zona, estrato) %>%
summarise(
moda_piso = moda(piso),
moda_parqueaderos = moda(parqueaderos),
.groups = 'drop'
)
# Unir los resultados de moda con los datos originales
vivienda_modificado_2 <- vivienda_modificado_2 %>%
left_join(moda_imputacion, by = c("tipo", "zona", "estrato"))
# Imputar los valores faltantes con la moda
vivienda_modificado_2 <- vivienda_modificado_2 %>%
mutate(
piso = ifelse(is.na(piso), moda_piso, piso),
parqueaderos = ifelse(is.na(parqueaderos), moda_parqueaderos, parqueaderos)
) %>%
select(-moda_piso, -moda_parqueaderos) # Eliminar las columnas auxiliares
n_nas_por_columna <- colSums(is.na(vivienda_modificado_2))
print(n_nas_por_columna)
## id zona piso estrato preciom areaconst
## 3 3 9 3 2 3
## parqueaderos banios habitaciones tipo barrio longitud
## 6 3 3 3 3 3
## latitud
## 3
# Identificar filas con al menos un valor NA
filas_con_na <- which(rowSums(is.na(vivienda_modificado_2)) > 0)
# Ver las filas con datos faltantes
vivienda_modificado_2[filas_con_na, ]
## # A tibble: 10 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1132 Zona … <NA> 5 325 89 1 2 3
## 2 4999 Zona … <NA> 6 1000 400 NA 5 10
## 3 5165 Zona … <NA> 5 180 98 1 2 3
## 4 6937 Zona … <NA> 6 1350 212 3 4 3
## 5 1214 Zona … 01 5 148 150 NA 1 3
## 6 5475 Zona … <NA> 5 650 129 NA 2 1
## 7 482 Zona … <NA> 5 350 152 1 4 3
## 8 NA <NA> <NA> NA NA NA NA NA NA
## 9 NA <NA> <NA> NA NA NA NA NA NA
## 10 NA <NA> <NA> NA 330 NA NA NA NA
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
Como se ve en la tabla anterior, los registros faltantes están dentro de los mismos registros, para un total de 10, por lo tanto, es posible eliminar esas filas.
# Eliminar filas con datos faltantes
vivienda_modificado_2 <- na.omit(vivienda_modificado_2)
summary(is.na(vivienda_modificado_2))
## id zona piso estrato
## Mode :logical Mode :logical Mode :logical Mode :logical
## FALSE:8312 FALSE:8312 FALSE:8312 FALSE:8312
## preciom areaconst parqueaderos banios
## Mode :logical Mode :logical Mode :logical Mode :logical
## FALSE:8312 FALSE:8312 FALSE:8312 FALSE:8312
## habitaciones tipo barrio longitud
## Mode :logical Mode :logical Mode :logical Mode :logical
## FALSE:8312 FALSE:8312 FALSE:8312 FALSE:8312
## latitud
## Mode :logical
## FALSE:8312
n_nas_por_columna <- colSums(is.na(vivienda_modificado_2))
print(n_nas_por_columna)
## id zona piso estrato preciom areaconst
## 0 0 0 0 0 0
## parqueaderos banios habitaciones tipo barrio longitud
## 0 0 0 0 0 0
## latitud
## 0
Se eliminan la columnas ya que no son reelevantes y ocasionan inconvenientes en el momentode la revision de los datos:
library(dplyr)
# Eliminar la columna 'ID'
vivienda_modificado_2 <- vivienda_modificado_2 %>% select(-id, -longitud, -latitud)
print(vivienda_modificado_2)
## # A tibble: 8,312 × 10
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Zona … 01 3 250 70 1 3 6 Casa
## 2 Zona … 01 3 320 120 1 2 3 Casa
## 3 Zona … 01 3 350 220 2 2 4 Casa
## 4 Zona … 02 4 400 280 3 5 3 Casa
## 5 Zona … 01 5 260 90 1 2 3 Apar…
## 6 Zona … 01 5 240 87 1 3 3 Apar…
## 7 Zona … 01 4 220 52 2 2 3 Apar…
## 8 Zona … 01 5 310 137 2 3 4 Apar…
## 9 Zona … 02 5 320 150 2 4 6 Casa
## 10 Zona … 02 5 780 380 2 3 3 Casa
## # ℹ 8,302 more rows
## # ℹ 1 more variable: barrio <chr>
# Verificar las columnas del dataframe
print(names(vivienda_modificado_2))
## [1] "zona" "piso" "estrato" "preciom" "areaconst"
## [6] "parqueaderos" "banios" "habitaciones" "tipo" "barrio"
# Convertir la variable 'piso' de character a numeric
vivienda_modificado_2$piso <- as.numeric(vivienda_modificado_2$piso)
# Verificar la conversión
str(vivienda_modificado_2$piso)
## num [1:8312] 1 1 1 2 1 1 1 1 2 2 ...
# Contar cuántos registros tienen valor cero en cada variable
zero_counts <- sapply(vivienda_modificado_2, function(x) sum(x == 0, na.rm = TRUE))
# Mostrar los resultados
print(zero_counts)
## zona piso estrato preciom areaconst parqueaderos
## 0 0 0 0 0 0
## banios habitaciones tipo barrio
## 45 66 0 0
Según el código anterior, se evidencia que variables importantes como baños y habitaciones, cuentan con 45 y 66 registros en cero respectivamente, lo que hace necesario normalizarlas ya que no es posible que una vivienda cuente con cero baños y habitaciones y menos aún teniendo en cuenta la estratificación de las viviendas, las cuales oscilan entre 3 y 6. Por lo tanto, se imputa la moda.
# Función para calcular la moda
calculate_mode <- function(x) {
unique_x <- unique(x)
unique_x[which.max(tabulate(match(x, unique_x)))]
}
# Calcular la moda para 'habitaciones' y 'banios' sin contar los ceros
mode_habitaciones <- calculate_mode(vivienda_modificado_2$habitaciones[vivienda_modificado_2$habitaciones != 0])
mode_banios <- calculate_mode(vivienda_modificado_2$banios[vivienda_modificado_2$banios != 0])
# Imputar la moda en 'habitaciones' y 'banios' donde el valor es 0
vivienda_modificado_2$habitaciones[vivienda_modificado_2$habitaciones == 0] <- mode_habitaciones
vivienda_modificado_2$banios[vivienda_modificado_2$banios == 0] <- mode_banios
Volvemos a verificar que las correcciones anteriores hayan quedado en el data set:
str(vivienda_modificado_2)
## spc_tbl_ [8,312 × 10] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ zona : chr [1:8312] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : num [1:8312] 1 1 1 2 1 1 1 1 2 2 ...
## $ estrato : num [1:8312] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8312] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8312] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8312] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8312] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8312] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8312] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8312] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## - 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>
## - attr(*, "na.action")= 'omit' Named int [1:10] 987 1005 4913 5427 5814 6023 6115 8320 8321 8322
## ..- attr(*, "names")= chr [1:10] "987" "1005" "4913" "5427" ...
# Contar cuántos registros tienen valor cero en cada variable
zero_counts <- sapply(vivienda_modificado_2, function(x) sum(x == 0, na.rm = TRUE))
# Mostrar los resultados
print(zero_counts)
## zona piso estrato preciom areaconst parqueaderos
## 0 0 0 0 0 0
## banios habitaciones tipo barrio
## 0 0 0 0
Se revisan los diferentes datos que están dentro de la variable “barrio”:
summary(vivienda_modificado_2$barrio)
## Length Class Mode
## 8312 character character
#print(unique(vivienda_modificado_2$barrio))
tabla_barrio <- table(vivienda_modificado_2$barrio)
#print(tabla_barrio)
Tenieneo en cuenta que de las tres variables más importantes para realizar la clasificación y conjuntos de datos, la bariable “barrio” cuenta con nombres diferentes para un solo lugar, se hace necesario crear un nuevo data frame en donde se unifiquen estos datos.
# Cargar las bibliotecas necesarias
library(dplyr)
library(ggplot2)
library(tidyr)
# Corrección de barrios
barrio_corregido <- table(vivienda_modificado_2$barrio) %>% data.frame()
# Se corrigen todos los nombres de los barrios y se llevan a minúscula
vivienda_modificado_2$barrio <- tolower(vivienda_modificado_2$barrio)
# Se eliminan las tildes
vivienda_modificado_2$barrio <- iconv(vivienda_modificado_2$barrio, to = "ASCII//TRANSLIT")
# Se hace limpieza de los nombres de los barrios
vivienda_modificado_2 <- vivienda_modificado_2 %>%
mutate(barrio = ifelse(barrio == "agua blanca", "aguablanca", barrio),
barrio = ifelse(barrio == "alf?crez real", "alferez real", barrio),
barrio = ifelse(barrio == "alfonso lopez i", "alfonso lopez", barrio),
barrio = ifelse(barrio == "arboledas", "arboleda", barrio),
barrio = ifelse(barrio == "cali bella", "calibella", barrio),
barrio = ifelse(barrio == "cali canto", "calicanto", barrio),
barrio = ifelse(barrio == "calicanto viii", "calicanto", barrio),
barrio = ifelse(barrio == "ciudad mel?cndez", "ciudadela melendez", barrio),
barrio = ifelse(barrio == "ciudad melendez", "ciudadela melendez", barrio),
barrio = ifelse(barrio == "ciudadela pasoancho", "ciudadela paso ancho", barrio),
barrio = ifelse(barrio == "el tr?cbol", "el troncal", barrio),
barrio = ifelse(barrio == "ingenio i", "el ingenio i", barrio),
barrio = ifelse(barrio == "ingenio ii", "el ingenio ii", barrio),
barrio = ifelse(barrio == "laflora", "la flora", barrio),
barrio = ifelse(barrio == "las am?cricas", "las americas", barrio),
barrio = ifelse(barrio == "las vegas de", "las vegas", barrio),
barrio = ifelse(barrio == "mel?cndez", "melendez", barrio),
barrio = ifelse(barrio == "pampalinda", "pampa linda", barrio),
barrio = ifelse(barrio == "portales de comfandi", "portada de comfandi", barrio),
barrio = ifelse(barrio == "rep??blica de israel", "republica de israel", barrio),
barrio = ifelse(barrio == "rincon de la", "rincon de salomia", barrio),
barrio = ifelse(barrio == "san judas", "san judas tadeo", barrio),
barrio = ifelse(barrio == "tequendeme", "tequendama", barrio),
barrio = ifelse(barrio == "valle de lili", "valle del lili", barrio),
barrio = ifelse(barrio == "zona norte los", "zona norte", barrio))
# Número de viviendas por tipo
numero_viviendas_tipo <- table(vivienda_modificado_2$tipo)
suma_total_tipo_vivienda <- sum(numero_viviendas_tipo) # Se suman las viviendas por tipo
barplot((numero_viviendas_tipo),
col = c("skyblue", "grey"),
xlab = "Tipo", ylab = "Cantidades",
main = "NUmero de viviendas por tipo")
for (i in seq_along(numero_viviendas_tipo)) {
text(i, numero_viviendas_tipo[i], label = paste(numero_viviendas_tipo[i], sprintf("(%.1f%%)", numero_viviendas_tipo[i]/suma_total_tipo_vivienda*100)), pos = 1)
}
legend("topright", legend = names(numero_viviendas_tipo), fill = c("skyblue", "skyblue")
)
# Número de viviendas por zona
numero_viviendas_zona <- table(vivienda_modificado_2$zona)
suma_total_zona_vivienda <- sum(numero_viviendas_zona) # Se suman las viviendas por zona
barplot((numero_viviendas_zona),
col = c("skyblue", "grey", "darkblue", "lightblue", "darkgrey"),
xlab = "Zona", ylab = "Cantidades",
main = "Numero de viviendas por zona")
for (i in seq_along(numero_viviendas_zona)) {
text(i, numero_viviendas_zona[i], label = paste(numero_viviendas_zona[i], sprintf("(%.1f%%)", numero_viviendas_zona[i]/suma_total_zona_vivienda*100)), pos = 1)
}
# Número de viviendas por estrato
numero_viviendas_estrato <- table(vivienda_modificado_2$estrato)
suma_total_estrato_vivienda <- sum(numero_viviendas_estrato) # Se suman las viviendas por zona
barplot((numero_viviendas_estrato),
col = c("skyblue", "grey", "darkblue", "lightblue", "darkgrey"),
xlab = "Estrato", ylab = "Cantidades")
for (i in seq_along(numero_viviendas_estrato)) {
text(i, numero_viviendas_estrato[i], label = paste(numero_viviendas_estrato[i], sprintf("(%.1f%%)", numero_viviendas_estrato[i]/suma_total_estrato_vivienda*100)), pos = 1)
}
legend("topright", legend = names(numero_viviendas_estrato), fill = c("skyblue", "skyblue")
)
# Precio promedio de las viviendas por tipo
promedio_valor_tipo <- tapply(vivienda_modificado_2$preciom, vivienda_modificado_2$tipo, mean)
barplot((promedio_valor_tipo),
col = c("skyblue","grey"),
xlab = "Tipo", ylab = "Promedio",
main = "Precio promedio de las viviendas por tipo")
# Agregamos valores al gráfico
text(
barplot(promedio_valor_tipo, col = "skyblue", plot = FALSE),
promedio_valor_tipo,
labels = sprintf("%.0f", promedio_valor_tipo),
pos = 1,
col = "black",
cex = 0.8
)
# Precio promedio de las viviendas por zona
promedio_valor_viviendas_zona <- tapply(vivienda_modificado_2$preciom, vivienda_modificado_2$zona, mean)
barplot((promedio_valor_viviendas_zona),
col = c("skyblue", "grey", "darkblue", "lightblue", "darkgrey"),
xlab = "Zona", ylab = "Promedio",
main = "Precio promedio de las viviendas por zona")
# Agregamos valores al gráfico
text(
barplot(promedio_valor_viviendas_zona, col = "skyblue", plot = FALSE),
promedio_valor_viviendas_zona,
labels = sprintf("%.0f", promedio_valor_viviendas_zona),
pos = 1,
col = "black",
cex = 0.8
)
# Precio máximo de las viviendas por zona
precio_maximo_viviendas_zona <- tapply(vivienda_modificado_2$preciom, vivienda_modificado_2$zona, max)
barplot((precio_maximo_viviendas_zona),
col = c("skyblue", "grey", "darkblue", "lightblue", "darkgrey"),
xlab = "Zona", ylab = "Precio",
main = "Precio maximo de las viviendas por zona")
# Agregamos valores al gráfico
text(
barplot(precio_maximo_viviendas_zona, col = "skyblue", plot = FALSE),
precio_maximo_viviendas_zona,
labels = sprintf("%.0f", precio_maximo_viviendas_zona),
pos = 1,
col = "black",
cex = 0.8
)
A continuación se realiza el análisis de los componentes principales:
# Con el siguiente código se seleccionan solo las columnas numéricas:
data_numeric <- vivienda_modificado_2[, sapply(vivienda_modificado_2, is.numeric)]
# Se estandarizan los datos:
data_scaled <- scale(data_numeric)
# Se realiza el análisis de componentes principales:
resultado_analisis_componentes_principales_2 <- prcomp(data_scaled, center = TRUE, scale. = TRUE)
# Se visualian los datos:
summary(resultado_analisis_componentes_principales_2)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 1.8810 1.1828 0.9026 0.6848 0.60107 0.48302 0.42969
## Proportion of Variance 0.5054 0.1999 0.1164 0.0670 0.05161 0.03333 0.02638
## Cumulative Proportion 0.5054 0.7053 0.8217 0.8887 0.94029 0.97362 1.00000
identificacion_componentes_principales_2 <- resultado_analisis_componentes_principales_2$rotation
# Ver las cargas para los primeros componentes
identificacion_componentes_principales_2[, 1:6] # Muestra las cargas para PC1 y PC2
## PC1 PC2 PC3 PC4 PC5
## piso 0.1233824 -0.5097239 0.83952589 0.12449399 0.03649808
## estrato -0.3031274 -0.5522896 -0.23506651 -0.56801182 -0.04239433
## preciom -0.4670897 -0.2232240 -0.04891294 0.08987985 0.30763839
## areaconst -0.4468059 0.1841179 0.07504580 0.28400769 0.65286066
## parqueaderos -0.4186572 -0.1891176 -0.12913065 0.61745514 -0.60532938
## banios -0.4608633 0.0906164 0.20718848 -0.36719310 -0.17824463
## habitaciones -0.2956577 0.5544840 0.41510706 -0.23883770 -0.27893975
## PC6
## piso 0.04547167
## estrato 0.45141705
## preciom -0.23569101
## areaconst 0.24661643
## parqueaderos 0.10384991
## banios -0.67461139
## habitaciones 0.46032568
Con la tabla anterior, se muestra como entre los dos componentes principales (PC1 y PC2) explican el 70.54% de la varianza, lo que indica que son los dos componentes que capturan la mayor parte de los datos.
Anteriormente, sin la eliminación de las variables latitud y longitud, la explicación de la variable en PC1 & PC2 se encontraba en solo 64.35%; por lo tanto, resultó eficiente haber eliminado las variables poco reelevantes.
Las variables más importantes para PC1 resultan ser las variables PrecioM, baños, área construída y parqueadero, lo que hace que PC1 esté influenciado por estas variables.
library(dplyr)
# Proporción de varianza explicada
varianza_explicada_2 <- summary(resultado_analisis_componentes_principales_2)$importance[2, ]
# Crear el scree plot
barplot(varianza_explicada_2,
main = "Proporcion de Varianza Explicada por Componentes Principales",
xlab = "Componentes Principales",
ylab = "Proporcion de Varianza Explicada",
col = "skyblue")
# Crear un biplot
biplot(resultado_analisis_componentes_principales_2,
main = "Biplot de analisis de Componentes Principales",
xlab = "Componente Principal 1",
ylab = "Componente Principal 2",
col = c("grey", "red"))
Con el gráfico anterior, el eje “x” representa el componente principal, mientras el eje “y” el segundo componente que captura la mayor parte de la varianza.
La variable habitaciones, al tener la longitud de la flecha más larga que el resto, indica que tiene mayor contribución; por otro lado, también muestra una correlación negativa con la variable piso, lo que indica que mientras una aumenta la otra disminuye.
Se visualiza una correlación positiva entre el área construída y el número de baños, indicando que ambos incrementan al mismo
Teniendo en cuenta que los dos primeros PC están capturando el 70.54% de los datos, se realiza la reducción de la dimensionalidad del conjunto de los datos a 2 PC.
# Se usan los dos primeros PC
data_reduced_2 <- predict(resultado_analisis_componentes_principales_2)[, 1:2]
# Extraer las cargas de los componentes principales del resultado del PCA
identificacion_componentes_principales_2 <- resultado_analisis_componentes_principales_2$rotation
# Seleccionar las cargas de los dos primeros componentes principales (PC1 a PC2), ya que juntos, explican el 78.49% de la varianza.
cargas_cuatro_componentes_principales_2 <- identificacion_componentes_principales_2[, 1:2]
# Mostrar las cargas para los primeros cuatro componentes principales
print(cargas_cuatro_componentes_principales_2)
## PC1 PC2
## piso 0.1233824 -0.5097239
## estrato -0.3031274 -0.5522896
## preciom -0.4670897 -0.2232240
## areaconst -0.4468059 0.1841179
## parqueaderos -0.4186572 -0.1891176
## banios -0.4608633 0.0906164
## habitaciones -0.2956577 0.5544840
Con la tabla anterior, se muestra que PC1 captura la variabilidad asociada a las variables como: precio promedio, area construída, parqueaderos y baños; por otro lado, PC2 está influenciado por piso, estrato y habiaciones.
if (!require(psych)) install.packages("psych")
## Cargando paquete requerido: psych
##
## Adjuntando el paquete: 'psych'
## The following objects are masked from 'package:ggplot2':
##
## %+%, alpha
## The following object is masked from 'package:boot':
##
## logit
library(psych)
cargas_originales <- resultado_analisis_componentes_principales_2$rotation
rotacion_varimax <- varimax(cargas_originales)
cargas_rotadas <- rotacion_varimax$loadings
print(round(cargas_rotadas, 2))
##
## Loadings:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## piso 1
## estrato 1
## preciom 1
## areaconst 1
## parqueaderos 1
## banios -1
## habitaciones 1
##
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## SS loadings 1.000 1.000 1.000 1.000 1.000 1.000 1.000
## Proportion Var 0.143 0.143 0.143 0.143 0.143 0.143 0.143
## Cumulative Var 0.143 0.286 0.429 0.571 0.714 0.857 1.000
Con la tabla anterior, se tiene un análisis de los componentes principales al aplicar una rotación Varimax con el fin de facilitar la interpretación de cargas.
En el PC1 la variable estrato está fuertemente asociada, capturando una gran cantidad de datos; en cuanto a PC2, el número de habitaciones tiene una gran predominancia.
en Proportion var, se evidencia que cada componente explica el 14.3% de la varianza totales en los datos, lo que indica que la varianza está distribuída equitativamente.
# Crear un biplot de los primeros dos componentes principales
biplot(resultado_analisis_componentes_principales_2, scale = 0)
Con el gráfico anterior, se evidencia que la variable piso tiene una
carga positiva hacia el componente principal (PC1), así que mientras
esta variable incrementa se genera un aumento en el primer componente
principal. En cuanto a la variable habitaciones, a diferencia de piso,
cuenta con una carga negativa frente a PC1, por lo tanto, si esta
variable incrementa, el valor de PC1 disminuye.
Por otro lado, en cuanto a PC2, las variables área construída y baño cuentan con una carga similar hacia dicho componente, generando un crecimiento entre ambas; así que se podría decir que si el área construída incrementa, también incrementará el número de baños, disminuyendo el valor del componente principal (PC1).
if (!require(factoextra)) install.packages("factoextra")
## Cargando paquete requerido: factoextra
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(factoextra)
# Visualizar las variables en función de su contribución a los primeros componentes principales
fviz_pca_var(resultado_analisis_componentes_principales_2,
col.var = "contrib", # Color por contribuciones a los PC
gradient.cols = c("#FF7F00", "#034D94"), # Colores del gradiente
repel = TRUE, # Evitar superposición de texto
axes = c(1, 2) # Cambiar los ejes a los primeros dos componentes principales
)
Con el gráfico anterior, se evidencia como la variable “piso”, cuenta
con una dirección de carga distinta a diferencia con las demás
variables, pero teniendo una relación positiva hacia PC1. Por otro lado,
la variable “estrato” también genera una relación positiva hacia el
componente principal.
# Seleccionar solo columnas numéricas
vivienda_modificado_2_numeric <- vivienda_modificado_2[, sapply(vivienda_modificado_2, is.numeric)]
# Realizar el PCA con las columnas numéricas
resultado_analisis_componentes_principales <- prcomp(vivienda_modificado_2_numeric, center = TRUE, scale. = TRUE)
if (!require(factoextra)) install.packages("factoextra")
library(factoextra)
# Realizar el PCA en tu dataframe
resultado_analisis_componentes_principales_2 <- prcomp(vivienda_modificado_2_numeric, center = TRUE, scale. = TRUE)
# Extraer los resultados del PCA
res.pca <- resultado_analisis_componentes_principales_2
# Extraer las puntuaciones para los primeros cuatro componentes principales
puntuaciones <- res.pca$x[, 1:3]
colnames(puntuaciones) <- c("PC1", "PC2", "PC3")
# Crear un dataframe con puntuaciones específicas para casos de interés
casos1 <- rbind(puntuaciones[98, 1:3], puntuaciones[778, 1:3])
rownames(casos1) <- c("98", "778")
casos1 <- as.data.frame(casos1)
casos2 <- rbind(puntuaciones[6, 1:3], puntuaciones[462, 1:3])
rownames(casos2) <- c("6", "462")
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) +
labs(title = "Visualizacion de Casos Especificos en los Primeros Dos Componentes Principales") +
theme_minimal()
Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas de las ofertas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.
# Cargar los datos
if (!exists("vivienda_modificado2"))
variables_clustering <- select(vivienda_modificado_2, estrato, preciom, areaconst, banios, habitaciones, parqueaderos)
# Seleccionar las variables relevantes para el clustering
variables_clustering <- select(vivienda_modificado_2, estrato, preciom, areaconst, banios, habitaciones, parqueaderos)
# Escalar las variables si es necesario
variables_clustering_scaled <- scale(variables_clustering)
# Determinar el número óptimo de clusters usando el método del codo
wcss <- numeric(10)
for (i in 1:10) {
kmeans_fit <- kmeans(variables_clustering_scaled, centers = i, nstart = 10)
wcss[i] <- kmeans_fit$tot.withinss
}
# Graficar el método del codo
plot(1:10, wcss, type = "b", pch = 19, frame = FALSE,
xlab = "Numero de clusters (k)", ylab = "WCSS")
fviz_nbclust(x = variables_clustering_scaled, FUNcluster = kmeans, method = "wss", k.max = 10,
diss = get_dist(variables_clustering_scaled, method = "euclidean"), nstart = 50)
## Warning: did not converge in 10 iterations
## Warning: did not converge in 10 iterations
## 2.1. Resulado del clustering
library(cluster)
require(cluster)
pam.res <- pam(variables_clustering_scaled, 5)
fviz_cluster(pam.res, geom = "point", ellipse.type = "norm", show.clust.cent = TRUE, star.plot = TRUE) + labs(title = "Resultado del clustering 5 PC") + theme_bw()
### 2.1.2 Cuatro componentes principales
library(cluster)
require(cluster)
pam.res <- pam(variables_clustering_scaled, 4)
fviz_cluster(pam.res, geom = "point", ellipse.type = "norm", show.clust.cent = TRUE, star.plot = TRUE) + labs(title = "Resultado del clustering 4 PC") + theme_bw()
library(cluster)
require(cluster)
pam.res <- pam(variables_clustering_scaled, 3)
fviz_cluster(pam.res, geom = "point", ellipse.type = "norm", show.clust.cent = TRUE, star.plot = TRUE) + labs(title = "Resultado del clustering 3 PC") + theme_bw()
library(cluster)
require(cluster)
pam.res <- pam(variables_clustering_scaled, 2)
fviz_cluster(pam.res, geom = "point", ellipse.type = "norm", show.clust.cent = TRUE, star.plot = TRUE) + labs(title = "Resultado del clustering 2 PC") + theme_bw()
Con las graficas anteriores, se evidencia la gran cantidad de datos que recogen los dos primeros PC (PC1 & PC2); por lo tanto, no solo a nivel de cifras, sino también teniendo en cuenta aspectos visuales, se logra determinar la importancia de estos 2 PC para la captura de los datos.
correlation_matriz <- cor(variables_clustering_scaled)
correlation_df <- as.data.frame(as.table(correlation_matriz))
colnames(correlation_df) <- c("Var1", "Var2", "Correlation")
# Convertir las correlaciones a porcentaje
correlation_df$Correlation_Percentage <- round(correlation_df$Correlation * 100, 1)
# Graficar la matriz de correlación como un mapa de calor con los valores de correlación en porcentaje
ggplot(data = correlation_df, aes(x = Var1, y = Var2, fill = Correlation)) +
geom_tile() +
scale_fill_gradient2(low = "green", high = "red", mid = "white", midpoint = 0) +
theme_minimal() +
labs(title = "Matriz de Correlación") +
geom_text(aes(label = paste0(Correlation_Percentage, "%")), color = "black", size = 3) # Agregar valores de correlación
Con la matriz de correlacion, es posible afirmar que no existe una
estrecha y alta correlación entre la diferentes variables; sin embargo,
es importante detectar aquellas tres variables con más alta correlación,
las cuales son:
69.3%: parqueaderos y precio 68.8%: área construída y precio 68%: baños y precio
Por lo tanto, se puede evidenciar que el precio promedio cuenta con una correlacion entre diferentes variables.
k_optimo <- 2
set.seed(444)
modelo_kmeans <- kmeans(variables_clustering_scaled, centers = k_optimo, nstart = 10)
cluster_labels <- as.factor(modelo_kmeans$cluster)
vivienda_limpia_con_cluster <- mutate(vivienda_modificado_2, cluster = cluster_labels)
# Visualizar los clusters en función de algunas variables relevantes
ggplot(vivienda_limpia_con_cluster, aes(x = estrato, y = preciom, color = cluster)) +
geom_point() +
labs(title = "Clusters de Propiedades Residenciales",
x = "Estrato Socioeconómico",
y = "Precio de la Propiedad") +
theme_minimal() +
scale_color_discrete(name = "Cluster")
Una vez el obtenido el gráfico por cada uno de los dos clusters,
relacionados a las variables precio y estrato socieconómico, se
evidencia que PC1 está afectado por las viviendas de menor precio en los
diferentes estratos; en cambio, PC2 está asociado por las viviendas de
precio alto.
ggplot(vivienda_limpia_con_cluster, aes(x = estrato, fill = cluster)) +
geom_density(alpha = 0.5) +
labs(title = "Distribución de Estrato por Cluster", x = "estrato", y = "Densidad") +
theme_minimal()
Con la gráfica anterior, se evidencia que en la variable estrato, PC1
está muy influenciado por los estratos 3 y 4, a diferencia del PC2 que
tiene una alta influencia por el estrato 6.
ggplot(vivienda_limpia_con_cluster, aes(x = preciom, fill = cluster)) +
geom_density(alpha = 0.5) +
labs(title = "Distribución de Precios por Cluster", x = "Precio", y = "Densidad") +
theme_minimal()
En cuanto a la variable precio, el PC1 tiene gran influencia por las
viviendas con precios hasta 400. El PC2 tiene una relación moderada
entre 600 y 800.
ggplot(vivienda_limpia_con_cluster, aes(x = areaconst, fill = cluster)) +
geom_density(alpha = 0.5) +
labs(title = "Distribución de Área construída por Cluster", x = "areaconst", y = "Densidad") +
theme_minimal()
Area construída tiene una fuerte densidad en viviendas con área
construída hasta 125 metros en el cluster 1. En cuanto al cluster 2, la
densidad es baja, sin embargo, se visualiza un alto desempeño en áreas
construídas entre 120 y 270 metros.
ggplot(vivienda_limpia_con_cluster, aes(x = banios, fill = cluster)) +
geom_density(alpha = 0.5) +
labs(title = "Distribución de Baños por Cluster", x = "banios", y = "Densidad") +
theme_minimal()
Por otro lado, en la variable baños la densidad más alta para el cluster
1, oscila entre 2 y 3 baños; en cambio, el cluster 2 tiene una densidad
alta entre 4 y 5 baños.
ggplot(vivienda_limpia_con_cluster, aes(x = habitaciones, fill = cluster)) +
geom_density(alpha = 0.5) +
labs(title = "Distribución de Habitaciones por Cluster", x = "Habitaciones", y = "Densidad") +
theme_minimal()
El Cluster 1 tiene una alta densidad entre 2.5 y 3 habitaciones.
ggplot(vivienda_limpia_con_cluster, aes(x = parqueaderos, fill = cluster)) +
geom_density(alpha = 0.5) +
labs(title = "Distribución de Parqueaderos por Cluster", x = "Parqueaderos", y = "Densidad") +
theme_minimal()
El cluster 1 tiene una alta densidad cuando se tiene 1 parqueadero.
Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio), para identificar patrones de comportamiento de la oferta en mercado inmobiliario.
library(FactoMineR)
library(ggplot2)
library(factoextra)
library(Rcpp)
library(pander)
##
## Adjuntando el paquete: 'pander'
## The following object is masked from 'package:GGally':
##
## wrap
library(corrplot)
## corrplot 0.92 loaded
library(gridExtra)
datos_inicial <- subset(vivienda_modificado_2, select = c("barrio", "zona", "tipo", "estrato"))
Barrio <- datos_inicial$barrio
Zona <- datos_inicial$zona
Tipo <- datos_inicial$tipo
Estrato <- datos_inicial$estrato
Datos <- cbind(datos_inicial, Barrio, Zona, Tipo, Estrato)
Datos[, 1:4] <- NULL
summary(Datos)
## Barrio Zona Tipo Estrato
## Length:8312 Length:8312 Length:8312 Min. :3.000
## Class :character Class :character Class :character 1st Qu.:4.000
## Mode :character Mode :character Mode :character Median :5.000
## Mean :4.633
## 3rd Qu.:5.000
## Max. :6.000
F1<-ggplot(Datos, aes(x=Zona)) + geom_bar(fill= "red")
F2<-ggplot(Datos, aes(x=Tipo)) + geom_bar(fill= "#FFD4A5")
F3<-ggplot(Datos, aes(x=Barrio)) + geom_bar(fill= "green")
F4<-ggplot(Datos, aes(x=Estrato)) + geom_bar(fill= "orange")
F5 <- grid.arrange(F1,F2,F3,F4, nrow = 4)
## 3.1. Relación barrio y zona
library(FactoMineR)
tabla_barrio_zona <- table(Datos$Barrio, Datos$Zona)
head(tabla_barrio_zona, n=10)
##
## Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
## 20 de julio 0 0 0 3 0
## 3 de julio 0 0 0 0 1
## acopi 0 157 0 0 1
## aguablanca 0 0 0 2 1
## aguacatal 0 0 108 0 1
## alameda 11 0 0 0 5
## alameda del rio 0 3 0 0 0
## alamos 0 14 0 0 0
## alborada 0 0 0 0 1
## alcazares 0 2 0 0 0
chisq.test(tabla_barrio_zona)
##
## Pearson's Chi-squared test
##
## data: tabla_barrio_zona
## X-squared = 29302, df = 1476, p-value < 2.2e-16
library(FactoMineR)
library(factoextra)
library(gridExtra)
resultados_barrio_zona <- CA(tabla_barrio_zona)
library(factoextra)
eig.val <- get_eigenvalue(resultados_barrio_zona)
eig.val
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 0.9622565 27.29569 27.29569
## Dim.2 0.9290207 26.35291 53.64860
## Dim.3 0.8963285 25.42555 79.07415
## Dim.4 0.7377002 20.92585 100.00000
fviz_screeplot(resultados_barrio_zona, addlabels = TRUE, ylim = c(0, 30))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
library(FactoMineR)
tabla_barrio_tipo <- table(Datos$Barrio, Datos$Tipo)
head(tabla_barrio_tipo, n=10)
##
## Apartamento Casa
## 20 de julio 0 3
## 3 de julio 0 1
## acopi 88 70
## aguablanca 1 2
## aguacatal 98 11
## alameda 4 12
## alameda del rio 2 1
## alamos 11 3
## alborada 0 1
## alcazares 2 0
chisq.test(tabla_barrio_tipo)
##
## Pearson's Chi-squared test
##
## data: tabla_barrio_tipo
## X-squared = 2416.6, df = 369, p-value < 2.2e-16
library(FactoMineR)
library(factoextra)
library(gridExtra)
resultados_barrio_tipo <- CA(tabla_barrio_tipo)
library(factoextra)
eig.val <- get_eigenvalue(resultados_barrio_tipo)
eig.val
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 0.290731 100 100
library(FactoMineR)
tabla_barrio_estrato <- table(Datos$Barrio, Datos$Estrato)
head(tabla_barrio_estrato, n=10)
##
## 3 4 5 6
## 20 de julio 3 0 0 0
## 3 de julio 0 1 0 0
## acopi 21 51 59 27
## aguablanca 3 0 0 0
## aguacatal 20 24 4 61
## alameda 13 3 0 0
## alameda del rio 3 0 0 0
## alamos 7 7 0 0
## alborada 0 1 0 0
## alcazares 2 0 0 0
chisq.test(tabla_barrio_estrato)
##
## Pearson's Chi-squared test
##
## data: tabla_barrio_estrato
## X-squared = 14864, df = 1107, p-value < 2.2e-16
library(FactoMineR)
library(factoextra)
library(gridExtra)
resultados_barrio_estrato <- CA(tabla_barrio_estrato)
library(factoextra)
eig.val <- get_eigenvalue(resultados_barrio_estrato)
eig.val
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 0.8217910 45.95375 45.95375
## Dim.2 0.6844665 38.27470 84.22844
## Dim.3 0.2820429 15.77156 100.00000
fviz_screeplot(resultados_barrio_estrato, addlabels = TRUE, ylim = c(0, 30))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
library(FactoMineR)
tabla_zona_tipo <- table(Datos$Zona, Datos$Tipo)
head(tabla_zona_tipo, n=10)
##
## Apartamento Casa
## Zona Centro 21 98
## Zona Norte 1198 722
## Zona Oeste 1029 169
## Zona Oriente 61 288
## Zona Sur 2787 1939
chisq.test(tabla_zona_tipo)
##
## Pearson's Chi-squared test
##
## data: tabla_zona_tipo
## X-squared = 695.36, df = 4, p-value < 2.2e-16
library(FactoMineR)
library(factoextra)
library(gridExtra)
resultados_zona_tipo <- CA(tabla_zona_tipo)
library(factoextra)
eig.val <- get_eigenvalue(resultados_zona_tipo)
eig.val
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 0.08365695 100 100
library(FactoMineR)
tabla_zona_estrato <- table(Datos$Zona, Datos$Estrato)
head(tabla_zona_estrato, n=10)
##
## 3 4 5 6
## Zona Centro 105 14 0 0
## Zona Norte 572 407 769 172
## Zona Oeste 54 84 290 770
## Zona Oriente 340 8 1 0
## Zona Sur 382 1616 1685 1043
chisq.test(tabla_zona_estrato)
##
## Pearson's Chi-squared test
##
## data: tabla_zona_estrato
## X-squared = 3867.7, df = 12, p-value < 2.2e-16
library(FactoMineR)
library(factoextra)
library(gridExtra)
resultados_zona_estrato <- CA(tabla_zona_estrato)
library(factoextra)
eig.val <- get_eigenvalue(resultados_zona_estrato)
eig.val
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 0.32644555 70.155929 70.15593
## Dim.2 0.12764789 27.432619 97.58855
## Dim.3 0.01122083 2.411452 100.00000
fviz_screeplot(resultados_zona_estrato, addlabels = TRUE, ylim = c(0, 30))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
library(FactoMineR)
tabla_tipo_estrato <- table(Datos$Tipo, Datos$Estrato)
head(tabla_tipo_estrato, n=10)
##
## 3 4 5 6
## Apartamento 639 1404 1763 1290
## Casa 814 725 982 695
chisq.test(tabla_tipo_estrato)
##
## Pearson's Chi-squared test
##
## data: tabla_tipo_estrato
## X-squared = 224.45, df = 3, p-value < 2.2e-16
library(FactoMineR)
library(factoextra)
library(gridExtra)
resultados_tipo_estrato <- CA(tabla_tipo_estrato)
library(factoextra)
eig.val <- get_eigenvalue(resultados_tipo_estrato)
eig.val
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 0.0270036 100 100
Presentar gráficos, mapas y otros recursos visuales para comunicar los hallazgos de manera clara y efectiva a la dirección de la empresa.
require(cluster)
cluster <- pam.res$clustering
x <- data.frame(vivienda_limpia_con_cluster, cluster)
summary(x)
## zona piso estrato preciom
## Length:8312 Min. : 1.000 Min. :3.000 Min. : 58.0
## Class :character 1st Qu.: 2.000 1st Qu.:4.000 1st Qu.: 220.0
## Mode :character Median : 3.000 Median :5.000 Median : 330.0
## Mean : 3.461 Mean :4.633 Mean : 433.8
## 3rd Qu.: 5.000 3rd Qu.:5.000 3rd Qu.: 540.0
## Max. :12.000 Max. :6.000 Max. :1999.0
## areaconst parqueaderos banios habitaciones
## Min. : 30.0 Min. : 1.000 Min. : 1.000 Min. : 1.000
## 1st Qu.: 80.0 1st Qu.: 1.000 1st Qu.: 2.000 1st Qu.: 3.000
## Median : 123.0 Median : 1.000 Median : 3.000 Median : 3.000
## Mean : 174.9 Mean : 1.713 Mean : 3.122 Mean : 3.629
## 3rd Qu.: 229.0 3rd Qu.: 2.000 3rd Qu.: 4.000 3rd Qu.: 4.000
## Max. :1745.0 Max. :10.000 Max. :10.000 Max. :10.000
## tipo barrio cluster cluster.1
## Length:8312 Length:8312 1:5683 Min. :1.000
## Class :character Class :character 2:2629 1st Qu.:1.000
## Mode :character Mode :character Median :1.000
## Mean :1.483
## 3rd Qu.:2.000
## Max. :2.000
boxplot(x$preciom ~ x$cluster,
main = "Distribución del precio de metro cuadrado por cluster",
ylab = "Precio del metro cuadrado",
xlab = "Cluster", las = 1,
col = c("#0d3b66", "#f4d353"))
boxplot(x$areaconst ~ x$cluster,
main = "Distribución del área construída por cluster",
ylab = "Precio del metro cuadrado",
xlab = "Cluster", las = 1,
col = c("#0d3b66", "#f4d353"))
boxplot(x$habitaciones ~ x$cluster,
main = "Distribución del número de habitaciones por cluster",
ylab = "Precio del metro cuadrado",
xlab = "Cluster", las = 1,
col = c("#0d3b66", "#f4d353"))
boxplot(x$banios ~ x$cluster,
main = "Distribución de la cantidad de baños por cluster",
ylab = "Precio del metro cuadrado",
xlab = "Cluster", las = 1,
col = c("#0d3b66", "#f4d353"))
boxplot(x$piso ~ x$cluster,
main = "Distribución del número de pisos por cluster",
ylab = "Precio del metro cuadrado",
xlab = "Cluster", las = 1,
col = c("#0d3b66", "#f4d353"))
conteo <- table(x$cluster, x$zona)
barplot(conteo, main = "Tipo de viviendas por zona",
xlab = "Categorias",
col = c("#0d3b66", "#f4d353"),
legend = rownames(conteo))
conteo <- table(x$cluster, x$tipo)
barplot(conteo, main = "Tipo de vivienda (casa o apartamento)",
xlab = "Categorias",
col = c("#0d3b66", "#f4d353"),
legend = rownames(conteo))
# Sumar el total de casas
total_casas <- sum(x$tipo == "Casa", na.rm = TRUE)
# Sumar el total de apartamentos
total_apartamentos <- sum(x$tipo == "Apartamento", na.rm = TRUE)
cat("Total de Apartamentos:", total_apartamentos, "\n")
## Total de Apartamentos: 5096
cat("Total de Casas:", total_casas, "\n")
## Total de Casas: 3216
Como se ven en las gráficas anteriores, PC1 está afectado por viviendas cuyo precio es bajo, con poca area construída y pocos baños, también con gran número de pisos, sobre todo en viviendas tipo apartamento.
En cuanto al PC2, este se encuetnra afectado por viviendas con precio y tamaño alto, con alto número de baños y pocos pisos; de esta forma, resulta ser lo contrario al PC1.
# Gráfico de líneas con línea de tendencia
ggplot(vivienda_modificado_2, aes(x = areaconst, y = preciom)) +
geom_line(color = "blue", size = 1) +
geom_smooth(method = "lm", color = "red", se = FALSE) +
labs(title = "Precio Medio en Función del Área Construida", x = "Área Construida", y = "Precio Medio") +
theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_smooth()` using formula = 'y ~ x'
Se evidencia que el precio promedio está en función del tamaño de las
viviendas, puesto que a mayor tamaño resultan ser más costosas.
# Gráfico de líneas con línea de tendencia
ggplot(vivienda_modificado_2, aes(x = estrato, y = preciom)) +
geom_line(color = "blue", size = 1) +
geom_smooth(method = "lm", color = "red", se = FALSE) +
labs(title = "Precio Medio en función del Estrato", x = "Estrato", y = "Precio Medio") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
Con el gráfico anterior, se evidencia el precio promedio por cada una de
los estratos; la línea roja, representa la tendencia de los precios a
través del método de regresión linea. De esta forma, se evidencia qeu
que el incremento real del valor de las viviendas de los estratos 5 al
6, está en línea con la ergresión lineal, a diferencia del precio
promedio de las viviendas de estrato 4 a 5.
# Gráfico de líneas con línea de tendencia
ggplot(vivienda_modificado_2, aes(x = areaconst, y = habitaciones)) +
geom_line(color = "blue", size = 1) +
geom_smooth(method = "lm", color = "red", se = FALSE) +
labs(title = "Número de Habitaciones en Función del Área Construida",
x = "Área Construida (m²)",
y = "Número de Habitaciones") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
# Gráfico de líneas con línea de tendencia
ggplot(vivienda_modificado_2, aes(x = banios, y = habitaciones)) +
geom_line(color = "blue", size = 1) +
geom_smooth(method = "lm", color = "red", se = FALSE) +
labs(title = "Número de habitaciones en Función al número de baños",
x = "Número de baños",
y = "Número de Habitaciones") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
# Gráfico de líneas con línea de tendencia
ggplot(vivienda_modificado_2, aes(x = areaconst, y = piso)) +
geom_line(color = "blue", size = 1) +
geom_smooth(method = "lm", color = "red", se = FALSE) +
labs(title = "Número de Pisos en Función del Área Construida - total viviendas", x = "Área Construida (m²)", y = "Número de Pisos") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
Con el gráfico anterior, se evidencia que entre menor área construída se
cuenta con más pisos.
Teniendo en cuenta que esto podría generar un sesgo en la interpretación y toma de decisiones por parte de la empresa, se desagrega el gráfico a nivel de viviendas tipo casa y viviendas tipo apartamento.
# Filtrar los datos para tipo "Casa" y graficar
ggplot(data = subset(vivienda_modificado_2, tipo == "Casa"), aes(x = areaconst, y = piso)) +
geom_line(color = "blue", size = 1) +
geom_smooth(method = "lm", color = "red", se = FALSE) +
labs(title = "Número de Pisos en Función del Área Construida - casas", x = "Área Construida (m²)", y = "Número de Pisos") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
# Filtrar los datos para tipo "Casa" y graficar
ggplot(data = subset(vivienda_modificado_2, tipo == "Apartamento"), aes(x = areaconst, y = piso)) +
geom_line(color = "blue", size = 1) +
geom_smooth(method = "lm", color = "red", se = FALSE) +
labs(title = "Número de Pisos en Función del Área Construida - apartamento", x = "Área Construida (m²)", y = "Número de Pisos") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
Se evidencia que para las viviendas tipo casa, el area construída no
afecta el número de pisos, ya que mantienen una media muy estable. En
cuanto a las viviendas tipo apartamento, el área construída si genera un
cambio en el número de pisos, mostrando una tendencia incremental
leve.
4.2. Gráfico de proporción
# Contar el número de viviendas por estrato
estrato_count <- as.data.frame(table(vivienda_modificado_2$estrato))
colnames(estrato_count) <- c("estrato", "count")
# Calcular el porcentaje
estrato_count <- estrato_count %>%
mutate(percentage = count / sum(count) * 100)
# Crear gráfico de pastel con porcentajes
ggplot(estrato_count, aes(x = "", y = count, fill = estrato)) +
geom_bar(width = 1, stat = "identity") +
coord_polar(theta = "y") +
geom_text(aes(label = sprintf("%.1f%%", percentage)), position = position_stack(vjust = 0.5), color = "white") +
scale_fill_manual(values = c("#1f77b4", "#aec7e8", "#d62728", "#ff7f0e", "#ffbb78")) +
labs(title = "Proporción de Estratos", x = "", y = "") +
theme_void()
# Contar el número de pisos
piso_count <- as.data.frame(table(vivienda_modificado_2$piso))
colnames(piso_count) <- c("piso", "count")
# Calcular el porcentaje
piso_count <- piso_count %>%
mutate(percentage = count / sum(count) * 100)
num_colors <- length(unique(piso_count$piso))
# Crear gráfico de pastel con porcentajes
ggplot(piso_count, aes(x = "", y = count, fill = as.factor(piso))) +
geom_bar(width = 1, stat = "identity") +
coord_polar(theta = "y") +
geom_text(aes(label = sprintf("%.1f%%", percentage)),
position = position_stack(vjust = 0.5),
color = "white") +
scale_fill_manual(values = RColorBrewer::brewer.pal(num_colors, "Set3")) +
labs(title = "Proporción de Propiedades por Número de Pisos", x = "", y = "") +
theme_void()
# Contar el número de baños
banios_count <- as.data.frame(table(vivienda_modificado_2$banios))
colnames(banios_count) <- c("banios", "count")
# Calcular el porcentaje
banios_count <- banios_count %>%
mutate(percentage = count / sum(count) * 100)
# Determinar el número de colores necesarios
num_colors <- length(unique(banios_count$banios))
# Crear gráfico de pastel con porcentajes
ggplot(banios_count, aes(x = "", y = count, fill = as.factor(banios))) +
geom_bar(width = 1, stat = "identity") +
coord_polar(theta = "y") +
geom_text(aes(label = sprintf("%.1f%%", percentage)),
position = position_stack(vjust = 0.5),
color = "white") +
scale_fill_manual(values = RColorBrewer::brewer.pal(num_colors, "Set3")) +
labs(title = "Proporción de Propiedades por Número de Baños", x = "", y = "") +
theme_void()
“El informe final debe incluir análisis detallados de los resultados obtenidos, las conclusiones claves y las recomendaciones específicas para guiar las decisiones estratégicas de la empresa inmobiliaria. Se espera que este análisis de datos proporcione ventajas competitivas en el mercado, optimizando la inversión y maximizando los beneficios en un entorno altamente competitivo y en constante cambio”.
Una vez revisado y analizado la base de datos de las viviendas, se puede llegar a las siguientes conclusiones:
• Se cuentan con más viviendas tipo apartamento que casa, con una participación de 61.31% y 38.69% respectivamente.
• La zona sur tiene más viviendas que el resto de zonas, con una participación de 56.95%; seguido de la zona norte y zona oeste, con 23.1% y 14.4% respectivamente.
• Estrato 5 tiene mayor participación en el número de viviendas, con 33%; seguido por el estrato 4 con 25.6% y el estrato 6 con 23.9%.
• Las casas tienen un precio promedio más alto, con un valor de 540 vs 367 de los apartamentos.
• Las zonas con el precio más alto son: oeste, norte y sur, ambas muy parejas, con un valor de 1.999, 1.940 y 1.900 respectivamente. Sin embargo, como precio promedio alto, las viviendas se encuentran ubicadas en la zona oeste con un valor de 678; seguido por la zona sur y zona norte, con 427 y 346 respectivamente.
• En cuanto al análisis de variables, no se encuentran correlaciones fuertes entre ellas; sin embargo, se visualizan patrones entre: precio y número de parqueaderos; precio y área construida y precio y número de baños; por lo tanto, es posible afirmar que un precio alto depende de estas tres características de las viviendas: parqueadero, área construida y número de baños.
• Se evidencia que el precio de las viviendas cuenta con un crecimiento lineal en función del área construida y el número de habitaciones, sobre todo en las viviendas ubicadas en estrato 6. Por otro lado, es importante mencionar que el precio de las viviendas no está en función al número de pisos.
Teniendo en cuenta lo anterior, la compañía inmobiliaria puede generar sus estrategias hacia dos caminos totalmente diferentes, pero que, de conocer las características propias de cada tipo de vivienda, podría generar grandes beneficios:
Viviendas de precio alto: si es interés de la empresa ofrecer viviendas con precios de venta alto, estas podrían ser construidas en las zonas oeste y deben ser de tipo casa, con un área construida alta, entre 125 y 270 metros cuadrados, de 2 pisos y preferiblemente en el estrato 6 o 5; con precios de 500 en adelante; también deberían considerar entre 4 a 5 baños y con 4, 3 o 5 habitaciones, dependiendo de igual forma del área de construcción. En cuanto al número de parqueaderos mínimo se debería ofrecer una vivienda con 2 parqueaderos.
Viviendas de precio bajo: si la empresa quiere enfocar sus esfuerzos hacia viviendas de precio promedio bajo, estas deben ser de tipo apartamento, con área construida hasta 125 metros y precios hasta 250; el número de baños podría variar entre 2 y 3, dependiendo del tamaño del apartamento; así como debería tener 3 habitaciones. En cuanto al número de parqueaderos con 1 podría ser suficiente.