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.
Retos:
El reto principal consisten en realizar un análisis integral y multidimensional de la base de datos para obtener una comprensión del mercado inmobiliario urbano. Se requiere aplicar diversas técnicas de análisis de datos, incluyendo:
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 preferencias del mercado.
Análisis de Conglomerados: 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.
Análisis de Correspondencia : Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio) y las variables numéricas (precio, área construida, número de parqueaderos, baños, habitaciones) para identificar patrones de comportamiento del mercado inmobiliario.
Visualización de resultados: Presentar gráficos, mapas y otros recursos visuales para comunicar los hallazgos de manera clara y efectiva a la dirección de la empresa.
Empecemos,
Carga de datos con los cuales se van a trabajar
#install.packages("learnr") # solo una vez
#install.packages("devtools") # solo una vez
devtools::install_github("dgonxalex80/paqueteMOD") #descarga paquete
## Skipping install of 'paqueteDAT' from a github remote, the SHA1 (f93b7506) has not changed since last install.
## Use `force = TRUE` to force installation
#install.packages("paqueteMET")
library(paqueteDAT)
data(vivienda)
#str(vivienda)
Observamos la dimensión de los datos
dimension <- dim(vivienda)
dimension
## [1] 8322 13
str(vivienda)
## Classes 'spec_tbl_df', 'tbl_df', 'tbl' and 'data.frame': 8322 obs. of 13 variables:
## $ id : num 1147 1169 1350 5992 1212 ...
## $ zona : chr "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr NA NA NA "02" ...
## $ estrato : num 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=List of 3
## ..$ cols :List of 13
## .. ..$ id : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ zona : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ piso : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ estrato : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ preciom : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ areaconst : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ parqueaderos: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ banios : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ habitaciones: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ tipo : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ barrio : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ longitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ latitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## ..$ default: list()
## .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
## ..$ delim : chr ";"
## ..- attr(*, "class")= chr "col_spec"
## - attr(*, "problems")=<externalptr>
El conjunto de datos corresponde a 8322 observaciones y 12 variables que corresponden a: zona (tipo texto), piso (tipo texto), estrato (tipo númerico), precio (tipo númerico), area construida (tipo númerico), parqueaderos (tipo númerico), número de baños (tipo númerico), número de habitaciones (tipo númerico), tipo (tipo texto), barrio (tipo texto) y ubicación la cual esta dada por longitud y latitud y son de tipo númerico. Para el posterior análisis hacemos una exploración de los datos faltantes,
Los datos faltantes del conjunto de catos corresponden a:
| Variable | Número de datos perdidos |
|---|---|
| Zona | 3 |
| Piso | 2638 |
| Estrato | 3 |
| Precio | 2 |
| Área Construida | 3 |
| Parqueaderos | 1605 |
| Baños | 3 |
| Habitaciones | 3 |
| Tipo | 3 |
| Barrio | 3 |
| Longitud | 3 |
| Latitud | 3 |
La distribución del número de inmuebes por barrio, es el siguiente,
# Obtener los cinco máximos
cinco_maximos <- conteo_valores_df[order(conteo_valores_df$Freq, decreasing = TRUE), ][1:10, ]
# Mostrar los cinco máximos
print(cinco_maximos)
## Var1 Freq
## 415 valle del lili 1008
## 107 ciudad jardín 516
## 299 pance 409
## 212 la flora 366
## 378 santa teresita 262
## 143 el caney 208
## 152 el ingenio 202
## 217 la hacienda 164
## 3 acopi 158
## 254 los cristales 154
Teniendo en cuenta que son 436 barrios solo se presenta la distribución del número del numero de inmuebles en los 10 barrios con mayor frecuencia, observando lo siguiente:
| Variable | Número de datos perdidos |
|---|---|
| Valle del lili | 1008 |
| Ciudad jardín | 516 |
| Pance | 409 |
| La flora | 366 |
| Santa Teresita | 262 |
| El Caney | 208 |
| El Ingenio | 202 |
| La Hacienda | 164 |
| Acopi | 158 |
| Los Cristales | 154 |
Dado que las variables que presentan mayor número de datos perdidos son: Piso y Parqueadero con 2630 y 1605 respectivamente las excluiremos de nuestro análisis, también no se tendra en cuenta el barrio.
quitar <- c("piso","parqueaderos","barrio")
vivienda <- vivienda[ ,!(names(vivienda) %in% quitar)]
vivienda <- vivienda[complete.cases(vivienda), ]
sum(is.na(vivienda))
## [1] 0
Imputando las datos perdidos se obtiene 8319 observaciones y 9 variables.
Veamos la distribución por zonas,
A continuación se presenta la distribución del numero de inmuebles por zona, donde el mayor porcentaje(56.8 %) se presento en la zona zur, seguido por la zona norte (23.1 %), zona oeste (14.4%), zona oriente (4.2%) y zona centro (1,5%).
conteo_valoreszona <- table(vivienda$zona )
conteo_valoreszona_df <- as.data.frame(conteo_valoreszona )
#conteo_mayores_a_100 <- sum(conteo_valores_df$Freq > 100)
#conteo_mayores_a_100 <- as.data.frame(conteo_mayores_a_100 )
#conteo_mayores_a_100
# print(conteo_valoreszona_df)
# Obtener los datos de la columna "Proporciones"
datos <- conteo_valoreszona_df$Freq
# Etiquetas para las secciones
etiquetas <- round(conteo_valoreszona_df$Freq / sum(conteo_valoreszona_df$Freq), 3)*100
# Colores para las secciones (opcional)
colores <- c("red", "blue", "green", "orange", "purple")
# Crear el diagrama de sectores con etiquetas en la mitad
pie(datos, labels = etiquetas, col = colores, clockwise = TRUE, radius = 1, init.angle = 90)
leyenda_etiquetas <- conteo_valoreszona_df$Var1
legend("topright", legend = leyenda_etiquetas, fill = colores, bty = "n")
En n uestro conjunto de datos exiten 5100 apartamentos y 3219 casas.
conteo_valorestipo <- table(vivienda$tipo )
conteo_valorestipo_df <- as.data.frame(conteo_valorestipo )
| Tipo de inmueble | Frecuencia |
|---|---|
| Apartamento | 5100 |
| Casa | 3219 |
conteo_valoresestrato <- table(vivienda$estrato )
conteo_valoresestrato_df <- as.data.frame(conteo_valoresestrato )
# Obtener los valores de la columna "Valores"
valores <- round(conteo_valoresestrato_df$Freq / sum(conteo_valoresestrato_df$Freq),2)
# Etiquetas para las barras
etiquetas <- conteo_valoresestrato_df$Var1
# Colores para las barras (opcional)
colores <- c("red", "blue", "green", "orange")
# Crear el diagrama de barras
barplot(valores, names.arg = etiquetas, col = colores)
# Agregar el valor a cada barra
text(x = 1:length(valores), y = valores, labels = valores, pos = 1, col = "black")
De la gráfica anterior se puede concluir que el más alto porcentaje de inmuebles se encuentra en el estrato cinco con el 33%, seguido del estrato 4 (26%), estrato 6 (24%) y estrato 3 (17%).
# Crear el diagrama de cajas por categorías
boxplot(vivienda$preciom ~ vivienda$zona, data = vivienda, col = c("red", "blue", "green","orange","purple" ), ylab = "Precio", xlab = "Zona")
resumen_zona <- function(x) c(media=mean(x),sd=sd(x), mediana=median(x), minimo=min(x), maximo=max(x))
descriptivos_zona<- aggregate(vivienda$preciom~vivienda$zona,vivienda,resumen_zona)
resumen_zona_df<-as.data.frame(descriptivos_zona)
descriptivos_zona
## vivienda$zona vivienda$preciom.media vivienda$preciom.sd
## 1 Zona Centro 309.6935 162.1479
## 2 Zona Norte 345.6083 240.8674
## 3 Zona Oeste 677.5801 391.5828
## 4 Zona Oriente 228.5299 122.0641
## 5 Zona Sur 426.5184 322.7229
## vivienda$preciom.mediana vivienda$preciom.minimo vivienda$preciom.maximo
## 1 297.0000 100.0000 1100.0000
## 2 300.0000 65.0000 1940.0000
## 3 580.0000 85.0000 1999.0000
## 4 210.0000 58.0000 1350.0000
## 5 320.0000 75.0000 1900.0000
Se puede evidenciar que el valor de los precios en orden descendente se presentaron en la zona Oeste, zona sur, zona norte, zona centro y zona oriente respectivamente.
# Crear el diagrama de cajas por categorías
boxplot(vivienda$preciom ~ vivienda$tipo, data = vivienda, col = c("red", "blue" ), ylab = "Precio", xlab = "Tipo")
resumen_tipo <- function(x) c(media=mean(x),sd=sd(x), mediana=median(x), minimo=min(x), maximo=max(x))
descriptivos_tipo<- aggregate(vivienda$preciom~vivienda$tipo,vivienda,resumen_tipo)
descriptivos_tipo
## vivienda$tipo vivienda$preciom.media vivienda$preciom.sd
## 1 Apartamento 366.9435 289.2194
## 2 Casa 539.9935 358.2028
## vivienda$preciom.mediana vivienda$preciom.minimo vivienda$preciom.maximo
## 1 279.0000 58.0000 1950.0000
## 2 430.0000 77.0000 1999.0000
Con respecto al precio por tipo de vivienda se observa que las casas presentaron precios más altos con respecto a los apartamentos.
# Crear el diagrama de cajas por categorías
boxplot(vivienda$preciom ~ vivienda$estrato, data = vivienda, col = c("red", "blue", "green", "orange" ), ylab = "Precio", xlab = "Estrato")
resumen_estrato <- function(x) c(media=mean(x),sd=sd(x), mediana=median(x), minimo=min(x), maximo=max(x))
descriptivos_estrato<- aggregate(vivienda$preciom~vivienda$estrato,vivienda,resumen_tipo)
descriptivos_estrato
## vivienda$estrato vivienda$preciom.media vivienda$preciom.sd
## 1 3 210.3235 133.8085
## 2 4 275.0996 158.2925
## 3 5 410.2509 223.8606
## 4 6 800.2889 380.0428
## vivienda$preciom.mediana vivienda$preciom.minimo vivienda$preciom.maximo
## 1 160.0000 58.0000 1600.0000
## 2 235.0000 78.0000 1800.0000
## 3 350.0000 89.0000 1999.0000
## 4 700.0000 128.0000 1950.0000
El orden de los precios de los inmuebles en orden descendente con respecto a los estratos se presentan del estrato seis al estrato tres.
A continuación se indagará sobre las posibles asociaciones o correlaciones entre las variables de tipo cuantitativo,
library(psych)
# Cargar el paquete corrplot
library(corrplot)
## corrplot 0.92 loaded
# Seleccionar solo las columnas deseadas para el cálculo de la correlación
columnas_seleccionadas <- vivienda[, c("preciom", "areaconst", "habitaciones", "banios")]
correlacion<-round(cor(columnas_seleccionadas), 1)
corrplot(correlacion, method="number", type="upper")
# install.packages("PerformanceAnalytics")
library(PerformanceAnalytics)
## Loading required package: xts
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
chart.Correlation(columnas_seleccionadas, histogram = TRUE, method = "pearson")
#chart.Correlation(columnas_seleccionadas, histogram = F, pch = 19)
De acuerdo al anális de correlación podemos concluir los siguiente:
El coeficiente de Pearson o grado de asociación lineal del precio con respecto a: área construida fue de 0.7, al número de habitaciones fue de 0.3 y con respecto al número de baños fue de 0.7. De cual se puede estimar que a mayor área contruida, mayor número de habitaciones y mayor numero de baños mayor será su precio.
Por otro lado el coeficiente de Pearson o grado de asociación lineal del área construida con respecto a: al número de habitaciones fue de 0.5 y con respecto al número de baños fue de 0.6, lo que indica que a mayor mayor área construida mayor numero de habitaciones y baños.
Finalmente el coeficiente de Pearson o grado de asociación lineal del número de habitaciones con respecto al número de baños es de 0.6, indicando que a mayor número de habitaciones, mayor número de baños se prsentarán.
A continuación se presentará un Análisis de Componentes principales, para encontrar una forma de agrupación de los inmuebles de acuerdo a ciertas similaridades que puedan presentar los datos.
Para hacer el Análisis de Componentes Principales, creamos variables dummy, para las variables: zona y tipo de la siguiente forma:
Zona
Tipo
#install.packages("rlang")
library(dplyr)
##
## ######################### Warning from 'xts' package ##########################
## # #
## # The dplyr lag() function breaks how base R's lag() function is supposed to #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or #
## # source() into this session won't work correctly. #
## # #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop #
## # dplyr from breaking base R's lag() function. #
## # #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning. #
## # #
## ###############################################################################
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:xts':
##
## first, last
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# Zona
#install.packages("dplyr", version = "1.0.7")
library(dplyr)
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)
# Tipo
vivienda <- vivienda %>% mutate(tipo = replace(tipo,
tipo == "Casa", 1))
vivienda <- vivienda %>% mutate(tipo = replace(tipo,
tipo == "Apartamento", 2))
vivienda$tipo <- as.numeric(vivienda$tipo)
head(vivienda,3) # Tabla
## # A tibble: 3 × 10
## id zona estrato preciom areaconst banios habitaciones tipo longitud
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 4 3 250 70 3 6 1 -76.5
## 2 1169 4 3 320 120 2 3 1 -76.5
## 3 1350 4 3 350 220 2 4 1 -76.5
## # ℹ 1 more variable: latitud <dbl>
Para realizar nuestro análisis (ACP) correspondiente tendremos en cuenta las siguientes variables: zona, estrato, precio, área construida, baños, número de habitaciones, tipo de inmueble.
vivienda_2 <- vivienda[1:8319,2:7]
Estandariando las variables se obtiene:
#install.packages("tidyr")
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats 1.0.0 ✔ readr 2.1.4
## ✔ ggplot2 3.4.2 ✔ stringr 1.5.0
## ✔ lubridate 1.9.2 ✔ tibble 3.2.1
## ✔ purrr 1.0.1 ✔ tidyr 1.3.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ ggplot2::%+%() masks psych::%+%()
## ✖ ggplot2::alpha() masks psych::alpha()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::first() masks xts::first()
## ✖ dplyr::lag() masks stats::lag()
## ✖ dplyr::last() masks xts::last()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
vivienda_2z= vivienda_2 %>%
scale()
head(vivienda_2z) # primeros 6 registros
## zona estrato preciom areaconst banios habitaciones
## [1,] 0.06192582 -1.5872276 -0.5595498 -0.7339949 -0.07793773 1.6406840
## [2,] 0.06192582 -1.5872276 -0.3465670 -0.3842568 -0.77811479 -0.4147626
## [3,] 0.06192582 -1.5872276 -0.2552886 0.3152194 -0.77811479 0.2703863
## [4,] 0.81508501 -0.6156201 -0.1031580 0.7349051 1.32241640 -0.4147626
## [5,] -1.44439256 0.3559875 -0.5291236 -0.5940997 -0.77811479 -0.4147626
## [6,] -1.44439256 0.3559875 -0.5899759 -0.6150839 -0.07793773 -0.4147626
Las siguientes medidas nos permitirán identificar si es viable o no aplicar un análisis factorial en particular un Análisis de Componentes Principales (ACP), en la matriz de datos, dichas medidas son:
Test de Bartlett, la misma que es una prueba estadística para homogeneidad de varianzas, y para la aplicación en un AF es decir proporciona la probabilidad estadística de que la matriz de correlación de las variables sea una matriz identidad.
Medida de suficiencia o adecuación de la muestra (MSA o KMO)
Este índice se extiende de 0 a 1, llegando a 1 cuando cada variable es perfectamente predicha sin error por las otras variables.
Esta medida puede ser interpretada de la siguiente forma:
Calculemos estas medidas para nuestra matriz de datos.
Se calcula la matriz de correlaciones
matriz_correlaciones <- cor(vivienda_2z, use = "pairwise.complete.obs")
matriz_correlaciones
## zona estrato preciom areaconst banios
## zona 1.000000000 0.11097057 0.0160982 0.007948296 0.07754447
## estrato 0.110970570 1.00000000 0.6098066 0.274323323 0.42032178
## preciom 0.016098198 0.60980664 1.0000000 0.687351963 0.66914558
## areaconst 0.007948296 0.27432332 0.6873520 1.000000000 0.64841648
## banios 0.077544475 0.42032178 0.6691456 0.648416477 1.00000000
## habitaciones 0.021593137 -0.07137615 0.2640912 0.516912916 0.58990641
## habitaciones
## zona 0.02159314
## estrato -0.07137615
## preciom 0.26409121
## areaconst 0.51691292
## banios 0.58990641
## habitaciones 1.00000000
Cuyo determinante de es
det(matriz_correlaciones)
## [1] 0.07009678
Prueba de esfericidad de BARLETT
#PRUEBA DE ESFERICIDAD DE BARLETT
library(psych)
cortest.bartlett(vivienda_2z)
## R was not square, finding R from data
## $chisq
## [1] 22100.7
##
## $p.value
## [1] 0
##
## $df
## [1] 15
#Prueba KMO
KMO(vivienda_2z)
## Kaiser-Meyer-Olkin factor adequacy
## Call: KMO(r = vivienda_2z)
## Overall MSA = 0.69
## MSA for each item =
## zona estrato preciom areaconst banios habitaciones
## 0.43 0.60 0.69 0.75 0.74 0.58
Se observa, el determinante de la matriz de correlaciones arroja un valor cercano a cero (0.07), lo que indica que el grado de intercorrelación de las variables es muy alto. Este valor es confirmado por la significatividad asociada al test de esfericidad de Bartlett, que es 0,000, por lo que se puede rechazar la hipótesis nula de incorrelación entre variables. También el KMO arroja un valor de 0,69, por lo que, según este indicador, la matriz de datos resulta adecuada para realizar sobre ella la factorización. Por lo tanto se procederá a calcular los factores.
resultado_pca<-prcomp(vivienda_2z)
resultado_pca
## Standard deviations (1, .., p=6):
## [1] 1.7140505 1.0971157 0.9956232 0.6598739 0.4914745 0.4360297
##
## Rotation (n x k) = (6 x 6):
## PC1 PC2 PC3 PC4 PC5
## zona -0.04982232 0.2664489 0.95249676 -0.1316906 -0.01325798
## estrato -0.33147442 0.6586234 -0.12896050 0.4191140 0.48073525
## preciom -0.50576448 0.2481943 -0.16949469 -0.2792797 -0.21609172
## areaconst -0.49252936 -0.1774601 -0.04265390 -0.6559480 0.29135511
## banios -0.51880182 -0.1017684 0.05975227 0.3729587 -0.66586242
## habitaciones -0.34656059 -0.6259161 0.20494141 0.3995471 0.44018366
## PC6
## zona 0.04188647
## estrato -0.18151086
## preciom 0.72744803
## areaconst -0.45710817
## banios -0.36666955
## habitaciones 0.30450657
print(summary(resultado_pca))
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6
## Standard deviation 1.7141 1.0971 0.9956 0.65987 0.49147 0.43603
## Proportion of Variance 0.4897 0.2006 0.1652 0.07257 0.04026 0.03169
## Cumulative Proportion 0.4897 0.6903 0.8555 0.92806 0.96831 1.00000
#install.packages("tidyr")
#fviz_screeplot(resultado_pca, addlabels = TRUE, ylim = c(0, 100))
#fviz_eig(resultado_pca, addlabels = TRUE)
De los 6 factores se puede concluir los siguiente:
Lo cual lo podemos observar el gráfico de segmentación siguiente:
El gráfico de Sedimentación nos muestra la cantidad óptimas de componentes a tomar en la data , siendo los valorer por encima de la linea de 1.0 los mas aceptables
library(psych)
scree(vivienda_2z,main ="Grafico_de_Sedimentacion")
Según el gráfico de sedimentación, lo optimo seria realizar 3 componentes, puesto que este valor se encuentra por encima de la línea aceptable de la grafica .
En la matriz de rotación(varimax) se puede observar el peso de cada variable en el factor correspondiente.
library(stats)
factanal(vivienda_2z, factors = 3, rotation = "varimax")
##
## Call:
## factanal(x = vivienda_2z, factors = 3, rotation = "varimax")
##
## Uniquenesses:
## zona estrato preciom areaconst banios habitaciones
## 0.960 0.257 0.005 0.357 0.220 0.251
##
## Loadings:
## Factor1 Factor2 Factor3
## zona 0.199
## estrato 0.662 -0.102 0.543
## preciom 0.955 0.288
## areaconst 0.543 0.588
## banios 0.495 0.668 0.297
## habitaciones 0.865
##
## Factor1 Factor2 Factor3
## SS loadings 1.890 1.636 0.425
## Proportion Var 0.315 0.273 0.071
## Cumulative Var 0.315 0.588 0.658
##
## The degrees of freedom for the model is 0 and the fit was 0
Obteniendo los factores a través del método de rotación varimax, se puede concluir que se encuentran muy correlacionadas el estrato y el precio que hacen parte del primer factor, el área construida, el numero de baños y el número de habitaciones que hacen parte del factor 2 y finalmente zona esta en el factor 3.
A continuación Visualizaremos la varianza explicada por las 6 componentes principales arrojadas en el análisis de componentes principales,
biplot(resultado_pca, scale=0.5)
#install.packages("factoextra")
library(factoextra)
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
fviz_pca_var(resultado_pca, col.var = "cos2",
geom.var = "arrow",
labelsize = 2, repel = FALSE)
#Marca el valor de la contribución de las variables a los componentes.
fviz_screeplot(resultado_pca, addlabels = TRUE, ylim = c(0, 100))
Al visualizar las variables en el plano de los componentes principales permite identificar el sentido y la caracterización de los componentes.
Del Análisis de Componentes Principales (ACP) se concluye lo siguiente:
Desde la visualización de los datos en dos dimensiones, no se alcanza a distinguir de forma clara, un patrón o comportamiento de las viviendas según la zona en la cual se encuentran.
La primera componente explica el 48.97% de la varianza observada de los datos, la segunda componente, explica el 20.06% de la varianza varianza observada de los datos y la tercera, explica el 16.52% de la varianza observada de los datos. Es decir, las tres componentes contienen la mayor parte de la información contenida en las 5 variables.
En la primera componente, las variables estrato y precio, son las que presentan una mayor influencia respectivamente. En la segunda componente, las variables área, baños y habitaciones, son las que presentan una mayor influencia respectivamente, mientras que en la tercera corresponde a la variable zona es la que presenta mayor influencia. Según el análisis de matriz de correlaciones que se hizo inicialmente, las variables de mayor influencia de la primera componente están altamente correlacionadas entre sí, por tanto, esta componente puede pertenecer a las variables correlacionadas.
En caso de querer ejecutar un modelo de regresión simple, se pueden usar las 3 componentes obtenidas con el ACP, pero si se desea un modelo de regresión múltiple, se pueden emplear las 5 variables originales y posteriormente comparar el ajuste y predicciones de ambos modelos.
Para el análisis de conglomerados (Clustering), se seleccionaran las siguientes variables: estrato, preciom, areacons, banios, habitaciones y zona.
Seleccionamos las variables que se van a trabajar,
vivienda_3 <- vivienda[1:8319,2:7]
Estandarizamos los valores de tal forma que la media sea cero y su desviación estándar 1, luego convertimos los datos en un data frame,
vivienda_3_est <- scale(vivienda_3)
vivienda_3_est <- as.data.frame(vivienda_3_est)
head(vivienda_3_est,3)
## zona estrato preciom areaconst banios habitaciones
## 1 0.06192582 -1.587228 -0.5595498 -0.7339949 -0.07793773 1.6406840
## 2 0.06192582 -1.587228 -0.3465670 -0.3842568 -0.77811479 -0.4147626
## 3 0.06192582 -1.587228 -0.2552886 0.3152194 -0.77811479 0.2703863
Se construye el siguiente gráfico para seleccionar el número de clusters adecuado para este conjunto de datos,
scv <- (nrow(vivienda_3_est) - 1) * sum(apply(vivienda_3_est, 2, var))
for (i in 2:15) scv[i] <- sum(kmeans(vivienda_3_est,
centers = i)$withinss)
plot(1:15, scv,
type = "b",
xlab = "Cantidad de Clusters",
ylab="Suma de cuadrados dentro de grupos")
Sin embargo se utilizará distintos métodos que permiten encontrar el
número de cluster adecuado
fviz_nbclust(vivienda_3_est, kmeans, method = "wss") + labs (subtitle="Elbow method")
El codo de la distribución lo podemos asumir que se encuentra en el cluster 3.
fviz_nbclust(vivienda_3_est, kmeans, method = "silhouette") + labs (subtitle="silhouette method")
De acuerdo al método de la silueta podemos estimar dos cluster.
#install.packages("NbClust")
library(NbClust)
res.nbclust <- NbClust(vivienda_3_est, distance = "euclidean", min.nc = 2, max.nc=6, method = "complete", index = "all")
## *** : The Hubert index is a graphical method of determining the number of clusters.
## In the plot of Hubert index, we seek a significant knee that corresponds to a
## significant increase of the value of the measure i.e the significant peak in Hubert
## index second differences plot.
##
## *** : The D index is a graphical method of determining the number of clusters.
## In the plot of D index, we seek a significant knee (the significant peak in Dindex
## second differences plot) that corresponds to a significant increase of the value of
## the measure.
##
## *******************************************************************
## * Among all indices:
## * 6 proposed 2 as the best number of clusters
## * 10 proposed 3 as the best number of clusters
## * 2 proposed 4 as the best number of clusters
## * 3 proposed 5 as the best number of clusters
## * 1 proposed 6 as the best number of clusters
##
## ***** Conclusion *****
##
## * According to the majority rule, the best number of clusters is 3
##
##
## *******************************************************************
#factoextra::fviz_nbclust(res.nbclust) + theme_minimal() + ggtittle("nb cust optimal number of clusters") + theme_classic()
Utilizando el método para seleccionar los clusters es K-Means, que es un método de agrupamiento, que tiene como objetivo la partición de un conjunto de n observaciones en k grupos en el que cada observación pertenece al grupo cuyo valor medio es más cercano, se obtuvo:
Concluyendo que de según la regla de la mayoría, el mejor número de clusters es 3.
set.seed(123)
modelo_kmeans <- kmeans(vivienda_3_est, 3) # Ajuste
vivienda_3_est <- data.frame(vivienda_3_est,
modelo_kmeans$cluster) # Cluster
aggregate(vivienda_3,
by = list(vivienda_3_est$modelo_kmeans.cluster),
FUN = median) # Medianas
## Group.1 zona estrato preciom areaconst banios habitaciones
## 1 1 5 6 750 300 5 4
## 2 2 5 4 252 92 2 3
## 3 3 2 5 300 103 2 3
table(vivienda_3_est$modelo_kmeans.cluster)
##
## 1 2 3
## 2243 3717 2359
Donde en el primer Custer aparecen 2243 registros, en el segundo 3717, mientras que en el tercero se presentaron 2359.
La gráfica a los tres cluster se presenta a continuación
fviz_cluster(list(data = vivienda_3_est[,1:6],
cluster = vivienda_3_est$modelo_kmeans.cluster),
palette = c("#2E9FDF", "#E7B800", "#FC4E07"),
ellipse.type = "convex",repel = F,
show.clust.cent = FALSE, ggtheme = theme_minimal())
Este gráfico respalda los resultados obtenidos anteriormente, pues evidentemente los clusters 1 y 2 están situados en los extremos del plano, lo que indica la lejania que existe entre estos grupos por las características que poseen.
set.seed(0)
clusterIris <- kmeans(vivienda_3, center=3, nstart = 20)
#clusterIris
library(cluster)
clusplot(vivienda_3, clusterIris$cluster, color=TRUE, shade = TRUE, lines=0, main = "Representación de los clusters modelados")
vivienda_3_est %>%
ggplot(aes(x = factor(clusterIris$cluster), y = preciom, fill = factor(clusterIris$cluster))) + geom_boxplot() + geom_point() + xlab("Cluster") + labs(fill="Cluster")
vivienda_3_est %>%
ggplot(aes(x = factor(clusterIris$cluster), y = areaconst, fill = factor(clusterIris$cluster))) + geom_boxplot() + geom_point() + xlab("Cluster") + labs(fill="Cluster")
vivienda_3_est %>%
ggplot(aes(x = factor(clusterIris$cluster), y = banios, fill = factor(clusterIris$cluster))) + geom_boxplot() + geom_point() + xlab("Cluster") + labs(fill="Cluster")
vivienda_3_est %>%
ggplot(aes(x = factor(clusterIris$cluster), y = habitaciones, fill = factor(clusterIris$cluster))) + geom_boxplot() + geom_point() + xlab("Cluster") + labs(fill="Cluster")
vivienda_3_est %>%
ggplot(aes(x = factor(clusterIris$cluster), y = estrato, fill = factor(clusterIris$cluster))) + geom_boxplot() + geom_point() + xlab("Cluster") + labs(fill="Cluster")
Con lo anterior podemos concluir los siguiente:
Cluster 1, presenta precios bajos, pequeñas áreas construidas, pocos baños, pocas habitaciones y estratos bajos.
Cluster 2, presentan precios altos, grandes áreas construidas, gran número de baños, nivel medio de habitaciones similares al del cluster 3 y estratos altos.
Cluster 3, presentan precios medio, áreas medias construidas, número medio de de baños, nivel medio de habitaciones similares al del cluster 2 y estratos medios.
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,
set.seed(0)
dist_eu <- dist(vivienda_3_est[,1:6],method = "euclidean")
modelo_jer <- hclust(dist_eu, method = "ward.D")
library(tidyverse)
library(cluster) # LibreríaS
# k = 2
cluster_assigments_k2 <- cutree(modelo_jer, k = 2) # Cluster
sil_1_k2 <- silhouette(cluster_assigments_k2, dist(vivienda_3_est[,1:6]))
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.2907282
# k = 3
cluster_assigments_k3 <- cutree(modelo_jer, k = 3) # Cluster
sil_1_k3 <- silhouette(cluster_assigments_k3, dist(vivienda_3_est[,1:6]))
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.2521172
# k = 4
cluster_assigments_k4 <- cutree(modelo_jer, k = 4) # Cluster
sil_1_k4 <- silhouette(cluster_assigments_k4, dist(vivienda_3_est[,1:6]))
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.2772796
# k = 5
cluster_assigments_k5 <- cutree(modelo_jer, k = 5) # Cluster
sil_1_k5 <- silhouette(cluster_assigments_k5, dist(vivienda_3_est[,1:6]))
sil_1_avg_k5 <- mean(sil_1_k5[,3])
cat("Coeficiente de Silhouette promedio k=5 : ", sil_1_avg_k5)
## Coeficiente de Silhouette promedio k=5 : 0.2883832
# k = 6
cluster_assigments_k6 <- cutree(modelo_jer, k = 6) # Cluster
sil_1_k6 <- silhouette(cluster_assigments_k6, dist(vivienda_3_est[,1:6]))
sil_1_avg_k6 <- mean(sil_1_k6[,3])
cat("Coeficiente de Silhouette promedio k=6 : ", sil_1_avg_k6)
## Coeficiente de Silhouette promedio k=6 : 0.2191879
# k = 7
cluster_assigments_k7 <- cutree(modelo_jer, k = 7) # Cluster
sil_1_k7 <- silhouette(cluster_assigments_k7, dist(vivienda_3_est[,1:6]))
sil_1_avg_k7 <- mean(sil_1_k7[,3])
cat("Coeficiente de Silhouette promedio k=7 : ", sil_1_avg_k7)
## Coeficiente de Silhouette promedio k=7 : 0.2328442
El valor indicado para k es el más cercano a 1. Estos valores que arroja el coeficiente están muy lejanos de 1, sim embargo, se toma el valor más próximo, que en este caso corresponde a k = 2.
Se crea un dendograma para visualizar las agrupaciones,
plot(modelo_jer)
rect.hclust(modelo_jer, k = 2, border = "green")
Se observa la cantidad de datos pertenecientes a cada cluster,
cluster_jer <- cutree(modelo_jer, k = 2)
vivienda_3_est <- data.frame(vivienda_3_est,cluster_jer)
table(vivienda_3_est$cluster_jer)
##
## 1 2
## 2781 5538
El cluster de mayor tamaño es el número 2 y la diferencia es bastante grande.
Descripción de los clusters,
aggregate(vivienda_3,
by = list(vivienda_3_est$cluster_jer),
FUN = median)
## Group.1 zona estrato preciom areaconst banios habitaciones
## 1 1 5 5 600 258 4 4
## 2 2 5 5 260 90 2 3
En este caso se identifican claramente 2 panoramas, por un lado, el cluster 1 contiene datos que en su mayoría pertenecen a viviendas precios, áreas y estratos altos, mientras que el cluster 2 son viviendas que en su mayoría también son estrato 5, pero que tienen áreas y precios inferiores a los inmuebles del cluster 1.
Se realiza el gráfico de dispersión,
fviz_cluster(list(data = vivienda_3_est[,1:6],
cluster = vivienda_3_est$cluster_jer),
palette = c("#2E9FDF", "#E7B800"),
ellipse.type = "convex",repel = F,
show.clust.cent = FALSE, ggtheme = theme_minimal())
Se desea validar si las distancias en el dendograma reflejan las
distancias originales. Para esto, se calcula la correlación entre las
distancias cofenéticas y los datos de distancia originales (distancia
euclideana)
dist_cf <- cophenetic(modelo_jer) # Distancias cofenéticas
cor(dist_eu, dist_cf) # Correlación
## [1] 0.4827681
La asociación entre ambas variables NO es tan buena, por tanto, no hay una buena precisión del agrupamiento realizado por el método jerárquico con el método Ward.
Se emplea el método “average” en lugar de “Ward.D”, para comparar los resultados entre ambos criterios de agrupación,
set.seed(0)
modelo_jer_2 <- hclust(dist_eu, method = "average")
Para seleccionar el número adecuado de clusters se emplea nuevamente el coeficiente de Silhouette,
# k = 2
cluster_assigments_k2_2 <- cutree(modelo_jer_2, k = 2) # Cluster
sil_2_k2 <- silhouette(cluster_assigments_k2_2,
dist(vivienda_3_est[,1:6]))
sil_2_avg_k2 <- mean(sil_2_k2[,3])
cat("Coeficiente de Silhouette promedio k=2 : ", sil_2_avg_k2)
## Coeficiente de Silhouette promedio k=2 : 0.6970237
# k = 3
cluster_assigments_k3_2 <- cutree(modelo_jer_2, k = 3) # Cluster
sil_2_k3 <- silhouette(cluster_assigments_k3_2,
dist(vivienda_3_est[,1:6]))
sil_2_avg_k3 <- mean(sil_2_k3[,3])
cat("Coeficiente de Silhouette promedio k=3 : ", sil_2_avg_k3)
## Coeficiente de Silhouette promedio k=3 : 0.5093748
# k = 4
cluster_assigments_k4_2 <- cutree(modelo_jer_2, k = 4) # Cluster
sil_2_k4 <- silhouette(cluster_assigments_k4_2,
dist(vivienda_3_est[,1:6]))
sil_2_avg_k4 <- mean(sil_2_k4[,3])
cat("Coeficiente de Silhouette promedio k=4 : ", sil_2_avg_k4)
## Coeficiente de Silhouette promedio k=4 : 0.5089671
# k = 5
cluster_assigments_k5_2 <- cutree(modelo_jer_2, k = 5) # Cluster
sil_2_k5 <- silhouette(cluster_assigments_k5_2,
dist(vivienda_3_est[,1:6]))
sil_2_avg_k5 <- mean(sil_2_k5[,3])
cat("Coeficiente de Silhouette promedio k=5 : ", sil_2_avg_k5)
## Coeficiente de Silhouette promedio k=5 : 0.4534455
# k = 6
cluster_assigments_k6_2 <- cutree(modelo_jer_2, k = 6) # Cluster
sil_2_k6 <- silhouette(cluster_assigments_k6_2,
dist(vivienda_3_est[,1:6]))
sil_2_avg_k6 <- mean(sil_2_k6[,3])
cat("Coeficiente de Silhouette promedio k=6 : ", sil_2_avg_k6)
## Coeficiente de Silhouette promedio k=6 : 0.4533141
# k = 7
cluster_assigments_k7_2 <- cutree(modelo_jer_2, k = 7) # Cluster
sil_2_k7 <- silhouette(cluster_assigments_k7_2,
dist(vivienda_3_est[,1:6]))
sil_2_avg_k7 <- mean(sil_2_k7[,3])
cat("Coeficiente de Silhouette promedio k=7 : ", sil_2_avg_k7)
## Coeficiente de Silhouette promedio k=7 : 0.390529
Entre más aumenta el valor de k, más lejano está de 1, por tanto, nuevamente se toma k = 2, que con este método presenta un mejor ajuste a comparación del modelo anterior.
Se crea un dendograma para visualizar las agrupaciones,
plot(modelo_jer_2)
rect.hclust(modelo_jer_2, k = 2, border = "red")
Se observa la cantidad de datos pertenecientes a cada cluster,
cluster_jer_2 <- cutree(modelo_jer_2, k = 2)
vivienda_3_est <- data.frame(vivienda_3_est,cluster_jer_2)
table(vivienda_3_est$cluster_jer_2)
##
## 1 2
## 8312 7
La diferencia en la cantidad de datos que contien cada cluster es abismal.
Descripción de cada uno de los clusters,
aggregate(vivienda_3,
by = list(vivienda_3_est$cluster_jer_2),
FUN = median)
## Group.1 zona estrato preciom areaconst banios habitaciones
## 1 1 5 5 330 123 3 3
## 2 2 5 6 1500 1500 4 4
En este caso se mantiene el mismo panorama que en la situación anterior, sin embargo, en esta ocasión las viviendas de mayor área y precio quedaron en el cluster 2, además, estas viviendas en su mayoría son estrato 6 y la diferencia de las variables entre ambos grupos parece ser mucho mayor, por tanto, todo indica que los datos del cluster 2 corresponden a valores extremos o datos atípicos.
Se realiza el gráfico de dispersión,
fviz_cluster(list(data = vivienda_3_est[,1:6],
cluster = vivienda_3_est$cluster_jer_2),
palette = c("#2E9FDF", "#E7B800"),
ellipse.type = "convex",repel = F,
show.clust.cent = FALSE, ggtheme = theme_minimal())
Por medio del gráfico se puede comprobar lo que se venía sospechando, la mayoría de los datos que pertenecen al cluster 2 corresponden a valores que están en el extremo del plano.
Se calcula la correlación entre las distancias cofenéticas y los datos de distancia originales (distancia euclideana),
dist_cf_2 <- cophenetic(modelo_jer_2) # Distancias cofenéticas
cor(dist_eu, dist_cf_2) # Correlación
## [1] 0.7781417
Este indicador mejoró notablemente a comparación del modelo jerárquico anterior.
Finalmente, se hace una comparación de las 2 agrupaciones anteriores por medio de una matriz de correlación,
library(dendextend) # Librería
##
## ---------------------
## Welcome to dendextend version 1.17.1
## Type citation('dendextend') for how to cite the package.
##
## Type browseVignettes(package = 'dendextend') for the package vignette.
## The github page is: https://github.com/talgalili/dendextend/
##
## Suggestions and bug-reports can be submitted at: https://github.com/talgalili/dendextend/issues
## You may ask questions at stackoverflow, use the r and dendextend tags:
## https://stackoverflow.com/questions/tagged/dendextend
##
## To suppress this message use: suppressPackageStartupMessages(library(dendextend))
## ---------------------
##
## Attaching package: 'dendextend'
## The following object is masked from 'package:stats':
##
## cutree
dend_1 <- as.dendrogram(modelo_jer) # Dendograma Ward.D
dend_2 <- as.dendrogram(modelo_jer_2) # Dendograma Average
cor_cophenetic(dend_1, dend_2) # Matriz de correlación cofenética
## [1] 0.4696979
En efecto, la correlación entre ambos dendogramas es muy baja, lo que indica que la agrupación realizada es muy diferente entre ellos.
Del Análisis de Conglomerados (Clustering) se concluye lo siguiente:
La cantidad de clusters que sugieren ambos métodos (jerárquico y no jerárquico) son diferentes entre sí, sin embargo, son grupos que no pasan un valor de k = 3. Esto podría indicar que las viviendas no poseen información suficiente para encontrar otros patrones o características que permitan generar clusters con una estructura más local y no tan general.
Con el modelo K-Means se generaron 3 grupos con características claramente definas.
Con los modelos jerárquicos se generaron 2 grupos para cada uno, las características eran similares a las generadas con el modelo K-Means, sin embargo, con el modelo jerárquico que empleo el criterio ”average”, en el cluster 2 obtuvo datos con características muy atípicas.
Los gráficos sirvieron como respaldo para cada una de las evidencias que se pudieron encontrar por medio de las métricas.
No se puede afirmar que un modelo sea mejor que el otro, a pesar de que en la comparación de los modelos jerárquicos la agrupación que se realizo por medio del criterio ”average” lanzó mejores resultados en las métricas que la agrupación realizada por el método ”Ward”, ya que como se pudo comprobar por medio del análisis, este primer modelo tenia un desequilibrio muy grande en los clusters.
Se pueden emplear estas agrupaciones para hacer un análisis estadístico mas profundo en cada uno de los grupos, ver que otras características comparten, que patrones siguen, que diferencia a un cluster de otro similar e incluso proponer nuevas medidas y agregar nuevos datos a la tabla para generar clusters con una mejor estructura interna.
Inicialmente se contruye una tabla cruzada para las variables categóricas zona y estrato,
library(FactoMineR) # Librería
tabla <- table(vivienda_3$zona, vivienda_3$estrato)
tabla # Tabla cruzada
##
## 3 4 5 6
## 1 105 14 4 1
## 2 572 407 769 172
## 3 54 84 290 770
## 4 340 8 2 1
## 5 382 1616 1685 1043
Donde las zonas son,
Zona Centro: 1 Zona Norte: 2 Zona Oeste: 3 Zona Oriente: 4 Zona Sur: 5
Se ejecuta la prueba Chi-Cuadrado para validar el supuesto de independencia entre los datos,
chisq.test(tabla)
##
## 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. Si se establece un nivel de significancia de 0.1, 0.05 o 0.01, se rechaza en cualquier caso la hipótesis nula, por tanto, hay algún grado de relación entre ambas variables.
Ahora, se procede a realizar el análisis de correspondencia,
library(factoextra) # Librerías
library(gridExtra)
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
ac <- CA(tabla) # Gráfico
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,
fviz_screeplot(ac, addlabels = TRUE,
ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
La primera componente explica el 70 % del total de la varianza y la segunda componente explica el 27.7 % del total de la varianza, por tanto, las 2 primeras componentes en conjunto explican el 97.7 % de la varianza total de los datos.
Del Análisis de Correspondencia Simple (ACS) se concluye lo siguiente:
Existe una relación entre las variables categorías zona y estrato.
Según el estrato en el cual desee vivir el cliente, se le pueden recomendar zonas acordes a la vivienda que busca.
Se pueden incluir otras variables categóricas para hacer inferencias sobre las viviendas de preferencia para cierto tipo de clientes.