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.
## 'data.frame': 8322 obs. of 13 variables:
## $ id : int 8312 8311 8307 8296 8297 8298 8299 8300 8286 8287 ...
## $ zona : chr "Zona Oeste" "Zona Oeste" "Zona Oeste" "Zona Sur" ...
## $ piso : int 4 1 NA 2 NA NA 2 NA NA 2 ...
## $ estrato : int 6 6 5 3 5 5 6 5 5 5 ...
## $ preciom : int 1300 480 1200 220 330 1350 305 480 275 285 ...
## $ areaconst: num 318 300 800 150 112 390 125 280 74 120 ...
## $ parquea : int 2 1 4 1 2 8 2 4 1 2 ...
## $ banios : int 4 4 7 2 4 10 3 4 2 4 ...
## $ habitac : int 2 4 5 4 3 10 3 4 3 3 ...
## $ tipo : chr "Apartamento" "Casa" "Casa" "Casa" ...
## $ barrio : chr "arboleda" "normandía" "miraflores" "el guabal" ...
## $ longitud : num -76576 -76571 -76568 -76565 -76565 ...
## $ latitud : num 3454 3454 3455 3417 3408 ...
Hemos identificado la presencia de 7 variables de tipo entero, 3 de tipo numérico y 3 de tipo caracter en nuestros datos. En vista de esto, hemos decidido proceder con la eliminación de las variables “longitud”, “latitud” y “barrio”. Estas variables, que proporcionan detalles sobre la ubicación de la vivienda, no resultan esenciales debido a que es preferible obtener esta información de manera más fiable a través de la variable “zona”. Además, en nuestro análisis exploratorio, procederemos a transformar las variables “zona” y “tipo” en factores, lo cual nos permitirá adecuadamente representar su naturaleza categórica. En consecuencia, los datos serán presentados de la siguiente manera:
data <- subset(data, select = -c(barrio,longitud,latitud,id))
data[c("zona", "tipo")] <- lapply(data[c("zona", "tipo")], factor)
str (data)## 'data.frame': 8322 obs. of 9 variables:
## $ zona : Factor w/ 5 levels "Zona Centro",..: 3 3 3 5 3 5 5 3 5 5 ...
## $ piso : int 4 1 NA 2 NA NA 2 NA NA 2 ...
## $ estrato : int 6 6 5 3 5 5 6 5 5 5 ...
## $ preciom : int 1300 480 1200 220 330 1350 305 480 275 285 ...
## $ areaconst: num 318 300 800 150 112 390 125 280 74 120 ...
## $ parquea : int 2 1 4 1 2 8 2 4 1 2 ...
## $ banios : int 4 4 7 2 4 10 3 4 2 4 ...
## $ habitac : int 2 4 5 4 3 10 3 4 3 3 ...
## $ tipo : Factor w/ 6 levels "Apartamento",..: 1 5 5 5 5 5 1 1 1 1 ...
Ahora analizamos las variables categoricas “tipo” y “zona” para detectar inconsistencias en sus valores:
##
## Apartamento APARTAMENTO apto casa Casa CASA
## 5025 61 13 14 3194 12
##
## Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
## 124 1920 1198 351 4726
Como se ve en la variable “tipo” tenemos 6 categorias en la cual se deben resumir a solo dos, para hacer esto se uniran estas categorias en solo dos: “casa” y “apto”, en la cual quedara de la siguiente manera:
data$tipo <- ifelse(grepl("casa|CASA|Casa", data$tipo), "casa",
ifelse(grepl("apartamento|Apartamento|APARTAMENTO|apto", data$tipo), "apto", data$tipo))
table(data$tipo)##
## apto casa
## 5099 3220
## 'data.frame': 8322 obs. of 9 variables:
## $ zona : Factor w/ 5 levels "Zona Centro",..: 3 3 3 5 3 5 5 3 5 5 ...
## $ piso : int 4 1 NA 2 NA NA 2 NA NA 2 ...
## $ estrato : int 6 6 5 3 5 5 6 5 5 5 ...
## $ preciom : int 1300 480 1200 220 330 1350 305 480 275 285 ...
## $ areaconst: num 318 300 800 150 112 390 125 280 74 120 ...
## $ parquea : int 2 1 4 1 2 8 2 4 1 2 ...
## $ banios : int 4 4 7 2 4 10 3 4 2 4 ...
## $ habitac : int 2 4 5 4 3 10 3 4 3 3 ...
## $ tipo : Factor w/ 2 levels "apto","casa": 1 2 2 2 2 2 1 1 1 1 ...
## [,1]
## zona 3
## piso 2638
## estrato 3
## preciom 2
## areaconst 3
## parquea 1605
## banios 3
## habitac 3
## tipo 3
## 8320 8321 8322 12 14 22
## 9 9 8 2 2 2
Se observa que las ultimas 3 filas son en su mayoria Na, por lo cual se eliminaran.
Los datos finales despues de la exploración y limpieza son:
## 'data.frame': 8319 obs. of 9 variables:
## $ zona : Factor w/ 5 levels "Zona Centro",..: 3 3 3 5 3 5 5 3 5 5 ...
## $ piso : int 4 1 NA 2 NA NA 2 NA NA 2 ...
## $ estrato : int 6 6 5 3 5 5 6 5 5 5 ...
## $ preciom : int 1300 480 1200 220 330 1350 305 480 275 285 ...
## $ areaconst: num 318 300 800 150 112 390 125 280 74 120 ...
## $ parquea : int 2 1 4 1 2 8 2 4 1 2 ...
## $ banios : int 4 4 7 2 4 10 3 4 2 4 ...
## $ habitac : int 2 4 5 4 3 10 3 4 3 3 ...
## $ tipo : Factor w/ 2 levels "apto","casa": 1 2 2 2 2 2 1 1 1 1 ...
## [,1]
## zona 0
## piso 2635
## estrato 0
## preciom 0
## areaconst 0
## parquea 1602
## banios 0
## habitac 0
## tipo 0
Para realizar el análisis de componentes principales vamos a utilizar solo los valores numericos:
## 'data.frame': 4808 obs. of 7 variables:
## $ piso : int 4 1 2 2 2 1 6 2 8 6 ...
## $ estrato : int 6 6 3 6 5 5 6 5 6 6 ...
## $ preciom : int 1300 480 220 305 285 310 640 416 700 700 ...
## $ areaconst: num 318 300 150 125 120 166 157 98 123 240 ...
## $ parquea : int 2 1 1 2 2 2 2 1 2 2 ...
## $ banios : int 4 4 2 3 4 4 3 2 3 5 ...
## $ habitac : int 2 4 4 3 3 3 3 2 4 4 ...
## - attr(*, "na.action")= 'omit' Named int [1:3511] 3 5 6 8 9 12 14 17 19 20 ...
## ..- attr(*, "names")= chr [1:3511] "3" "5" "6" "8" ...
Ahora vamos a observar la correlación entre las variables:
Observamos que todas las variables mantienen una relación lineal significativa con el precio, excepto la variable “piso”. Esta última no muestra una conexión clara ni con las demás variables ni con el precio. Por lo tanto, en el análisis de componentes principales, optaremos por omitir la variable “piso”.
## 'data.frame': 4808 obs. of 6 variables:
## $ estrato : int 6 6 3 6 5 5 6 5 6 6 ...
## $ preciom : int 1300 480 220 305 285 310 640 416 700 700 ...
## $ areaconst: num 318 300 150 125 120 166 157 98 123 240 ...
## $ parquea : int 2 1 1 2 2 2 2 1 2 2 ...
## $ banios : int 4 4 2 3 4 4 3 2 3 5 ...
## $ habitac : int 2 4 4 3 3 3 3 2 4 4 ...
## - attr(*, "na.action")= 'omit' Named int [1:3511] 3 5 6 8 9 12 14 17 19 20 ...
## ..- attr(*, "names")= chr [1:3511] "3" "5" "6" "8" ...
Ahora procedemos a realizar el análisis de componentes principales:
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 3.5590750 59.317917 59.31792
## Dim.2 1.1845261 19.742101 79.06002
## Dim.3 0.4834367 8.057278 87.11730
## Dim.4 0.3425537 5.709228 92.82652
## Dim.5 0.2464845 4.108075 96.93460
## Dim.6 0.1839240 3.065400 100.00000
Como se puede apreciar, las dos primeras componentes pueden explicar aproximadamente el 79% de la variabilidad presente en la base de datos. La primera componente, por sí sola, es capaz de explicar más de la mitad de la variabilidad total de los datos (59%) .
fviz_pca_var(pca_result, col.var = "contrib", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), repel = TRUE)En el gráfico de correlación entre las variables, se observa claramente que la primera componente está fuertemente relacionada con el precio, la cantidad de plazas de estacionamiento, el número de baños y el tamaño construido de las viviendas. Estas variables muestran una correlación positiva, ya que están agrupadas de manera conjunta. Se destaca que un aumento en el número de espacios de estacionamiento se vincula con un incremento en el precio, así como un aumento en la cantidad de baños se asocia con un tamaño construido más grande en las viviendas. Por otro lado, la segunda componente presenta una relación más fuerte con el estrato y la cantidad de habitaciones.
fviz_pca_biplot(pca_result, repel = FALSE,
col.var = "#2E9FDF", # Variables color
col.ind = "#E7B800" # Individuals color
)
En el gráfico de individuos, se puede identificar un grupo amplio que se
encuentra en el centro y se extiende en dirección contraria a las
variables representadas en el gráfico. Esto sugiere que este conjunto de
viviendas exhibe valores reducidos en dichas variables.
Aquí observamos las variables que ejercen la mayor influencia en las primeras dos componentes:
En la primera componente, encontramos que el precio, los baños, el área y los parqueaderos tienen magnitudes similares en términos de influencia.
Por otro lado, en la segunda componente, solo dos variables influyen de manera significativa: el número de habitaciones y el estrato.
A partir del Análisis de Componentes Principales (ACP), se pueden extraer las siguientes conclusiones:
La primera componente explica el 59.3% de la variabilidad observada en los datos, mientras que la segunda componente explica el 19.7%. En conjunto, ambas componentes logran explicar aproximadamente el 79% de esta variabilidad. En otras palabras, estas dos componentes capturan la mayoría de la información contenida en las 6 variables originales.
Dentro de la primera componente, las variables que más contribuyen son, en orden, el precio de la vivienda, el número de baños, el área construida y la disponibilidad de parqueadero. En la segunda componente, las variables que predominan en términos de influencia son el número de habitaciones y el estrato. Es importante destacar que, de acuerdo con el análisis de la matriz de correlaciones inicial, las variables de mayor impacto en la primera componente están altamente correlacionadas entre sí. Esto sugiere que esta componente puede estar vinculada a variables que presentan relaciones fuertes.
Estas conclusiones resaltan la utilidad del ACP para reducir la dimensionalidad de los datos y obtener información relevante que puede ser aprovechada en análisis posteriores o en la construcción de modelos predictivos.
Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas y demandas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.
Para el análisis de conglomerados (Clustering), se toman las siguientes variables: estrato, preciom, areacons, banios, habitaciones y zona.
dataAC <- data[1:8319, c("estrato", "preciom", "areaconst", "banios", "habitac","zona")]
str(dataAC)## 'data.frame': 8319 obs. of 6 variables:
## $ estrato : int 6 6 5 3 5 5 6 5 5 5 ...
## $ preciom : int 1300 480 1200 220 330 1350 305 480 275 285 ...
## $ areaconst: num 318 300 800 150 112 390 125 280 74 120 ...
## $ banios : int 4 4 7 2 4 10 3 4 2 4 ...
## $ habitac : int 2 4 5 4 3 10 3 4 3 3 ...
## $ zona : Factor w/ 5 levels "Zona Centro",..: 3 3 3 5 3 5 5 3 5 5 ...
Dado que los rangos de las variables son diferentes y con fin de que estas diferencias en las dimensiones de las variables no afecte los cálculos de las distancias, se estandarizan las variables (media 0 y varianza 1) antes de generar los cálculos de las distancias.
Se va a utilizar un algoritmo de k-means para visualizar la formación de 2, 3 y 4 clusteres:
Por medio de los metodos de silhouette y Elbow vamos a mirar cuantos numeros de cluster nos recomienda:
Ahora procederemos a crear un diagrama de caja (boxplot) con el fin de analizar el comportamiento de los distintos clústeres entre 2 y 4. De esta manera, podremos evaluar cuál de ellos proporciona las conclusiones más significativas.
plot1 <-dataAC_N %>%
ggplot(aes(x=factor(k1$cluster), y=preciom, fill=factor(k1$cluster)))+
geom_boxplot()+geom_point()+xlab("Clusters")+ labs(fill="Clusters")
plot2 <-dataAC_N %>%
ggplot(aes(x=factor(k1$cluster), y=areaconst, fill=factor(k1$cluster)))+
geom_boxplot()+geom_point()+xlab("Clusters")+ labs(fill="Clusters")
plot3 <-dataAC_N %>%
ggplot(aes(x=factor(k1$cluster), y=banios, fill=factor(k1$cluster)))+
geom_boxplot()+geom_point()+xlab("Clusters")+ labs(fill="Clusters")
grid.arrange(plot1, plot2, plot3, ncol=3)
### Cluster = 3
plot1 <-dataAC_N %>%
ggplot(aes(x=factor(k2$cluster), y=preciom, fill=factor(k2$cluster)))+
geom_boxplot()+geom_point()+xlab("Clusters")+ labs(fill="Clusters")
plot2 <-dataAC_N %>%
ggplot(aes(x=factor(k2$cluster), y=areaconst, fill=factor(k2$cluster)))+
geom_boxplot()+geom_point()+xlab("Clusters")+ labs(fill="Clusters")
plot3 <-dataAC_N %>%
ggplot(aes(x=factor(k2$cluster), y=banios, fill=factor(k2$cluster)))+
geom_boxplot()+geom_point()+xlab("Clusters")+ labs(fill="Clusters")
grid.arrange(plot1, plot2, plot3, ncol=3)
### Cluster = 4
plot1 <-dataAC_N %>%
ggplot(aes(x=factor(k3$cluster), y=preciom, fill=factor(k3$cluster)))+
geom_boxplot()+geom_point()+xlab("Clusters")+ labs(fill="Clusters")
plot2 <-dataAC_N %>%
ggplot(aes(x=factor(k3$cluster), y=areaconst, fill=factor(k3$cluster)))+
geom_boxplot()+geom_point()+xlab("Clusters")+ labs(fill="Clusters")
plot3 <-dataAC_N %>%
ggplot(aes(x=factor(k3$cluster), y=banios, fill=factor(k3$cluster)))+
geom_boxplot()+geom_point()+xlab("Clusters")+ labs(fill="Clusters")
grid.arrange(plot1, plot2, plot3, ncol=3)Al analizar los diversos clústeres, se vuelve evidente que la diferenciación mas notable entre clusteres se encuentra cuando se divide en dos. Estos dos clústeres resaltan de manera clara las distinciones en los grupos: el primer clúster alberga viviendas de mayor precio, área y cantidad de baños, mientras que el segundo clúster está compuesto por viviendas de precio más bajo, menos baños y un área reducida.
Para comparar los resultados obtenidos con K-Means se emplea un método jerárquico de agrupación.
En este caso se utilizan las distacias euclidianas y se toma como criterio para ajustar el modelo jerarquico el método Ward de varianza mínima.
#calculamos la matriz de distancia
d <- dist(dataAC_N, method = "euclidean")
#Clustering jerarquico con ward
hc2 <- hclust(d,method = "ward.D")
# dendograma
plot(hc2, cex=0.6, hang=-1)Para seleccionar el número adecuado de clusters se emplea el coeficiente de Silhouette
k2_cluster <- cutree(hc2, k = 2) # Cluster
sil_1_k2 <- silhouette(k2_cluster, dist(dataAC_N))
sil_1_avg_k2 <- mean(sil_1_k2[,3])
cat("Coeficiente de Silhouette promedio k=2 : ", sil_1_avg_k2)## Coeficiente de Silhouette promedio k=2 : 0.1719297
k3_cluster <- cutree(hc2, k = 3) # Cluster
sil_1_k3 <- silhouette(k3_cluster, dist(dataAC_N))
sil_1_avg_k3 <- mean(sil_1_k3[,3])
cat("Coeficiente de Silhouette promedio k=3 : ", sil_1_avg_k3)## Coeficiente de Silhouette promedio k=3 : 0.2480213
k4_cluster <- cutree(hc2, k = 4) # Cluster
sil_1_k4 <- silhouette(k4_cluster, dist(dataAC_N))
sil_1_avg_k4 <- mean(sil_1_k4[,3])
cat("Coeficiente de Silhouette promedio k=4 : ", sil_1_avg_k4)## Coeficiente de Silhouette promedio k=4 : 0.2503797
Del análisis de conglomerados (clustering), se extraen las siguientes conclusiones:
Los resultados obtenidos mediante los métodos de agrupamiento jerárquico y no jerárquico revelan cantidades de clústeres diversas entre sí. No obstante, ambos métodos sugieren que el número de grupos no debería exceder k = 4. Esto puede indicar que la información disponible sobre las viviendas no es suficiente para identificar patrones o características adicionales que permitan la formación de clústeres con estructuras más específicas en lugar de generales.
En el caso del modelo K-Means, se logra establecer 2 grupos con características claramente definidas.
Por otro lado, el enfoque jerárquico arroja un coeficiente de Silhouette notablemente bajo, sugiriendo la creación de 4 clústeres a pesar de su limitada cohesión.
Los gráficos proporcionan respaldo a las evidencias encontradas mediante las métricas empleadas.
Es importante destacar que no se puede afirmar categóricamente que un modelo sea superior al otro. Aunque la comparación entre los modelos jerárquicos indica que la agrupación basada en el criterio “k-means” exhibe métricas más favorables que la agrupación según el método “Ward”, no se puede concluir de manera definitiva sobre la supremacía de uno sobre el otro.
Estos conjuntos de agrupaciones pueden ser aprovechados para llevar a cabo análisis estadísticos detallados dentro de cada grupo. Esto posibilitaría la identificación de características compartidas, patrones intrínsecos y diferencias entre clústeres similares. Además, se podría considerar la adopción de nuevas métricas y la inclusión de más datos en la tabla para generar clústeres con una estructura interna aún más refinada.
Inicialmente se contruye una tabla cruzada para las variables categóricas zona y estrato.
##
## 3 4 5 6
## 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
Se ejecuta la prueba Chi-Cuadrado para validar la independencia entre los datos.
##
## Pearson's Chi-squared test
##
## data: tabla
## X-squared = 3830.4, df = 12, p-value < 2.2e-16
La hipótesis nula para esta prueba es la independencia de la variables categóricas. El resultado indica que se rechaza la hipótesis de independencia de las variables (p-value: 0.0000), indicando un grado de relación entre ellas.
Ahora, se procede a realizar el análisis de correspondencia:
Por medio del análisis del plano se puede concluir lo siguiente:
Las viviendas que están en la zona Oeste son estrato 6. Las viviendas que están ubicadas en las zonas Norte y Sur son principalmente de estratos 4 y 5. Las viviendas que están ubicadas en las zonas Oriente y Centro son en su mayoría de estrato 3. Se realiza un gráfico para el porcentaje de varianza explicado por cada una de las componentes,
Se realiza un gráfico para el porcentaje de varianza explicado por cada una de las componentes,
fviz_screeplot(ac, addlabels = TRUE,
ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")Los resultados muestran que el primer componente resume el 70% del total de la varianza, mientras que los dos primeros componentes representados en el plano factorial de los dos ejes principales abarcan un 97.7% de los datos.
En este informe se presentan detalladamente los resultados del análisis realizado sobre una base de datos que contiene información sobre 8322 viviendas con diversas características y propiedades observadas. Esta información se distribuye en 12 variables, que incluyen elementos como zona, piso, estrato, precio, área de construcción, número de parqueaderos, cantidad de baños, número de habitaciones, tipo, barrio, longitud y latitud. Es importante destacar que la base de datos contiene tanto valores faltantes como nueve variables numéricas y tres variables de tipo texto.
En el análisis de componentes principales, se pudo determinar que el primer componente explica el 59.3% de la variabilidad presente en los datos. Al considerar los dos primeros componentes, se llega a una explicación del 75% de los datos (79). Esto sugiere que una sola variable (CP1), obtenida a través de una combinación lineal de las variables originales, puede capturar una gran parte de la variabilidad en la base de datos. Al graficar las variables en el plano de componentes principales, es posible identificar la dirección y características de los componentes. En este caso, el primer componente principal está asociado principalmente con las variables precio, baños, área y parqueaderos, mientras que el segundo componente se relaciona con habitaciones y estrato. Es evidente que un aumento en el número de espacios de estacionamiento se vincula con un incremento en el precio, al igual que un aumento en la cantidad de baños se relaciona con un mayor tamaño de construcción en las viviendas.
En el análisis de conglomerados, se seleccionaron las variables estrato, precio, área de construcción, baños, habitaciones y zona. Dado que las magnitudes de estas variables varían, se recomienda estandarizarlas previamente para evitar que las diferencias dimensionales afecten los cálculos de distancias. La elección del número óptimo de clústeres es subjetiva, pero se considera el criterio de la mayor diferencia en las distancias euclidianas entre nodos. Además, se utiliza el índice de Silhouette promedio para evaluar las alternativas de número de clústeres. Aunque los coeficientes obtenidos son en general bajos, el valor más favorable es k=4. Sin embargo, al realizar un boxplot de los diferentes clústeres, la heterogeneidad de estos no es clara, lo que sugiere que dividir los datos en dos clústeres proporciona una información más significativa.
En el análisis de correspondencia, se inicia construyendo una tabla cruzada de las variables involucradas, organizada según zona y estrato. Luego, a través de la prueba de chi-cuadrado, se generan dos matrices que servirán para crear coordenadas y representarlas en un plano cartesiano, lo que permitirá visualizar la cercanía o relación entre las categorías de ambas variables. Los resultados de la prueba de chi-cuadrado indican que se rechaza la hipótesis de independencia entre las variables, sugiriendo una relación entre ellas. Finalmente, se procede con el análisis de correspondencia, donde se estiman las coordenadas para cada nivel de las variables y se representan en un plano cartesiano. A través de este gráfico, se pueden establecer relaciones y validaciones: el estrato 6 se ubica en la Zona Oeste, los estratos 4 y 5 predominan en las Zonas Sur y Norte, mientras que el estrato 3 se distribuye en las Zonas Oriente y Centro. Estos resultados indican una relación fuerte y sugieren zonas en función del estrato. Respecto a las categorías de las variables zona y estrato, se concluye que la primera componente resume el 70% del total de la varianza y los dos primeros componentes en el plano factorial abarcan el 97.7% de los datos.