Como primer punto será necesario la utilización de 2 librerías:
factoextra es un paquete de R diseñado para extraer y
visualizar los resultados de análisis de datos multivariados,
especialmente aquellos que involucran técnicas de reducción de
dimensionalidad y agrupamiento.FactoMineR, que proporciona funciones para realizar
análisis de componentes principales (PCA), análisis factorial y
más.factoextra, puedes crear visualizaciones
informativas, como gráficos de dispersión, biplots y varios tipos de
mapas de factores, que permiten comprender la estructura de tus datos
después de aplicar algoritmos de reducción de dimensionalidad o
agrupamiento.dplyr es un paquete fundamental para la manipulación y
transformación de datos en R.En resumen, factoextra se enfoca principalmente en
extraer y visualizar resultados de análisis de reducción de
dimensionalidad y agrupamiento, mientras que dplyr se
enfoca en tareas de manipulación y transformación de datos.
## Loading required package: ggplot2
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
Habiendo realizado la instalación de las librerías, será necesario guardar los datos a analizar en una variable para comenzar a trabajar con ella, una vez hecho esto podemos observar los primeros 5 registros de nuestros datos de la siguiente manera:
## id zona piso estrato preciom areaconst parquea banios habitac
## 1 8312 Zona Oeste 4 6 1300 318 2 4 2
## 2 8311 Zona Oeste 1 6 480 300 1 4 4
## 3 8307 Zona Oeste NA 5 1200 800 4 7 5
## 4 8296 Zona Sur 2 3 220 150 1 2 4
## 5 8297 Zona Oeste NA 5 330 112 2 4 3
## tipo barrio longitud latitud
## 1 Apartamento arboleda -76576 3454
## 2 Casa normandía -76571 3454
## 3 Casa miraflores -76568 3455
## 4 Casa el guabal -76565 3417
## 5 Casa bella suiza alta -76565 3408
Ahora observamos el tipo de dato y la cantidad de valores faltantes de cada columna.
## '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 ...
## id zona piso estrato preciom areaconst parquea banios
## 3 3 2638 3 2 3 1605 3
## habitac tipo barrio longitud latitud
## 3 3 3 3 3
Borramos las columnas ID (ya que se trata únicamente de un número identificador de cada registro por lo que no será utilizado en el análisis). Eliminamos las columnas Barrio, Longitud y Latitud debido a que estaremos utilizando la columna Zona, la cual nos brindará la misma información de manera generalizada. Borramos algunas columnas como Piso y Parqueadero debido a que contienen muchos valores faltantes.
borrar <- c("id","barrio","latitud","longitud","piso","parquea")
vivienda <- my_data[ ,!(names(my_data) %in% borrar)]
colSums(is.na(vivienda))
## zona estrato preciom areaconst banios habitac tipo
## 3 3 2 3 3 3 3
Luego de realizar estos pasos, podemos observar que aún existen missings en nuestros datos.Por lo que es necesario borrar las filas que contienen registros con missings:
vivienda <- vivienda[complete.cases(vivienda),]
colSums(is.na(vivienda))
## zona estrato preciom areaconst banios habitac tipo
## 0 0 0 0 0 0 0
Ahora podemos ver que no existen datos faltantes. Para realizar el primer paso de éste análisis, emplearemos un análisis de componentes principales.
El Análisis de Componentes Principales (PCA, por sus siglas en inglés) es una técnica de análisis multivariado utilizada en estadísticas y ciencia de datos para reducir la dimensionalidad de conjuntos de datos complejos, manteniendo al mismo tiempo la mayor parte de la variabilidad presente en los datos originales. PCA se utiliza principalmente para simplificar la estructura de datos de alta dimensionalidad al transformar las variables originales en un nuevo conjunto de variables no correlacionadas llamadas componentes principales. El objetivo principal del PCA es encontrar un conjunto de componentes principales que sean combinaciones lineales de las variables originales y que expliquen la mayor cantidad posible de variabilidad en los datos. Los componentes principales están ordenados en función de la cantidad de varianza que explican, y el primer componente principal captura la mayor parte de la varianza total.
El Análisis de Componente Principales sólo es aplicable en variables numéricas, realizando una exploración de nuestros datos podemos encontrar que actualmente no todos nuestros datos son de tipo numérico.
str(vivienda)
## 'data.frame': 8319 obs. of 7 variables:
## $ zona : chr "Zona Oeste" "Zona Oeste" "Zona Oeste" "Zona Sur" ...
## $ 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 ...
## $ tipo : chr "Apartamento" "Casa" "Casa" "Casa" ...
Por lo cual, será necesario implementar una mutación de datos.
# Realizamos un remplazo de los valores del campo Zona mediante la función mutate
vivienda <- vivienda %>% mutate(zona = replace(zona,
zona == "Zona Centro", 1))
vivienda <- vivienda %>% mutate(zona = replace(zona,
zona == "Zona Norte", 2))
vivienda <- vivienda %>% mutate(zona = replace(zona,
zona == "Zona Oeste", 3))
vivienda <- vivienda %>% mutate(zona = replace(zona,
zona == "Zona Oriente",
4))
vivienda <- vivienda %>% mutate(zona = replace(zona,
zona == "Zona Sur", 5))
vivienda$zona <- as.numeric(vivienda$zona)
# Realizamos un remplazo de los valores del campo Tipo mediante la función mutate
vivienda <- vivienda %>% mutate(tipo = replace(tipo,
tipo == "Casa", 1))
vivienda <- vivienda %>% mutate(tipo = replace(tipo,
tipo == "Apartamento", 2))
vivienda$tipo <- as.numeric(vivienda$tipo)
## Warning: NAs introduced by coercion
Ahora todas nuestras variables son de tipo numérico, sin embargo, tenemos algunos missings en las columnas Zona y Tipo.
str(vivienda)
## 'data.frame': 8319 obs. of 7 variables:
## $ zona : num 3 3 3 5 3 5 5 3 5 5 ...
## $ 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 ...
## $ tipo : num 2 1 1 1 1 1 2 2 2 2 ...
Procedemos a quitarlos del dataset.
vivienda <- vivienda[complete.cases(vivienda),]
#revisamos cuántos valores NA existen actualmente
colSums(is.na(vivienda))
## zona estrato preciom areaconst banios habitac tipo
## 0 0 0 0 0 0 0
Observamos la cantidad de filas que obtuvimos del preprocesamiento
## [1] 8219
Detallamos la correlación de las variables:
correlacion <- round(cor(vivienda), 1)
correlacion
## zona estrato preciom areaconst banios habitac tipo
## zona 1.0 0.1 0.0 0.0 0.1 0.0 -0.1
## estrato 0.1 1.0 0.6 0.3 0.4 -0.1 0.1
## preciom 0.0 0.6 1.0 0.7 0.7 0.3 -0.3
## areaconst 0.0 0.3 0.7 1.0 0.6 0.5 -0.5
## banios 0.1 0.4 0.7 0.6 1.0 0.6 -0.4
## habitac 0.0 -0.1 0.3 0.5 0.6 1.0 -0.5
## tipo -0.1 0.1 -0.3 -0.5 -0.4 -0.5 1.0
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.3'
## (as 'lib' is unspecified)
## corrplot 0.92 loaded
Hallamos la matriz de correlación
install.packages("Hmisc")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.3'
## (as 'lib' is unspecified)
library("Hmisc")
##
## Attaching package: 'Hmisc'
## The following objects are masked from 'package:dplyr':
##
## src, summarize
## The following objects are masked from 'package:base':
##
## format.pval, units
res2 <- rcorr(as.matrix(correlacion))
res2
## zona estrato preciom areaconst banios habitac tipo
## zona 1.00 -0.18 -0.30 -0.24 -0.18 -0.16 -0.10
## estrato -0.18 1.00 0.60 0.24 0.28 -0.27 -0.01
## preciom -0.30 0.60 1.00 0.88 0.86 0.51 -0.70
## areaconst -0.24 0.24 0.88 1.00 0.88 0.75 -0.89
## banios -0.18 0.28 0.86 0.88 1.00 0.80 -0.88
## habitac -0.16 -0.27 0.51 0.75 0.80 1.00 -0.88
## tipo -0.10 -0.01 -0.70 -0.89 -0.88 -0.88 1.00
##
## n= 7
##
##
## P
## zona estrato preciom areaconst banios habitac tipo
## zona 0.7061 0.5092 0.6059 0.6919 0.7295 0.8321
## estrato 0.7061 0.1554 0.5969 0.5461 0.5602 0.9856
## preciom 0.5092 0.1554 0.0092 0.0123 0.2460 0.0774
## areaconst 0.6059 0.5969 0.0092 0.0091 0.0498 0.0072
## banios 0.6919 0.5461 0.0123 0.0091 0.0301 0.0096
## habitac 0.7295 0.5602 0.2460 0.0498 0.0301 0.0083
## tipo 0.8321 0.9856 0.0774 0.0072 0.0096 0.0083
Podemos observar un resultado más detallado en el siguiente gráfico de la matriz de correlación:
Observamos que el area construida y cantidad de baños está mucho más
correlacionado positivamente al precio de las viviendas.
Luego de estandarizar nuestros datos para que las variables no dominen de acuerdo a sus escalas y de hallar la matriz de correlación de las variables originales para entender cómo están relacionadas entre sí, procedemos a realizar el cálculo del análisis de componentes principales.
PCA <- prcomp(vivienda, scale = TRUE, center = TRUE)
Del siguiente gráfico podemos deducir que las componentes más contribuyentes son PC1, PC2, PC3, PC4 en ese orden.
plot(PCA, type = "l")
print(PCA)
## Standard deviations (1, .., p=7):
## [1] 1.7966656 1.2153838 1.0025429 0.7174243 0.5890131 0.4916427 0.4317360
##
## Rotation (n x k) = (7 x 7):
## PC1 PC2 PC3 PC4 PC5
## zona 0.04484504 -0.09953272 0.983041650 0.03400220 -0.13999773
## estrato 0.24636645 -0.66798737 0.003434856 -0.07494024 0.48877321
## preciom 0.44854765 -0.35366216 -0.125583203 0.19263157 -0.27874190
## areaconst 0.48453661 0.05572751 -0.086561067 0.33947781 -0.53964330
## banios 0.49081807 -0.05338208 0.012663948 -0.37941931 0.18096051
## habitac 0.37412255 0.43499464 0.039949480 -0.63274923 -0.04832285
## tipo -0.34706154 -0.47289920 -0.092720120 -0.54455955 -0.58095408
## PC6 PC7
## zona 0.013160504 0.02797432
## estrato -0.481703150 -0.12857463
## preciom 0.218251540 0.70393127
## areaconst -0.293886855 -0.51166038
## banios 0.666107692 -0.36835095
## habitac -0.435974078 0.27647050
## tipo 0.003578401 -0.11511760
Con la función summary podemos obtener más detalle del PCA
summary(PCA)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 1.7967 1.2154 1.0025 0.71742 0.58901 0.49164 0.43174
## Proportion of Variance 0.4611 0.2110 0.1436 0.07353 0.04956 0.03453 0.02663
## Cumulative Proportion 0.4611 0.6722 0.8157 0.88928 0.93884 0.97337 1.00000
En el contexto del Análisis de Componentes Principales (PCA), “Desviación Estándar” (Standard Deviation), “Proporción de Varianza” (Proportion of Variance) y “Proporción Acumulada” (Cumulative Proportion) son conceptos importantes que te ayudan a comprender la importancia de cada componente principal y la cantidad de información retenida al reducir la dimensionalidad de tus datos.
Desviación Estándar:
La desviación estándar mide la dispersión o la extensión de un conjunto de datos alrededor del valor medio (promedio). En PCA, la desviación estándar de un componente principal indica cuánta variación o “extensión” existe en los datos proyectados en ese componente. Una desviación estándar más alta para un componente implica que los puntos de datos tienen un rango más amplio cuando se proyectan en ese componente, lo que sugiere que captura más información de los datos originales.
Proporción de Varianza:
La proporción de varianza explica cuánta de la varianza total en los datos originales es capturada por un componente principal específico. Se calcula dividiendo la varianza de un componente principal específico entre la varianza total de todas las variables originales. Una proporción de varianza más alta para un componente indica que retiene una cantidad mayor de información de los datos originales.
Proporción Acumulada:
La proporción acumulada es la suma de las proporciones de varianza de los componentes principales que vienen antes de un componente específico. Representa la cantidad acumulativa de varianza explicada a medida que consideras más y más componentes principales en orden. Una proporción acumulada más alta indica cuánta de la variabilidad total se captura al incluir cierto número de componentes principales. Esto es especialmente útil para decidir cuántos componentes principales retener. Una práctica común es retener suficientes componentes para capturar una parte significativa de la varianza total (por ejemplo, 95% o 99%). En resumen, estos conceptos te ayudan a evaluar la importancia de cada componente principal en términos de la información que contiene. Al realizar un PCA, a menudo se elige retener cierto número de componentes principales en función de su proporción de varianza y proporción acumulada. Esto te permite reducir la dimensionalidad de tus datos mientras preservas una porción sustancial de la variabilidad de los datos originales.
Para detallar un poco más la información que nos proporcionan las componentes principales, estudiamos las PC1 y PC2:
#creamos un nuevo dataset
vivienda_2 <- vivienda
pc1 <- apply(PCA$rotation[,1]*vivienda_2,1,sum)
pc2 <- apply(PCA$rotation[,2]*vivienda_2,1,sum)
vivienda_2$pc1 <- pc1
vivienda_2$pc2 <- pc2
head(vivienda_2)
## zona estrato preciom areaconst banios habitac tipo pc1 pc2
## 1 3 6 1300 318 4 2 2 740.82472 -446.635321
## 2 3 6 480 300 4 4 1 383.40647 6.357497
## 3 3 5 1200 800 7 5 1 890.08921 278.678922
## 4 5 3 220 150 2 4 1 35.66657 21.657755
## 5 3 5 330 112 4 3 1 -103.34895 -168.866781
## 6 5 5 1350 390 10 10 1 166.58068 -398.106492
#PCA SCORE
pca_scores <- data.frame(PC1 = pc1, PC2 = pc2)
ggplot(pca_scores, aes(x = PC1, y = PC2)) +
geom_point() +
labs(x = "PC1", y = "PC2", title = "PCA Scatter Plot")
# Hallamos la proporción de varianza explicada para cada componente
variance_explained <- PCA$sdev^2 / sum(PCA$sdev^2)
# Imprimimos la varianza explicada
print(variance_explained)
## [1] 0.46114392 0.21102255 0.14358460 0.07352823 0.04956235 0.03453036 0.02662800
#Graficamos la varianza explicada
plot(variance_explained, type = "b", xlab = "Principal Component", ylab = "Variance Explained",
main = "Scree Plot de varianza explicada para cada componente")
# Cumulative variance explained plot
cumulative_variance <- cumsum(variance_explained)
plot(cumulative_variance, type = "b", xlab = "Number of Principal Components", ylab = "Cumulative Variance Explained",
main = "Cumulative Variance Explained")
# Biplot visualization
biplot(PCA, scale = 0)
fviz_screeplot(PCA, addlabels = TRUE, ylim = c(0, 100))
fviz_contrib(PCA, choice = "var", axes = 1, top = 10) # Dim1
fviz_contrib(PCA, choice = "var", axes = 2, top = 10) # Dim2
Cabe resaltar que en la gráfica Biplot no se logra detallar mayor información debido a que se está tomando todos y cada uno de los registros así como las variables del dataset. Sin embargo, se logra apreciar la distribución de las variables estudiadas.
Mediante el scree plot de nuestro PCA podemos observar que la componente principal con mayor varianza explicada es PC1. La varianza explicada ayuda a comprender cuánta información se conserva al considerar cada componente. Es decir, el componente principal captura el 46% de la información presente en los datos.Esto significa que al considerar solo este componente principal, estaríamos reteniendo el 46% de la variación total que estaba presente en las variables originales.
Es decir, que al considerar las primeras cuatro componentes principales estamos capturando el 89% de la variación total de las variables originales.
Ahora bien, teniendo en cuenta las dimensiones 1 y 2, podemos deducir que las variables que nos dan información de la cantidad de baños, área construida, precio y cantidad de habitaciónes son las que tienen mayor influencia en esa dimensión, y por lo tanto, tendrán más influencia sobre los registros de viviendas que se ubiquen en esa dimensión, por otra parte, las variables estrato, tipo y cantidad de habitaciones llevan la delantera a nivel de influencia en la dimensión 2.
Esto nos podría indicar que la cantidad de habitaciones posiblemente sea influyente para predecir el precio de una vivienda, ya que esta variable es influyente en dos dimensiones.
Pasamos a la clusterización.
Los métodos Elbow, Silhouette o Gap_stat nos ayudan a calcular la cantidad de clusters que son necesarios para agrupar nuestros datos en segmentos homogéneos, sin embargo, podemos detallar en las siguientes gráficas cómo quedarían clusterizados los datos para una cantidad de clusters: 2,3 y 4.
df_clusters <- vivienda
k2 <- kmeans(df_clusters, centers = 2, nstart = 25)
#plotear los cluster
fviz_cluster(k2, data = df_clusters)
fviz_cluster(k2, data = df_clusters, ellipse.type = "euclid",repel = FALSE,star.plot = TRUE) #ellipse.type= "t", "norm", "euclid"
fviz_cluster(k2, data = df_clusters, ellipse.type = "norm")
fviz_cluster(k2, data = df_clusters, ellipse.type = "norm",palette = "Set2", ggtheme = theme_minimal())
vivienda_clusters <- df_clusters
# Agregamos los resultados del clustering al conjunto de datos original
vivienda_clusters$cluster <- as.factor(k2$cluster)
# Visualizamos la distribución de las viviendas en cada clúster
table(vivienda_clusters$cluster)
##
## 1 2
## 1390 6829
# 3 clusters
k3 <- kmeans(df_clusters, centers = 3, nstart = 25)
#plotear los cluster
fviz_cluster(k3, data = df_clusters)
fviz_cluster(k3, data = df_clusters, ellipse.type = "euclid",repel = FALSE,star.plot = TRUE) #ellipse.type= "t", "norm", "euclid"
fviz_cluster(k3, data = df_clusters, ellipse.type = "norm")
fviz_cluster(k3, data = df_clusters, ellipse.type = "norm",palette = "Set2", ggtheme = theme_minimal())
vivienda_clusters_3 <- df_clusters
# Agregamos los resultados del clustering al conjunto de datos original
vivienda_clusters_3$cluster <- as.factor(k2$cluster)
# 4 clusters
k4 <- kmeans(df_clusters, centers = 4, nstart = 25)
#plotear los cluster
fviz_cluster(k4, data = df_clusters)
fviz_cluster(k4, data = df_clusters, ellipse.type = "euclid",repel = FALSE,star.plot = TRUE) #ellipse.type= "t", "norm", "euclid"
fviz_cluster(k4, data = df_clusters, ellipse.type = "norm")
fviz_cluster(k4, data = df_clusters, ellipse.type = "norm",palette = "Set2", ggtheme = theme_minimal())
vivienda_clusters_4 <- df_clusters
# Agregamos los resultados del clustering al conjunto de datos original
vivienda_clusters_4$cluster <- as.factor(k2$cluster)
Podemos observar cómo hemos obtenido una agrupación más homogénea con un número de clusters igual a 2.
Ahora para aplicar un dendograma sería necesario tener mucho menos cantidad de datos, ya que es necesario tener únicamente cientos de datos. Nuestro dataset tiene poco más de ocho mil registros.
Ahora realizamos un análisis de correspondencia entre las variables categóricas y numéricas de nuestro dataset.
El Análisis de Correspondencia es similar al Análisis de Componentes Principales (PCA), pero en lugar de trabajar con variables numéricas, se aplica a variables categóricas. Esta técnica busca encontrar patrones de asociación y dependencia entre categorías en las variables categóricas y las representa en un espacio de menor dimensionalidad.
library(dplyr)
library(mice)
##
## Attaching package: 'mice'
## The following object is masked from 'package:stats':
##
## filter
## The following objects are masked from 'package:base':
##
## cbind, rbind
library(FactoMineR)
library(factoextra)
vivienda_3 <- sample_n(my_data, 4000)
# Crear una tabla de contingencia para las variables categóricas
tabla <- table(vivienda_3$zona, vivienda_3$estrato)
# Mostrar la tabla cruzada Zona vs. Estrato
print(tabla)
##
## 3 4 5 6
## Zona Centro 56 3 1 1
## Zona Norte 278 176 364 92
## Zona Oeste 28 40 131 375
## Zona Oriente 143 3 1 0
## Zona Sur 203 808 793 502
resultados_ac <- CA(tabla)
valores_prop <- resultados_ac$eig
# Gráfica ScreePlot
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80)) +
ggtitle("Scree Plot del Análisis de Correspondencia Zona vs. Estrato") +
ylab("Porcentaje de Varianza Explicado") +
xlab("Ejes")
Mediante los gráficos anteriormente presentados podemos observar la correlación entre las variables estudiadas y cómo claramente se observa una correlación en cuanto a la zona y estrato de las viviendas. Además de que en la zona sur y oeste se encuentran las viviendas con mayor estrato en general.
Este análisis sin duda apoyará la gestión de compra, venta y valoración de viviendas por parte de la inmobiliaria.