Se deben instalar los siguientes paquetes, una sola vez.
#install.packages('dplyr')
#install.packages("cluster")
#install.packages("FactoMineR")
#install.packages("learnr")
#install.packages("devtools")
#install.packages("factoextra")
#install.packages("devtools")
library(dplyr)
library(paqueteMODELOS)
library(stats)
library(FactoMineR)
library(factoextra)
library(cluster)
library(ggplot2)
data("vivienda")
head(vivienda)
Iniciaremos el analisis con una revision de los datos y limpieza de los mismos.
dim(vivienda)
## [1] 8322 13
Contamos con 8322 filas y 13 variables o columnas.
colSums(is.na(vivienda))
## 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
Expresamos los faltantes en terminos de porcentaje
porcentaje_faltantes <- function(x) {sum(is.na(x)) / length(x)*100}
apply(vivienda, 2, porcentaje_faltantes)
## id zona piso estrato preciom areaconst
## 0.03604903 0.03604903 31.69911079 0.03604903 0.02403268 0.03604903
## parqueaderos banios habitaciones tipo barrio longitud
## 19.28622927 0.03604903 0.03604903 0.03604903 0.03604903 0.03604903
## latitud
## 0.03604903
Encontramos que hay dos variables importantes (piso y parqueaderos) con el 31 y 19% de faltantes respectivamente,estos valores se reemplazaran por cero, teniendo en cuenta que puede darse el caso que una casa o apartamento no tenga esta caracteristica, es preferibles asumir que no tiene.
Antes de eso eliminaremos las columnas de id, barrio, longitud y latitud, para el presente ejercicio no aportan información de valor.
quitar <- c("id","barrio","longitud", "latitud")
vivienda <- vivienda[ ,!(names(vivienda) %in% quitar)]
dim(vivienda)
## [1] 8322 9
Ahora contamos con 9 variables, identificadas asi:
zona: Variable categórica nominal.
estrato: Variable categórica ordinal.
tipo (Tipo de vivienda): Variable categórica nominal.
piso: Variable cuantitativa discreta.
preciom (Precio): Variable cuantitativa continua.
areaconst (Área construida): Variable cuantitativa continua.
parquea (Número de parqueaderos): Variable cuantitativa discreta.
banios (Número de Baños): Variable cuantitativa discreta.
habitac (Número de Habitaciones): Variable cuantitativa discreta.
Hasta el momento identificamos que en la matriz tenemos 9 variables con 8322 registros, contamos con valores nulos, principalmente en las variables de piso y parqueaderos.
Se identifica que los tres ultimos registros de la base de datos presentan principalmente el valor nulo en todas las variables, se procedera a eliminarlos e imputar las variables de piso y parqueadero.
# Eliminar registros donde la columna zona = "NA"
vivienda_clean <- subset(vivienda, zona != "NA")
# Reemplazar NA por 0 en la columna "parqueaderos"
vivienda_clean$parqueaderos <- ifelse(is.na(vivienda_clean$parqueaderos), 0, vivienda_clean$parqueaderos)
# Reemplazar NA por 0 en la columna "piso"
vivienda_clean$piso <- ifelse(is.na(vivienda_clean$piso), 0, vivienda_clean$piso)
# Convertimos la variable estrato a categorcia.
vivienda_clean$estrato <- as.character(vivienda_clean$estrato)
# Convertimos la variable piso a numerica
vivienda_clean$piso <- as.numeric(vivienda_clean$piso)
vivienda_clean
Mediante los graficos de histrogramas, revisamos como estan distribuidos los datos, si estan siguiente una distribucion normal, asi como sus extremos, nos brinda una visual amplia de la base de datos.
# Configurar el diseño del gráfico
par(mfrow = c(3, 2)) # 3 filas y 2 columnas para 6 histogramas
# Histogramas de frecuencia para la variable piso
hist(vivienda_clean$piso, main = "Pisos", xlab = "piso", ylab = "Piso",col = "#2F4F4F")
# Histogramas de frecuencia para la variable preciom
hist(vivienda_clean$preciom, main = "Precios", xlab = "preciom", ylab = "Cantidad",col = "#00868B")
# Histogramas de frecuencia para la variable areaconst
hist(vivienda_clean$areaconst, main = "Área_construida", xlab = "areaconst", ylab = "Mts2",col = "slateblue4")
# Histogramas de frecuencia para la variable parqueaderos
hist(vivienda_clean$parqueaderos, main = "Parqueaderos", xlab = "parqueaderos", ylab = "Cantidad",col = "deeppink3")
# Histogramas de frecuencia para la variable banios
hist(vivienda_clean$banios, main = "Baños", xlab = "banios", ylab = "cantidad",col = "#1E90FF")
# Histogramas de frecuencia para la variable habitaciones
hist(vivienda_clean$habitaciones, main = "Habitaciones", xlab = "habitaciones", ylab = "Cantidad",col = "#00CD00")
Ahora hacemos un analisis para las variables categoricas.
tiposvivienda = table(vivienda_clean$tipo, vivienda_clean$zona)
barplot(tiposvivienda, main="Tipos de viviendas disponibles por zona y tipos",
col=c("#0d3b66","#f4d35e"),
xlab="Cali",
ylab="Cantidad",
las=1, ylim = c(0,5000),
names.arg=c("Zona Centro","Zona Norte","Zona Oeste","Zona Oriente","Zona Sur"))
legend("topleft",
c("Apartamentos","Casas"),
fill = c("#0d3b66","#f4d35e"),
text.font = 7,
bg='#E5E7E9'
)
table(vivienda_clean$tipo, vivienda_clean$zona)
##
## Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
## Apartamento 24 1198 1029 62 2787
## Casa 100 722 169 289 1939
La Zona Sur es la que cuenta con mas propiedades disponibles para la venta, seguida de la Zona Norte, en ambas zonas se cuenta con mayor disponibilidad de viviendas tipo “Apartamento”.
Ahora por medio de una tabla, podemos analizar la relacion de los estratos de las viviendas en cada zona.
table(vivienda_clean$estrato, vivienda_clean$zona)
##
## Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
## 3 105 572 54 340 382
## 4 14 407 84 8 1616
## 5 4 769 290 2 1685
## 6 1 172 770 1 1043
Análisis de Componentes Principales: Reducir la dimensionalidad del conjunto de datos y visualizar la estructura de las variables en componentes principales para identificar características clave que influyen en la variación de precios y oferta del mercado.
Inciamos el analisis seleccionando las variables, normalizando el conjunto de datos para evitar que las diferencias de magnitudes entre las variables afecten los resultados ingresando sesgos y finalmente se aplica el PCA.
# Paso 1: Seleccionar las variables:
vars_pca <- vivienda_clean %>%
select(piso, preciom, areaconst, parqueaderos, banios, habitaciones)
# Paso 2: Normalizar el conjunto de datos
vars_pca_standardized <- scale(vars_pca)
# Paso 3: Aplicar el PCA
pca_result <- PCA(vars_pca_standardized, graph = FALSE)
# Explorar los resultados del PCA
summary(pca_result)
##
## Call:
## PCA(X = vars_pca_standardized, graph = FALSE)
##
##
## Eigenvalues
## Dim.1 Dim.2 Dim.3 Dim.4 Dim.5 Dim.6
## Variance 3.146 1.114 0.799 0.428 0.319 0.194
## % of var. 52.426 18.566 13.315 7.135 5.325 3.233
## Cumulative % of var. 52.426 70.992 84.307 91.442 96.767 100.000
##
## Individuals (the 10 first)
## Dist Dim.1 ctr cos2 Dim.2 ctr cos2 Dim.3
## 1 | 2.135 | -0.150 0.000 0.005 | -1.637 0.029 0.588 | 0.756
## 2 | 1.433 | -0.955 0.003 0.445 | -0.732 0.006 0.261 | -0.749
## 3 | 1.369 | -0.006 0.000 0.000 | -0.757 0.006 0.306 | -0.624
## 4 | 2.002 | 1.323 0.007 0.437 | 0.363 0.001 0.033 | -0.517
## 5 | 1.372 | -1.176 0.005 0.735 | -0.479 0.002 0.122 | -0.481
## 6 | 1.173 | -0.869 0.003 0.549 | -0.504 0.003 0.185 | -0.321
## 7 | 1.561 | -1.038 0.004 0.443 | -0.182 0.000 0.014 | -0.725
## 8 | 0.887 | -0.031 0.000 0.001 | -0.468 0.002 0.279 | -0.227
## 9 | 1.857 | 0.828 0.003 0.199 | -0.780 0.007 0.177 | 0.992
## 10 | 1.887 | 1.195 0.005 0.401 | 0.310 0.001 0.027 | -0.844
## ctr cos2
## 1 0.009 0.125 |
## 2 0.008 0.273 |
## 3 0.006 0.208 |
## 4 0.004 0.067 |
## 5 0.003 0.123 |
## 6 0.002 0.075 |
## 7 0.008 0.216 |
## 8 0.001 0.065 |
## 9 0.015 0.285 |
## 10 0.011 0.200 |
##
## Variables
## Dim.1 ctr cos2 Dim.2 ctr cos2 Dim.3 ctr
## piso | -0.159 0.800 0.025 | 0.822 60.699 0.676 | 0.539 36.357
## preciom | 0.842 22.520 0.708 | 0.264 6.278 0.070 | -0.243 7.390
## areaconst | 0.859 23.479 0.739 | -0.093 0.781 0.009 | -0.006 0.005
## parqueaderos | 0.714 16.218 0.510 | 0.399 14.279 0.159 | -0.310 12.020
## banios | 0.875 24.357 0.766 | -0.017 0.027 0.000 | 0.183 4.209
## habitaciones | 0.630 12.626 0.397 | -0.447 17.936 0.200 | 0.565 40.018
## cos2
## piso 0.290 |
## preciom 0.059 |
## areaconst 0.000 |
## parqueaderos 0.096 |
## banios 0.034 |
## habitaciones 0.320 |
# Paso 4: Visualizamos la proporción de varianza explicada por cada componente
fviz_eig(pca_result, addlabels = TRUE)
# Paso 5: Creamos el gráfico de círculo de correlación utilizando los resultados del PCA (pca_result)
circle_plot <- factoextra::fviz_pca_var(pca_result,
col.var = "contrib",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)
# Mostrar el gráfico de círculo de correlación
print(circle_plot)
En las graficas del analisis de componentes podemos identificar que las dos primeras componentes explican el 70.9% de la variabilidad del conjunto de datos, las variables baños, area construida, precio y parqueadero tienen una influencia principalmente en la dimension 1, lo que se podria entender como las caracteristicas mas valoradas por los posibles compradores, la variable pisos tiene una influencia mas definida sobre la dimension 2.
En la siguiente grafica podemos evidenciar lo observado anteriormente, analizando la contribucion de cada variable a la dimension 1 en terminos de porcentaje.
fviz_contrib(pca_result, choice = "var")
# Seleccionamos las variables numéricas para el análisis
variables_analisis <- vivienda_clean[, c('piso', 'preciom', 'areaconst', 'parqueaderos', 'banios', 'habitaciones')]
# Normalizamos los datos utilizando la función scale()
datos_normalizados <- scale(variables_analisis)
Análisis de Conglomerados: 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.
# Creamos una función para calcular la suma de los cuadrados internos (WCSS) para diferentes números de clústeres
calcular_wcss <- function(data, k_max) {
wcss <- vector("numeric", length = k_max)
for (k in 1:k_max) {
model <- kmeans(data, centers = k, nstart = 10)
wcss[k] <- model$tot.withinss
}
return(wcss)
}
# Aplicamos la función para diferentes números de clústeres
k_max <- 9
wcss_valores <- calcular_wcss(datos_normalizados, k_max)
# Graficamos la curva del codo para identificar el número óptimo de clústeres
plot(1:k_max, wcss_valores, type = "b", pch = 19, frame = FALSE, xlab = "Numero de clusteres", ylab = "Suma de cuadrados internos",col = "#5586B3")
Antes de aplicar el algoritmo K-Means, es fundamental definir el número adecuado de clústeres para segmentar las viviendas. Para lograr esto, se empleó el método del codo (Elbow Method), que nos ayuda a determinar el número óptimo de clústeres que captura la mayor parte de la varianza en los datos.
El método del codo se visualiza a través de un gráfico que muestra la Suma de Cuadrados Internos (WCSS) frente al número de clústeres. La WCSS es una métrica que cuantifica la variabilidad dentro de cada clúster. El objetivo es encontrar el “codo” en la gráfica, que representa el punto en el cual el aumento en el número de clústeres deja de disminuir significativamente la WCSS.
En el gráfico:
Al incrementar el número de clústeres, se observa una disminución inicial considerable en la WCSS. Esto ocurre porque con más clústeres, los puntos se agrupan más cerca de sus centros, reduciendo así la dispersión interna. Sin embargo, al seguir añadiendo clústeres, la reducción en la WCSS se vuelve cada vez menos pronunciada.
El “codo” en el gráfico es el punto en el que la disminución de la WCSS se vuelve más suave, formando una curva que se asemeja a un codo. Este punto es relevante porque indica que agregar más clústeres a partir de ese lugar no resulta en una reducción significativa de la dispersión interna. Por lo tanto, el “codo” señala un equilibrio entre la complejidad del modelo y su capacidad para explicar la variación en los datos.
En base al gráfico generado, se puede inferir que el número óptimo de clústeres se encuentra alrededor de 4 o 5. Después de este punto, la reducción en la WCSS se vuelve menos evidente, sugiriendo que agregar más clústeres no mejora de manera significativa el modelo.
# Definimos el número óptimo de clústeres (para nuestro análisis 4)
num_clusters <- 4
# Aplicamos el algoritmo K-Means
modelo_kmeans <- kmeans(datos_normalizados, centers = num_clusters, nstart = 10)
# Agregamos los resultados del clustering al conjunto de datos original
vivienda_clean$cluster <- as.factor(modelo_kmeans$cluster)
# Visualizamos la distribución de las viviendas en cada clúster
table(vivienda_clean$cluster)
##
## 1 2 3 4
## 1482 3738 921 2178
# Paleta de colores personalizada
colores_personalizados <- c("#F67C6D", "#1A7332", "#1C5A99", "#7466C3")
# Gráfico de barras para mostrar la distribución de viviendas en cada clúster
ggplot(vivienda_clean, aes(x = factor(cluster))) +
geom_bar(fill = colores_personalizados) +
labs(title = "Distribución de viviendas en cada clúster",
x = "Clúster",
y = "Cantidad de viviendas") +
theme_minimal() +
geom_text(stat='count', aes(label=..count..), vjust=-0.5)
El gráfico de barras representa la distribución de viviendas en cada clúster.
En el gráfico generado:
El eje x (horizontal) representa los diferentes clústeres en tu análisis.
El eje y (vertical) representa la cantidad de viviendas en cada clúster.
Cada barra en el gráfico representa un clúster específico y su altura muestra la cantidad de viviendas en ese clúster en particular, he agregado las etiquetas en la parte superior de cada barra con el fin de mostrar la cantidad exacta de viviendas en cada clúster y así obtener información cuantitativa adicional y facilitar la interpretación de los valores exactos.
# Tabla resumen de características promedio por clúster
tabla_resumen <- vivienda_clean %>%
group_by(cluster) %>%
summarise(promedio_preciom = mean(preciom),
promedio_areaconst = mean(areaconst),
promedio_parqueaderos = mean(parqueaderos),
promedio_banios = mean(banios),
promedio_habitaciones = mean(habitaciones))
# Mostrar tabla resumen
print(tabla_resumen)
## # A tibble: 4 × 6
## cluster promedio_preciom promedio_areaconst promedio_parqueaderos
## <fct> <dbl> <dbl> <dbl>
## 1 1 350. 106. 1.42
## 2 2 250. 99.5 0.892
## 3 3 1131. 419. 3.72
## 4 4 512. 248. 1.59
## # ℹ 2 more variables: promedio_banios <dbl>, promedio_habitaciones <dbl>
La tabla resumen permite comparar y contrastar las características promedio de las propiedades en diferentes clústeres. esta información se puede utilizar para Identificar patrones.
# Diagrama de dispersión para la relación entre 'preciom' y 'areaconst'
ggplot(vivienda_clean, aes(x = preciom, y = areaconst, color = factor(cluster))) +
geom_point() +
labs(title = "Relación entre precio y área construida por clúster",
x = "Precio",
y = "Área construida",
color = "Clúster") +
theme_minimal() +
theme(legend.position = "bottom")
Patrón general: Observando el gráfico, se puede identificar que existe un patrón general en la relación entre el precio y el área construida. los precios tienden a disminuir a medida que el área construida disminuye
Tendencias por clúster: Los colores de los puntos indican a qué clúster pertenece cada propiedad. Esto permite analizar que los cluster que tienen mayor cantidad de viviendas (Clúster 3738 viviendas y Clúster = 2176 Viviendas) son los que menor área construida tienen y por ende menores los precios de sus viviendas
Segmentación del mercado: Hay un segmentos de mercado con preferencias particulares en términos de relación entre precio y área construida y es que el Clúster = 921 viviendas que es el de menor cantidad de viviendas posee, es el que tiene viviendas con el máyor número de áreas construidas .
Outliers: si se observa la gráfica los puntos que están muy lejos de la tendencia general o outliers son aquellos puntos o propiedas cuyos precios son muy elevados y que están por encima del promedio .
Examinar la relación entre las variables categóricas (tipo de vivienda, zona y estrato) y las variables numéricas (precio, área construida, número de parqueaderos, baños, habitaciones) para identificar patrones de comportamiento del mercado inmobiliario.
# Creamos un nuevo dataframe solo con las variables categóricas
vivienda_categ <- vivienda_clean[, c("tipo", "zona", "estrato")]
# Realizamos el Análisis de Correspondencia Múltiple (MCA) para las variables categóricas
mca_result <- MCA(vivienda_categ)
El gráfico nos permite establecer relaciones y validarlas como son:
El estrato 6 se encuentra ubicado en la Zona Oeste Los estratos 4 y 5 están ubicados principalmente en la Zona Sur y Norte El estrato 3 está presente en las Zonas Oriente y Centro
fviz_screeplot(mca_result, addlabels = TRUE, ylim = c(0, 25))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
Los resultados indican que la primera componente resumen el 21.1% y los dos primeros ejes resumen un 38.1% de los datos.
Variables Cercanas: Las variables “zona” y “barrio” están próximas en la gráfica esto significa que tienen categorías que tienden a co-ocurrir o estar relacionadas la una de la otra en el conjunto de datos.
Variables Alejadas: La variable “tipo” se encuentra alejada entre sí en la gráfica, esto significa que tiene una categoría que es menos propensas a co-ocurrir. Esto podría señalar diferencias o segmentos distintos en el mercado inmobiliario.
El análisis exploratorio de los datos permitió identificar que la base de datos presentaba valores faltantes, principalmente en las variables de piso y parqueaderos, con un 31% y un 19% de datos faltantes, respectivamente. Estos valores fueron imputados con cero para asumir que las viviendas no cuentan con esas características y evitar introducir algún sesgo. También se identificó que las zonas sur y norte son las que cuentan con la mayor disponibilidad de viviendas para la venta, lo que podría sugerir a la empresa que la fuerza de ventas y marketing debería enfocarse en estas zonas.
En el análisis de componentes principales se evidencia que características como el precio, la cantidad de baños y el área son altamente valoradas por los clientes, seguidas por la disponibilidad de parqueadero y la cantidad de habitaciones.
Con el análisis de conglomerados, se observa una relación entre el área construida y el precio: a medida que el precio aumenta, se espera que el área también lo haga. Esta es una tendencia apreciada por los clientes y debería mantenerse en los productos ofertados.
Finalmente, en el análisis de correspondencia se observan asociaciones entre las zonas y el estrato. La zona oeste se relaciona con el estrato 6, los estratos 4 y 5 con la zona norte, y el estrato 3 con las zonas centro y oriente.