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.
Aquí se describen los paquetes usados
#devtools::install_github("dgonxalex80/paqueteMOD", force = TRUE)
library(paqueteMOD)
library(tidyverse)
library(mice)
library(factoextra)
library(cluster)
library(fpc)
library(psych)
library(corrplot)
library(FactoMineR)
library(gridExtra)
library(pander)
library(ggdendro)
require(raster)
require(sf)
Ahora se cargan los datos
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 inicia con un resumen de los datos contenidos en el dataframe de vivienda
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
El análisis previo revela rápidamente que la variable
estrato solo incluye datos de viviendas clasificadas entre
3 y 6. Las viviendas a considerar tienen precios que oscilan entre los
58 y los 1999 millones de COP. En cuanto a las áreas construidas, estas
varían entre los 30 y los 1745 metros cuadrados. Se observa que 1605
viviendas no indican si cuentan con parqueaderos, aunque algunas
registran hasta 10 de estos. Es importante notar que existen viviendas
que no registran baños ni habitaciones, lo cual podría requerir una
limpieza de datos, ya que estos registros podrían no tener sentido en el
contexto de este análisis. Se aclará finalmente que, el análisis se
realizará sobre 8322 viviendas urbanas que se encuentran en una ciudad
específica.
Para analizar las variables de tipo character se hace lo siguiente:
# También puedes usar dplyr para obtener resúmenes más detallados
vivienda %>%
group_by(zona) %>%
summarise(n = n(), .groups = "drop")
## # A tibble: 6 × 2
## zona n
## <chr> <int>
## 1 Zona Centro 124
## 2 Zona Norte 1920
## 3 Zona Oeste 1198
## 4 Zona Oriente 351
## 5 Zona Sur 4726
## 6 <NA> 3
vivienda %>%
group_by(tipo) %>%
summarise(n = n(), .groups = "drop")
## # A tibble: 3 × 2
## tipo n
## <chr> <int>
## 1 Apartamento 5100
## 2 Casa 3219
## 3 <NA> 3
Se observa que las viviendas están ubicadas principalmente en las zonas Norte, Oeste y Sur de la ciudad. La zona Sur alberga cerca del 56% de las viviendas totales a analizar. La base de datos contiene más registros de apartamentos que de casas.
En cuanto a las variables barrio y piso,
que son categóricas pero con muchas categorías, se procederá a construir
un ‘top 5’ para cada una de ellas.
# Construye el 'top 5' de los pisos más populares
vivienda %>%
group_by(piso) %>%
summarise(n = n(), .groups = "drop") %>%
arrange(desc(n)) %>%
head(5)
## # A tibble: 5 × 2
## piso n
## <chr> <int>
## 1 <NA> 2638
## 2 02 1450
## 3 03 1097
## 4 01 860
## 5 04 607
# Construye el 'top 5' de los barrios con más viviendas a la venta
vivienda %>%
group_by(barrio) %>%
summarise(n = n(), .groups = "drop") %>%
arrange(desc(n)) %>%
head(5)
## # A tibble: 5 × 2
## barrio n
## <chr> <int>
## 1 valle del lili 1008
## 2 ciudad jardín 516
## 3 pance 409
## 4 la flora 366
## 5 santa teresita 262
Se evidencia que el barrio Valle del Lili es el que posee mayor cantidad de viviendas disponibles en el mercado, también que los pisos 2 y 3 son los más ofertados, aunque la información del piso no siempre queda consignada en las ofertas realizadas de vivienda.
Ahora se realiza una revisión más detallada de la variable
preciom
resumen <- describe(vivienda$preciom)
resumen
## vars n mean sd median trimmed mad min max range skew kurtosis
## X1 1 8320 433.89 328.65 330 374.43 207.56 58 1999 1941 1.85 3.67
## se
## X1 3.6
El precio medio de las viviendas es de 433.89 millones COP. La desviación estándar es de 328.65 millones, lo que indica que los precios de las viviendas varían considerablemente alrededor de la media.La asimetría es de 1.85, lo que indica que la distribución de los precios de las viviendas está sesgada hacia la derecha. Esto significa que hay un número de viviendas con precios muy altos que están alejando la media de la mediana.
Aunque se podrían empezar a realizar distintos cruces de variables para analizarlas, la idea es iniciar con un análisis de componentes principales, el cual permitirá reducir la dimensionalidad de los datos sin perder información significativa. Este enfoque facilitará la interpretación de los resultados y ayudará a identificar las variables que más contribuyen a la variabilidad en los datos. Además, proporcionará una visión más clara de las posibles correlaciones entre las variables.
Primero se realiza un análisis de valores faltantes
# Ahora puedes generar tu gráfico
vivienda_new = vivienda[,c(4:9)]
md.pattern(vivienda_new, rotate.names = TRUE)
## preciom estrato areaconst banios habitaciones parqueaderos
## 6717 1 1 1 1 1 1 0
## 1602 1 1 1 1 1 0 1
## 1 1 0 0 0 0 0 5
## 2 0 0 0 0 0 0 6
## 2 3 3 3 3 1605 1619
De lo anterior se puede concluir que:
parqueaderos.preciom.La variable parqueaderos presenta datos faltantes en el
19% de los registros. Dado que esta variable es considerada
significativa para determinar el precio de las viviendas, se opta por
eliminar los registros que carecen de datos completos. De esta manera,
se construirá un conjunto de datos sin registros faltantes.
# Elimina las filas con datos faltantes
vivienda_new <- na.omit(vivienda_new)
# Ahora 'vivienda_new' no tiene filas con datos faltantes
md.pattern(vivienda_new, rotate.names = TRUE)
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## estrato preciom areaconst parqueaderos banios habitaciones
## 6717 1 1 1 1 1 1 0
## 0 0 0 0 0 0 0
Para prevenir que las variables con escalas de valores más grandes sesguen las estimaciones, se lleva a cabo la estandarización de las variables. Este paso se realiza antes de proceder con el proceso de estimación de los componentes principales. De esta manera, se asegura que todas las variables contribuyan de manera equitativa al análisis, independientemente de su escala original.
viviendaZ = vivienda_new %>%
scale()
head(viviendaZ) # primeros 6 registros
## estrato preciom areaconst parqueaderos banios habitaciones
## [1,] -1.9279348 -0.6532909 -0.7712458 -0.7424551 -0.1850976 1.7511897
## [2,] -1.9279348 -0.4443626 -0.4242642 -0.7424551 -0.9096316 -0.4477275
## [3,] -1.9279348 -0.3548218 0.2696991 0.1465058 -0.9096316 0.2852449
## [4,] -0.8746661 -0.2055873 0.6860770 1.0354668 1.2639704 -0.4477275
## [5,] 0.1786025 -0.6234440 -0.6324532 -0.7424551 -0.9096316 -0.4477275
## [6,] 0.1786025 -0.6831378 -0.6532721 -0.7424551 -0.1850976 -0.4477275
Ya con las variables escaladas se puede proceder con el calculo de los componentes principales
prcomp(viviendaZ)
## Standard deviations (1, .., p=6):
## [1] 1.8664857 1.1059274 0.7067478 0.5996120 0.4943519 0.4355974
##
## Rotation (n x k) = (6 x 6):
## PC1 PC2 PC3 PC4 PC5 PC6
## estrato 0.2953982 -0.6377404 0.5431029 0.07074563 0.4349440 -0.1299429
## preciom 0.4704788 -0.2394751 -0.1081038 -0.29100096 -0.2659341 0.7444545
## areaconst 0.4502724 0.2044012 -0.2594726 -0.65721148 0.3038390 -0.4048503
## parqueaderos 0.4278010 -0.1513045 -0.6161907 0.62045124 0.1192404 -0.1233864
## banios 0.4652553 0.1598972 0.3695544 0.14075513 -0.6782753 -0.3762054
## habitaciones 0.2986104 0.6676068 0.3313085 0.27132051 0.4165440 0.3290044
res.pca <- prcomp(viviendaZ)
fviz_eig(res.pca, addlabels = TRUE)
En este caso el primer componente principal explica el 58.1% de la variabilidad contenida en la base de datos y entre los dos primeros el 78.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(res.pca,
col.var = "contrib", # Color by contributions to the PC
gradient.cols = c("#FF7F00", "#034D94"),
repel = TRUE # Avoid text overlapping
)
El círculo de correlaciones en el primer plano factorial revela varias relaciones interesantes entre las variables. Se observa que el precio de las viviendas y el número de parqueaderos están altamente correlacionados, lo que sugiere que las viviendas con más parqueaderos tienden a tener precios más altos.
De manera similar, el área construida y el número de baños también muestran una alta correlación, lo que indica que las viviendas con mayor área construida suelen tener más baños.
Por otro lado, las variables habitaciones y
estrato presentan una correlación baja, ya que casi forman
un ángulo recto entre ellas en el círculo de correlaciones. Sin embargo,
a pesar de su baja correlación, ambas variables muestran altos niveles
de contribución a la conformación del primer componente principal. Esto
sugiere que, aunque no estén fuertemente correlacionadas entre sí, ambas
variables son importantes para explicar la variabilidad en los datos.
Estas también son las variables que más relación poseen con el segundo
componente principal.
Es importante destacar que, de todas las variables,
parqueaderos es la que menos contribuye a la conformación
del primer componente principal.
Para explicar el sentido de los ejes, se escogen dos casos extremos conformados por las siguientes viviendas
casos1 <- rbind(res.pca$x[426,1:2],res.pca$x[1258,1:2]) # CP1
rownames(casos1) = c("426","1258")
casos1 <- as.data.frame(casos1)
casos2 <- rbind(res.pca$x[4060,1:2], res.pca$x[6645,1:2]) # CP2
rownames(casos2) = c("4060","6645")
casos2 <- as.data.frame(casos2)
# Genera el gráfico
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_text(data = casos1, aes(x = PC1, y = PC2, label = rownames(casos1)), color = "red", vjust = -1) +
geom_point(data = casos2, aes(x = PC1, y = PC2), color = "blue", size = 3) +
geom_text(data = casos2, aes(x = PC1, y = PC2, label = rownames(casos2)), color = "blue", vjust = -1)
datos <- rbind(vivienda_new[426,], # ok
vivienda_new[1258,],
vivienda_new[4060,],
vivienda_new[6645,])
datos <- as.data.frame(datos)
rownames(datos) = c("Vivienda 0426","Vivienda 1258","Vivienda 4060","Vivienda 6645")
datos
## estrato preciom areaconst parqueaderos banios habitaciones
## Vivienda 0426 3 89 130 1 1 1
## Vivienda 1258 6 1800 1586 10 4 5
## Vivienda 4060 6 580 138 2 4 0
## Vivienda 6645 3 350 72 1 4 10
La vivienda 0426 se caracteriza por tener un precio relativamente bajo, situado en 89 millones de COP. En contraste, la vivienda 1258, ubicada en el extremo opuesto del análisis, presenta un precio considerablemente más elevado, ascendiendo a 1800 millones de COP. Esta distribución ilustra la dirección en la que aumentan los valores del primer componente principal (Dim1).
Este primer componente parece estar fuertemente asociado con las condiciones de infraestructura de la vivienda. Por lo tanto, una vivienda que se ubica cerca del componente y en la misma dirección que la variable de precio, probablemente también exhibirá valores más altos en las demás variables. Esto se debe a que se observa una correlación entre casi todas estas variables y el precio.
En cuanto a la vivienda 4060, esta se distingue por tener un estrato alto (6), mientras que la vivienda 6645 presenta un estrato más bajo (3). Existe una particularidad con respecto al número de habitaciones, ya que debido a la correlación entre el estrato y las habitaciones, es probable que las viviendas cercanas a este componente en ubicaciones opuestas presenten ya sea un estrato alto y un bajo número de habitaciones, o viceversa. Sin embargo, las viviendas más cercanas al centro del plano tienden a mostrar un equilibrio más notable en esta relación.
fviz_pca_biplot(res.pca,
repel = TRUE,
habillage = vivienda_new$estrato,
col.var = "#034A94", # Variables color
col.ind = c("#DEDEDE", "#034A94") # Individuals color
)
La representación gráfica de los dos primeros componentes principales revela las relaciones entre las variables. Se puede observar una correlación entre el precio y el número de parqueaderos, así como entre el número de baños y el área construida. Estas variables forman un grupo que tiene un impacto significativo en el primer componente principal.
Por otro lado, las variables de estrato y número de habitaciones influyen más en el segundo componente principal. Los colores correspondientes a los estratos indican que, en general, las viviendas de estrato superior tienden a tener precios más altos y una infraestructura más amplia.
El gráfico también destaca un hallazgo interesante: las viviendas de estrato 3 y 4, que a pesar de no ser las de estrato más alto, también presentan precios elevados y una infraestructura considerable en términos de áreas, habitaciones y baños. Esto sugiere que el estrato no es el único factor que determina el precio y la infraestructura de una vivienda.
La idea es 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.
# Correlación
cor(vivienda_new)
## estrato preciom areaconst parqueaderos banios
## estrato 1.00000000 0.5876109 0.2591140 0.4226084 0.3950842
## preciom 0.58761094 1.0000000 0.6839831 0.6886785 0.6719967
## areaconst 0.25911395 0.6839831 1.0000000 0.5848290 0.6671746
## parqueaderos 0.42260837 0.6886785 0.5848290 1.0000000 0.5705065
## banios 0.39508418 0.6719967 0.6671746 0.5705065 1.0000000
## habitaciones -0.08049567 0.2670210 0.5339207 0.2844808 0.5969167
## habitaciones
## estrato -0.08049567
## preciom 0.26702104
## areaconst 0.53392073
## parqueaderos 0.28448076
## banios 0.59691671
## habitaciones 1.00000000
corrplot(cor(vivienda_new))
Antes de iniciar con la construcción de clúster, ver que la matriz de correlación concuerda con lo mostrado en el círculo de correlaciones donde lo que menos correlación presenta frente al precio es el número de habitaciones, un detalle no menor que se debería analizar con más detenimiento frente a las variables que determinan el precio de una vivienda. La hipótesis aquí es que la variable habitaciones puede haber quedado mal específicada en los datos o que en realidad el número de habitaciones no tiene nada que ver con el precio de la vivienda, esto pues en todos los estratos y formas de vivienda, el número de habitaciones es similar en todas.
Ahora se construyen los clústers.
# PCA
res.pca <- PCA(vivienda_new, graph = FALSE, scale.unit = TRUE )
# Calculamos la distancia euclidiana
distancia <- dist(res.pca$ind$coord, method = "euclidean")
# Cluster
res.HCPC <- HCPC(res.pca, nb.clust=4)
Para ver si k=4 es el mejor número de clústers se utiliza el siguiente
gráfico
# Método del codo
wss <- sapply(1:10, function(k){kmeans(res.pca$ind$coord, k)$tot.withinss})
plot(1:10, wss, type="b", pch = 19, frame = FALSE,
xlab="Número de clusters K", ylab="Total within-clusters sum of squares")
# Realizamos el clustering jerárquico
res.hclust <- hclust(distancia, method = "ward.D2")
# Calculamos el índice de Calinski-Harabasz para diferentes números de clusters
ch <- c()
for (k in 2:10) {
cluster_assignments <- cutree(res.hclust, k)
ch[k] <- cluster.stats(distancia, cluster_assignments)$ch
}
# Graficamos el índice de Calinski-Harabasz
plot(2:10, ch[2:10], type = "b", xlab = "Número de clusters", ylab = "Índice de Calinski-Harabasz")
Tanto el método del codo como el índice de Calinski-Harabasz muestran que k=4, es un buen valor a la hora de seleccionar el óptimo de clústers, ahora se procede a revisar las características de cada clúster.
# Caracteristicas de las viviendas
res.HCPC$desc.var
##
## Link between the cluster variable and the quantitative variables
## ================================================================
## Eta2 P-value
## estrato 0.5115513 0
## preciom 0.7088112 0
## areaconst 0.5796944 0
## parqueaderos 0.5840964 0
## banios 0.5968006 0
## habitaciones 0.5470108 0
##
## Description of each cluster by quantitative variables
## =====================================================
## $`1`
## v.test Mean in category Overall mean sd in category Overall sd
## habitaciones -37.39526 2.938025 3.610838 0.6547489 1.3642062
## estrato -43.74113 4.282763 4.830430 0.7338314 0.9493547
## areaconst -45.10955 95.413289 181.136408 44.9919667 144.0891185
## parqueaderos -45.22423 1.164300 1.835194 0.3884100 1.1248251
## preciom -50.47409 245.865074 468.880601 84.1922536 335.0181418
## banios -56.29631 2.230794 3.255471 0.6171589 1.3800948
## p.value
## habitaciones 4.666398e-306
## estrato 0.000000e+00
## areaconst 0.000000e+00
## parqueaderos 0.000000e+00
## preciom 0.000000e+00
## banios 0.000000e+00
##
## $`2`
## v.test Mean in category Overall mean sd in category Overall sd
## estrato 42.077915 5.566683 4.830430 0.5205347 0.9493547
## banios 13.176047 3.590620 3.255471 0.8522908 1.3800948
## preciom 12.042189 543.236932 468.880601 198.1223143 335.0181418
## parqueaderos 9.764005 2.037616 1.835194 0.5468315 1.1248251
## areaconst -3.555174 171.695012 181.136408 68.3998397 144.0891185
## habitaciones -9.294717 3.377137 3.610838 0.7061908 1.3642062
## p.value
## estrato 0.000000e+00
## banios 1.205430e-39
## preciom 2.132208e-33
## parqueaderos 1.606820e-22
## areaconst 3.777294e-04
## habitaciones 1.475982e-20
##
## $`3`
## v.test Mean in category Overall mean sd in category Overall sd
## habitaciones 53.97947 6.119110 3.610838 1.5927523 1.3642062
## banios 25.61148 4.459424 3.255471 1.2962603 1.3800948
## areaconst 23.70205 297.464071 181.136408 116.3119806 144.0891185
## estrato -22.07833 4.116492 4.830430 0.8207328 0.9493547
## p.value
## habitaciones 0.000000e+00
## banios 1.136501e-144
## areaconst 3.434430e-124
## estrato 5.106609e-108
##
## $`4`
## v.test Mean in category Overall mean sd in category Overall sd
## preciom 61.12031 1144.574257 468.880601 350.4752529 335.0181418
## parqueaderos 55.95538 3.912129 1.835194 1.5199829 1.1248251
## areaconst 51.02315 423.738416 181.136408 200.3409117 144.0891185
## banios 42.62754 5.196782 3.255471 1.2225762 1.3800948
## estrato 29.03747 5.740099 4.830430 0.5211146 0.9493547
## habitaciones 17.77226 4.410891 3.610838 1.3047818 1.3642062
## p.value
## preciom 0.000000e+00
## parqueaderos 0.000000e+00
## areaconst 0.000000e+00
## banios 0.000000e+00
## estrato 2.215129e-185
## habitaciones 1.159203e-70
Para interpretar los clústeres, es esencial comprender los signos positivos o negativos que cada valor posee en el v.test.
Analizar y entender los clústeres de esta manera es la forma más efectiva de segmentar las viviendas. Esto permite tomar decisiones informadas que afectan la compra y venta de las mismas. Además, facilita la construcción de un catálogo inmobiliario que, dependiendo de la metodología de negocio que se esté implementando, permitirá seleccionar el nicho más conveniente para trabajar.
Se desea examinar la relación entre las variables categóricas (tipo de vivienda, zona, barrio, estrato y precio_categorico), para identificar patrones de comportamiento de la oferta en mercado inmobiliario.
# Datos para analizar
vivienda_new_2 = vivienda[,c(2,4,5,10,11)]
hist(vivienda_new_2$preciom)
## De aquí se puede observar que la variable precio podría definirse de forma categorica en intervalor de 250 millones COP para un total de 8 categorias
# Define los intervalos para preciom
breaks <- seq(0, 2000, by = 250)
# Crea una nueva variable con los intervalos en un nuevo dataframe
vivienda_AC <- vivienda_new_2
vivienda_AC$preciom <- NULL # Elimina la variable preciom
vivienda_AC$preciom_categorizado <- cut(vivienda_new_2$preciom, breaks = breaks, include.lowest = TRUE, labels = FALSE)
# Organiza los datos a tipo factor
labels <- paste0("[", breaks[-length(breaks)], "-", breaks[-1], ")")
vivienda_AC$preciom_categorizado <- cut(vivienda_new_2$preciom, breaks = breaks, include.lowest = TRUE, labels = labels)
vivienda_AC$estrato <- as.factor(vivienda_AC$estrato)
vivienda_AC$zona <- as.factor(vivienda_AC$zona)
vivienda_AC$tipo <- as.factor(vivienda_AC$tipo)
vivienda_AC$barrio <- as.factor(vivienda_AC$barrio)
Nota: Los barrios generan demasiadas categorías lo que los convierte en algo demasiado complejo de analizar
Se revisan las variables resultantes para el análisis
# Crea los gráficos de barras con las etiquetas del eje x giradas
G1 <- ggplot(vivienda_AC, aes(x=zona)) + geom_bar(fill= "#DDB4EB") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
G2 <- ggplot(vivienda_AC, aes(x=estrato)) + geom_bar(fill= "#FFD4A5")
G3 <- ggplot(vivienda_AC, aes(x=tipo)) + geom_bar(fill= "#41894A")
G4 <- ggplot(vivienda_AC, aes(x=preciom_categorizado)) + geom_bar(fill= "#FFEC28") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
# Organiza los gráficos en una cuadrícula
grid.arrange(G1, G2, G3, G4, nrow = 2)
Se revisan los datos faltantes
vivienda_AC$barrio <- NULL # Elimina la variable preciom
md.pattern(vivienda_AC, rotate.names = TRUE)
## preciom_categorizado zona estrato tipo
## 8319 1 1 1 1 0
## 1 1 0 0 0 3
## 2 0 0 0 0 4
## 2 3 3 3 11
Se observa que: - 8319 casos tienen datos completos (ningún valor faltante). - Hay 1 caso donde solo preciom_categorizado tiene un valor y las demás variables son faltantes. - Hay 2 casos donde todas las variables son faltantes. - preciom_categorizado tiene 2 valores faltantes en total, mientras que zona, estrato, tipo y barrio tienen cada uno 3 valores faltantes.
Al tratarse de muy pocos datos faltantes se decide eliminarlos.
# Elimina las filas con datos faltantes
vivienda_AC <- na.omit(vivienda_AC)
# Ahora 'vivienda_new' no tiene filas con datos faltantes
md.pattern(vivienda_AC, rotate.names = TRUE)
## /\ /\
## { `---' }
## { O O }
## ==> V <== No need for mice. This data set is completely observed.
## \ \|/ /
## `-----'
## zona estrato tipo preciom_categorizado
## 8319 1 1 1 1 0
## 0 0 0 0 0
Aunque es posible crear una tabla cruzada con las 5 variables, esta sería demasiado complicado de interpretar, por lo que se decide hacer 3 tablas cruzadas para analizar:
tabla <- table(vivienda_AC$zona, vivienda_AC$estrato)
colnames(tabla) <- c("Estrato3", "Estrato4", "Estrato5", "Estrato6" )
tabla
##
## Estrato3 Estrato4 Estrato5 Estrato6
## Zona Centro 105 14 4 1
## Zona Norte 572 407 769 172
## Zona Oeste 54 84 290 770
## Zona Oriente 340 8 2 1
## Zona Sur 382 1616 1685 1043
chisq.test(tabla)
##
## Pearson's Chi-squared test
##
## data: tabla
## X-squared = 3830.4, df = 12, p-value < 2.2e-16
El resultado indica que se rechaza la hipótesis de independencia de las variables (p-value: 0.0000), indicando grado tipo de relación entre ellas.
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.
resultados_ac_ZE <- CA(tabla)
El gráfico permite establecer relaciones y validarlas como son:
Para medir el grado de representatividad del proceso calculas los valores de la varianza acumulada, utilizando para ellos los valores propios de la matriz de discrepancias
fviz_screeplot(resultados_ac_ZE, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
Los resultados indican que la primera componente resumen el 70% y los dos primeros componentes prepresentados en el plano factorial, mientras que los dos primeros ejes resumen un 97.7% de los datos.
tabla2 <- table(vivienda_AC$preciom_categorizado, vivienda_AC$estrato)
colnames(tabla2) <- c("Estrato3", "Estrato4", "Estrato5", "Estrato6" )
tabla2
##
## Estrato3 Estrato4 Estrato5 Estrato6
## [0-250) 1050 1233 525 19
## [250-500) 360 747 1658 469
## [500-750) 32 118 411 607
## [750-1000) 7 19 86 425
## [1000-1250) 1 5 29 200
## [1250-1500) 2 5 29 150
## [1500-1750) 1 1 5 72
## [1750-2000) 0 1 7 45
chisq.test(tabla2)
##
## Pearson's Chi-squared test
##
## data: tabla2
## X-squared = 5016.7, df = 21, p-value < 2.2e-16
El resultado indica que se rechaza la hipótesis de independencia de las variables (p-value: 0.0000), indicando grado tipo de relación entre ellas.
resultados_ac_PE <- CA(tabla2)
El gráfico permite establecer relaciones y validarlas como son:
Para medir el grado de representatividad del proceso calculas los valores de la varianza acumulada, utilizando para ellos los valores propios de la matriz de discrepancias.
fviz_screeplot(resultados_ac_PE, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
Las variables se representan en los 2 primeros ejes, siendo la suma de ambas el 100% de la variabilidad.
tabla3 <- table(vivienda_AC$preciom_categorizado, vivienda_AC$zona)
colnames(tabla3) <- c("Zona_Centro", "Zona_Norte", "Zona_Oeste", "Zona_Oriente", "Zona_Sur")
tabla3
##
## Zona_Centro Zona_Norte Zona_Oeste Zona_Oriente Zona_Sur
## [0-250) 49 805 98 228 1647
## [250-500) 64 776 400 119 1875
## [500-750) 8 219 323 3 615
## [750-1000) 2 80 151 0 304
## [1000-1250) 1 21 109 0 104
## [1250-1500) 0 12 73 1 100
## [1500-1750) 0 5 21 0 53
## [1750-2000) 0 2 23 0 28
chisq.test(tabla3)
## Warning in chisq.test(tabla3): Chi-squared approximation may be incorrect
##
## Pearson's Chi-squared test
##
## data: tabla3
## X-squared = 1090.2, df = 28, p-value < 2.2e-16
Nuevament, el resultado indica que se rechaza la hipótesis de independencia de las variables (p-value: 0.0000), indicando grado tipo de relación entre ellas.
resultados_ac_ZP <- CA(tabla3)
El gráfico muestra que la Zona Oeste es la más costosa, seguida por la zona Sur, que posee valores medios, y las zonas más económicas respecto al precio de vivienda son la Zona Norte, Centro y Oriente.
fviz_screeplot(resultados_ac_ZP, addlabels = TRUE, ylim = c(0, 100))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
El primer eje 1 se lleva casi toda la variabilidad con 95.6%
De esta forma se pueden seguir realizando cruces hasta obtener todos los que se consideren necesarios para las necesidades de la empresa.
En relación con el análisis de componentes principales, este método ofrece una excelente aproximación al estado de las viviendas. En este caso, contamos con diversas variables numéricas que permiten establecer correlaciones entre ellas, especialmente las asociadas a la variación de los precios. Esto nos permite comprender qué variables están más relacionadas con este valor y en qué magnitud.
El análisis de conglomerados potencia la visión proporcionada por el análisis de componentes principales. Una vez definidos los grupos de segmentación, estos ayudan a identificar viviendas con similitudes entre sí. Esto genera una visión más amplia para la empresa a la hora de establecer nichos de mercado, definir metas o enfocarse en algún aspecto particular de la venta de viviendas. Aunque este análisis se puede potenciar aún más, la forma presentada en este informe ya proporciona una gran claridad sobre las viviendas que están en oferta y sus características más notables segmentadas.
Finalmente, el análisis de correspondencias, aunque simple, se ve algo limitado al trabajar solo con dos variables y puede no ser tan viable si el número de categorías es excesivamente alto. Sin embargo, muestra relaciones entre variables categóricas que no siempre son fáciles de ver, evidenciando qué categorías se relacionan más con otras. Esto ayuda en el análisis de viviendas al responder preguntas muy específicas sobre lo que se desea saber en función de estas variables.
El análisis permite identificar rápidamente tanto viviendas céntricas como excéntricas. Por lo tanto, enfocarse en un nicho de mercado específico con una estrategia clara puede marcar una diferencia significativa en la obtención de resultados de venta.
Existen viviendas con características muy particulares, como tener pocas habitaciones o baños, entre otras. Se debería considerar si el objetivo es vender a personas solteras, casadas o con mascotas para definir adecuadamente el nicho al que se quiere apuntar. De esta manera, se pueden ofrecer viviendas que satisfagan un conjunto general de necesidades, tanto en términos de infraestructura como de ubicación.
Finalmente, existen viviendas de estrato medio con excelente infraestructura. Es posible que estas viviendas generen una alta rentabilidad, ya que se pueden adquirir a un buen precio y luego venderlas por un valor superior. Sin embargo, es importante visitar dichas viviendas, ya que el espacio podría no estar completamente terminado, lo que podría incurrir en gastos adicionales.
# Cargamos el shapefile con raster::shapefile()
shp_bcali <- shapefile('C:/Users/Andre/OneDrive/Documentos/COMPU_IEI/1_JAVERIANA_IEI/0_PROYECTOS AÑOS ANTERIORES JAVERIANA/PROPUESTA BARRIOS VEREDAS/PROPUESTA_BARRIOS_MANZANAS/_shp/BarriosCali84.shp')
# Convertimos a sf
shp_bcali_sf <- st_as_sf(shp_bcali)
# Se cargan las coordenadas
vivienda_sf <- st_as_sf(na.omit(vivienda), coords = c("longitud", "latitud"), crs = 4326)
# Se hace el plot
ggplot() +
geom_sf(data = shp_bcali_sf, fill = "white") +
geom_sf(data = vivienda_sf, aes(color = tipo), size = 1) +
theme_minimal() +
labs(title = "Barrios", x = "Longitud", y = "Latitud", color = "Tipo de vivienda")
El mapa muestra la distribución de las diferentes viviendas, ubicadas en la ciudad de interés según su tipo.
# Agregamos las columnas de latitud y longitud a vivienda_new
vivienda_new$latitud <- vivienda$latitud[match(rownames(vivienda_new), rownames(vivienda))]
vivienda_new$longitud <- vivienda$longitud[match(rownames(vivienda_new), rownames(vivienda))]
# Agregamos los conglomerados a vivienda_new
vivienda_new$cluster <- res.HCPC$data.clust$clust
# Asumiendo que 'vivienda' es tu dataframe y que tiene las columnas 'latitud', 'longitud' y 'tipo'
vivienda_sf <- st_as_sf(na.omit(vivienda_new), coords = c("longitud", "latitud"), crs = 4326)
# Hacemos el plot
ggplot() +
geom_sf(data = shp_bcali_sf, fill = "white") +
geom_sf(data = vivienda_sf, aes(color = as.factor(estrato)), size = 1) +
theme_minimal() +
labs(title = "Barrios", x = "Longitud", y = "Latitud", color = "Estratos de vivienda")
El mapa muestra la distribución espacial de las viviendas en la ciudad de interés según el estrato socioeconómico
# Asumiendo que 'vivienda' es tu dataframe y que tiene las columnas 'latitud', 'longitud' y 'tipo'
vivienda_sf <- st_as_sf(na.omit(vivienda_new), coords = c("longitud", "latitud"), crs = 4326)
# Hacemos el plot
ggplot() +
geom_sf(data = shp_bcali_sf, fill = "white") +
geom_sf(data = vivienda_sf, aes(color = cluster), size = 1) +
theme_minimal() +
labs(title = "Barrios", x = "Longitud", y = "Latitud", color = "Clusters de Vivienda")
Finalmente, se anexa un mapa que evidencia la distribución espacial de las viviendas según la clusterización realizada en el análisis de componentes principales PCA.