Problema

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:

  1. 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.

  2. 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.

  3. 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.

  4. 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,

Base de datos y variables:

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,

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

Distribución por barrio

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

Imputación de variables y datos perdidos.

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,

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")

Distribución por tipo de inmueble.

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

Distribución por estrato del inmuble

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%).

Distribución del precio del inmueble por zona.

# 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.

Distribución del precio del inmueble por tipo.

# 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.

Distribución del precio del inmueble por estrato.

# 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,

Correlaciones entre 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.

Análisis de Componentes Principales (ACP)

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.

Cálculo de 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:

Gráfico de Sedimentación

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.

Conclusiones: Análisis de Componentes Principales (ACP)

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.

Análisis de Conglomerados (Clustering)

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

Métodos NO Jerárquicos

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

Evaluamos el número de Cluster

Método del codo

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.

Método de la silueta

fviz_nbclust(vivienda_3_est, kmeans, method = "silhouette") + labs (subtitle="silhouette method")

De acuerdo al método de la silueta podemos estimar dos cluster.

Gap Statistics

Metodo completo que selecciona distintas técnicas

#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:

  • 6 métodos proponen 2 como el mejor número de clusters
  • 10 métodos proponen 3 como el mejor número de clusters
  • 2 métodos proponen 4 como el mejor número de clusters
  • 3 métodos proponen 5 como el mejor número de clusters
  • 1 método propone 6 como el mejor número de clusters

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")

Diagrama de Cajas y bigotes por cada Cluster de acuerdo al precio del inmueble

vivienda_3_est %>% 
ggplot(aes(x = factor(clusterIris$cluster), y = preciom, fill = factor(clusterIris$cluster))) + geom_boxplot() + geom_point() + xlab("Cluster") + labs(fill="Cluster")

Diagrama de Cajas y bigotes por cada Cluster de acuerdo al área construida

vivienda_3_est %>% 
ggplot(aes(x = factor(clusterIris$cluster), y = areaconst, fill = factor(clusterIris$cluster))) + geom_boxplot() + geom_point() + xlab("Cluster") + labs(fill="Cluster")

Diagrama de Cajas y bigotes por cada Cluster de acuerdo al número de baños

vivienda_3_est %>% 
ggplot(aes(x = factor(clusterIris$cluster), y = banios, fill = factor(clusterIris$cluster))) + geom_boxplot() + geom_point() + xlab("Cluster") + labs(fill="Cluster")

Diagrama de Cajas y bigotes por cada Cluster de acuerdo al número de habitaciones

vivienda_3_est %>% 
ggplot(aes(x = factor(clusterIris$cluster), y = habitaciones, fill = factor(clusterIris$cluster))) + geom_boxplot() + geom_point() + xlab("Cluster") + labs(fill="Cluster")

Diagrama de Cajas y bigotes por cada Cluster de acuerdo al estrato

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.

Método Jerárquico

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.

Conclusiones: Análisis de Conglomerados (Clustering)

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.

Análisis de Correspondencia Simple (ACS)

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.

Conclusiones: Análisis de Correspondencia Simple (ACS)

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.