library(FactoMineR)
library(factoextra)
## Cargando paquete requerido: ggplot2
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(devtools)
## Cargando paquete requerido: usethis
library(paqueteMODELOS)
## Cargando paquete requerido: boot
## Cargando paquete requerido: broom
## Cargando paquete requerido: GGally
## Registered S3 method overwritten by 'GGally':
##   method from   
##   +.gg   ggplot2
## Cargando paquete requerido: gridExtra
## Cargando paquete requerido: knitr
## Cargando paquete requerido: summarytools
library(ggplot2)
library(dplyr)
## 
## Adjuntando el paquete: 'dplyr'
## The following object is masked from 'package:gridExtra':
## 
##     combine
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tinytex)
options(warn = -1)
data("vivienda")
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id          : num [1:8322] 1147 1169 1350 5992 1212 ...
##  $ zona        : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ piso        : chr [1:8322] NA NA NA "02" ...
##  $ estrato     : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
##  $ preciom     : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
##  $ areaconst   : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
##  $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
##  $ banios      : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
##  $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
##  $ tipo        : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
##  $ barrio      : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
##  $ longitud    : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:8322] 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>
View(vivienda)
colSums(is.na(vivienda))
##           id         zona         piso      estrato      preciom    areaconst 
##            3            3         2638            3            2            3 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##         1605            3            3            3            3            3 
##      latitud 
##            3
num_filas <- nrow(vivienda)
# Obtener el número total de columnas
num_columnas <- ncol(vivienda)
cat("Número total de columnas:", num_columnas, "\n")
## Número total de columnas: 13
cat("Numero total de filas:", num_filas, "\n")
## Numero total de filas: 8322
colSums(is.na(vivienda))
##           id         zona         piso      estrato      preciom    areaconst 
##            3            3         2638            3            2            3 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##         1605            3            3            3            3            3 
##      latitud 
##            3

Con el objetivo de depurar la base de datos y eliminar los registros nulos, se implementó una estrategia de imputación de datos basada en grupos, específicamente utilizando la variable “zona”. Esta técnica consistió en reemplazar los valores faltantes en las columnas de “piso” y “parqueaderos” con la mediana correspondiente a cada zona.

vivienda$piso <- as.numeric(as.character(vivienda$piso))
# Calcular la mediana de piso por zona
mediana_piso_por_zona <- vivienda %>%
  group_by(zona) %>%
  summarise(mediana_piso = median(piso, na.rm = TRUE))
# Imprimir el resultado
print(mediana_piso_por_zona)
## # A tibble: 6 × 2
##   zona         mediana_piso
##   <chr>               <dbl>
## 1 Zona Centro             2
## 2 Zona Norte              3
## 3 Zona Oeste              4
## 4 Zona Oriente            2
## 5 Zona Sur                3
## 6 <NA>                   NA
# Calcular la mediana de parqueaderos por zona
mediana_parqueaderos_por_zona <- vivienda %>%
  group_by(zona) %>%
  summarise(mediana_parqueaderos = median(parqueaderos, na.rm = TRUE))
# Imprimir el resultado
print(mediana_parqueaderos_por_zona)
## # A tibble: 6 × 2
##   zona         mediana_parqueaderos
##   <chr>                       <dbl>
## 1 Zona Centro                     1
## 2 Zona Norte                      1
## 3 Zona Oeste                      2
## 4 Zona Oriente                    1
## 5 Zona Sur                        1
## 6 <NA>                           NA
print(vivienda)
## # A tibble: 8,322 × 13
##       id zona    piso estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <dbl>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  1147 Zona …    NA       3     250        70            1      3            6
##  2  1169 Zona …    NA       3     320       120            1      2            3
##  3  1350 Zona …    NA       3     350       220            2      2            4
##  4  5992 Zona …     2       4     400       280            3      5            3
##  5  1212 Zona …     1       5     260        90            1      2            3
##  6  1724 Zona …     1       5     240        87            1      3            3
##  7  2326 Zona …     1       4     220        52            2      2            3
##  8  4386 Zona …     1       5     310       137            2      3            4
##  9  1209 Zona …     2       5     320       150            2      4            6
## 10  1592 Zona …     2       5     780       380            2      3            3
## # ℹ 8,312 more rows
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
# 1. Calcular la mediana de 'piso' por 'zona'
mediana_por_zona <- vivienda %>%
  group_by(zona) %>%
  summarise(mediana_piso = median(piso, na.rm = TRUE), .groups = 'drop')

# 2. Unir la mediana con el data frame original
vivienda <- vivienda %>%
  left_join(mediana_por_zona, by = "zona")

# 3. Imputar los valores NA en 'piso' con la mediana correspondiente
vivienda$piso <- ifelse(is.na(vivienda$piso), vivienda$mediana_piso, vivienda$piso)

# 4. Eliminar la columna de mediana
vivienda <- vivienda %>%
  select(-mediana_piso)

# Imprimir el data frame resultante
print(vivienda)
## # A tibble: 8,322 × 13
##       id zona    piso estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <dbl>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  1147 Zona …     2       3     250        70            1      3            6
##  2  1169 Zona …     2       3     320       120            1      2            3
##  3  1350 Zona …     2       3     350       220            2      2            4
##  4  5992 Zona …     2       4     400       280            3      5            3
##  5  1212 Zona …     1       5     260        90            1      2            3
##  6  1724 Zona …     1       5     240        87            1      3            3
##  7  2326 Zona …     1       4     220        52            2      2            3
##  8  4386 Zona …     1       5     310       137            2      3            4
##  9  1209 Zona …     2       5     320       150            2      4            6
## 10  1592 Zona …     2       5     780       380            2      3            3
## # ℹ 8,312 more rows
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
View(vivienda)
mediana_por_zona_parqueaderos <- vivienda %>%
  group_by(zona) %>%
  summarise(mediana_parqueaderos = median(parqueaderos, na.rm = TRUE), .groups = 'drop')

# 2. Unir la mediana con el data frame original
vivienda <- vivienda %>%
  left_join(mediana_por_zona_parqueaderos, by = "zona")

# 3. Imputar los valores NA en 'parqueaderos' con la mediana correspondiente
vivienda$parqueaderos <- ifelse(is.na(vivienda$parqueaderos), vivienda$mediana_parqueaderos, vivienda$parqueaderos)

# 4.Eliminar la columna de mediana 
vivienda <- vivienda %>%
  select(-mediana_parqueaderos)

# Imprimir el data frame resultante
print(vivienda)
## # A tibble: 8,322 × 13
##       id zona    piso estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <dbl>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  1147 Zona …     2       3     250        70            1      3            6
##  2  1169 Zona …     2       3     320       120            1      2            3
##  3  1350 Zona …     2       3     350       220            2      2            4
##  4  5992 Zona …     2       4     400       280            3      5            3
##  5  1212 Zona …     1       5     260        90            1      2            3
##  6  1724 Zona …     1       5     240        87            1      3            3
##  7  2326 Zona …     1       4     220        52            2      2            3
##  8  4386 Zona …     1       5     310       137            2      3            4
##  9  1209 Zona …     2       5     320       150            2      4            6
## 10  1592 Zona …     2       5     780       380            2      3            3
## # ℹ 8,312 more rows
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Teniendo en cuenta que la cantidad de faltantes para todas las columnas (excepto “parqueaderos y piso”) es poco representativo respecto al total, optamos por eliminar estas filas.

vivienda <- vivienda %>%
  filter(!is.na(id) & !is.na(zona) & !is.na(estrato) & 
         !is.na(preciom) & !is.na(areaconst) & 
         !is.na(banios) & !is.na(habitaciones) & 
         !is.na(tipo) & !is.na(barrio) & 
         !is.na(longitud))

Una vez completada la imputación, verificamos la cantidad de datos faltantes, lo que nos permite confirmar que la base de datos está limpia en términos de faltantes.

colSums(is.na(vivienda))
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0            0            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##            0            0            0            0            0            0 
##      latitud 
##            0
nrow(vivienda)
## [1] 8319
ncol(vivienda)
## [1] 13

Analisis Explotario:

library(summarytools)
descr(vivienda)
## Non-numerical variable(s) ignored: zona, tipo, barrio
## Descriptive Statistics  
## vivienda  
## N: 8319  
## 
##                     areaconst    banios   estrato   habitaciones        id   latitud   longitud
## ----------------- ----------- --------- --------- -------------- --------- --------- ----------
##              Mean      174.93      3.11      4.63           3.61   4160.00      3.42     -76.53
##           Std.Dev      142.96      1.43      1.03           1.46   2401.63      0.04       0.02
##               Min       30.00      0.00      3.00           0.00      1.00      3.33     -76.59
##                Q1       80.00      2.00      4.00           3.00   2080.00      3.38     -76.54
##            Median      123.00      3.00      5.00           3.00   4160.00      3.42     -76.53
##                Q3      229.00      4.00      5.00           4.00   6240.00      3.45     -76.52
##               Max     1745.00     10.00      6.00          10.00   8319.00      3.50     -76.46
##               MAD       84.51      1.48      1.48           1.48   3083.81      0.05       0.02
##               IQR      149.00      2.00      1.00           1.00   4159.00      0.07       0.02
##                CV        0.82      0.46      0.22           0.40      0.58      0.01       0.00
##          Skewness        2.69      0.93     -0.18           1.63      0.00      0.03       0.65
##       SE.Skewness        0.03      0.03      0.03           0.03      0.03      0.03       0.03
##          Kurtosis       12.91      1.13     -1.11           3.98     -1.20     -1.15       0.58
##           N.Valid     8319.00   8319.00   8319.00        8319.00   8319.00   8319.00    8319.00
##         Pct.Valid      100.00    100.00    100.00         100.00    100.00    100.00     100.00
## 
## Table: Table continues below
## 
##  
## 
##                     parqueaderos      piso   preciom
## ----------------- -------------- --------- ---------
##              Mean           1.69      3.55    433.90
##           Std.Dev           1.06      2.20    328.67
##               Min           1.00      1.00     58.00
##                Q1           1.00      2.00    220.00
##            Median           1.00      3.00    330.00
##                Q3           2.00      4.00    540.00
##               Max          10.00     12.00   1999.00
##               MAD           0.00      1.48    207.56
##               IQR           1.00      2.00    320.00
##                CV           0.63      0.62      0.76
##          Skewness           2.57      1.74      1.85
##       SE.Skewness           0.03      0.03      0.03
##          Kurtosis           9.93      3.17      3.67
##           N.Valid        8319.00   8319.00   8319.00
##         Pct.Valid         100.00    100.00    100.00
view(dfSummary(vivienda))
## Switching method to 'browser'
## Output file written: C:\Users\WH612PS\AppData\Local\Temp\Rtmpe6wa1l\file2b98345534a6.html

Analisis de Correlación

library(corrplot)
## corrplot 0.94 loaded
# Filtrar solo las variables numéricas
vivienda_numericas <- vivienda %>% select_if(is.numeric)

# Calcular la correlación solo con las variables numéricas
correlacion <- round(cor(vivienda_numericas), 1)

# Graficar la matriz de correlación con los números
corrplot(correlacion, 
         method = "color",      # Método de visualización
         number.cex = 0.5,     # Tamaño del texto de los números
         addCoef.col = "black", # Color de los números
         tl.col = "black",      # Color de las etiquetas de las variables
         tl.srt = 45)           # Rotación de las etiquetas

Del análisis de correlación podemos observar lo siguiente: El precio de las viviendas presenta una correlación positiva fuerte con el número de baños, parqueaderos, el área construida y el estrato. Esto significa que, a medida que aumentan estas características (atributos), el precio de las viviendas tiende a incrementarse, y viceversa.

Por otro lado, se observan correlaciones negativas e incluso una falta de correlación entre las variables de latitud, longitud y piso en relación con las demás variables del conjunto. En particular, el piso no se considera una variable determinante para el tipo de vivienda, pues no es claro si se refiere al número de piso (apto) y como se podria relacionar para el tipo de vivienda (casa).

////////////////////////////////////////////////////

1) Analisis de Componentes Principales

Para efectos del análisis unicamente se consideraron las variables: estrato, precio, area, parqueaderos, baños y habitaciones

vivienda1=vivienda[,c(4,5,6,7,8,9)]
vivienda1
## # A tibble: 8,319 × 6
##    estrato preciom areaconst parqueaderos banios habitaciones
##      <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1       3     250        70            1      3            6
##  2       3     320       120            1      2            3
##  3       3     350       220            2      2            4
##  4       4     400       280            3      5            3
##  5       5     260        90            1      2            3
##  6       5     240        87            1      3            3
##  7       4     220        52            2      2            3
##  8       5     310       137            2      3            4
##  9       5     320       150            2      4            6
## 10       5     780       380            2      3            3
## # ℹ 8,309 more rows
viviendaZ=scale(vivienda1)
head(vivienda1)
## # A tibble: 6 × 6
##   estrato preciom areaconst parqueaderos banios habitaciones
##     <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1       3     250        70            1      3            6
## 2       3     320       120            1      2            3
## 3       3     350       220            2      2            4
## 4       4     400       280            3      5            3
## 5       5     260        90            1      2            3
## 6       5     240        87            1      3            3

En primer lugar realizamos el análisis de componentes principales y posteriormente calculamos las desviaciones estandar de los componentes principales

Grafico de sedimentación

#Análisis de PCA
res.pca<-prcomp(viviendaZ)
#Análisis de desviación estandar
res.pca$sdev
## [1] 1.8547043 1.1091831 0.7140783 0.6275200 0.4888913 0.4325284
#La suma de los valores propios (lambda) nos da el número de variables en el análisis
sum(res.pca$sdev^2)
## [1] 6
#Porcentaje de variabilidad explicada
install.packages("factoextra")
library (factoextra)
fviz_eig(res.pca,addlabels=TRUE)

Analisis del grafico de sedimentación:

A partir del grafico, podemos concluir que la primera dimensión (componente principal) explica gran parte de la varianza total (57.3%), lo que indica que es la más importante y captura la mayor cantidad de información sobre los datos. Ahora bien, la segunda dimensión explica un 20.5% de la variabilidad y la tercera el 8.5%. De esta forma,podriamos concluir que con solo el primer componente puede resumir más de la mitad de la variabilidad que contiene la base de datos, si a este se auna el segundo componente nos da casi el 80%; un valor bastante representativo de la varianza total.

Obtenemos la matriz de cargas variables; es decir la matriz cuyas columnas contienen los vectores propios

res.pca$rotation
##                    PC1        PC2         PC3         PC4        PC5        PC6
## estrato      0.3183109 -0.5988998  0.55055006  0.06468313 -0.4483827  0.1779352
## preciom      0.4777762 -0.2163769 -0.06437327 -0.29604355  0.2009128 -0.7699087
## areaconst    0.4457009  0.2182730 -0.26498862 -0.66631079 -0.2239362  0.4351679
## parqueaderos 0.4157888 -0.2045393 -0.65028489  0.58154880 -0.0983311  0.1206023
## banios       0.4647057  0.1804038  0.36797082  0.19497491  0.6930022  0.3127832
## habitaciones 0.2879708  0.6873683  0.25349316  0.29663112 -0.4674597 -0.2717173
#Combinaciones lineales de las variables escaladas
scores<-res.pca$x

Gráfico de contribución de variables al componente:

fviz_contrib(res.pca,choice="var",axes=1)

fviz_contrib(res.pca,choice="var",axes=2)

fviz_contrib(res.pca,choice="var",axes=3)

Análisis del grafico de contribución de variables:

DIM-1: Según lo que se observa en el gráfico, se puede concluir que, por encima de la línea roja discontinua, que representa el 11% del umbral de contribución, las variables más relevantes en relación con la contribución de la dimensión 1 son el precio, el número de baños, el área construida y la cantidad de parqueaderos. DIM-2: Ahora bien, para la dimensión 2, podemos observar que las variables que mas contribuyen son las habitaciones y el estrato. DIM-3: Finalmente, para la dimensión 3, las variables que tienen una mayor contribución son los parqueaderos y el estrato

Círculo de de correlación (nube de variables):

fviz_pca_var(res.pca,
             col.var="contrib",
             gradient.cols=c("#FF7F00","#034D94"),
             axes=c(1,2),
             repel=TRUE
             )

Análisis del grafico de componentes principales: Los vectores que representan las variables (habitaciones, areaconst, baños, parqueaderos, precio, y estrato) están distribuidos de manera que algunos están más alejados del origen, indicando una mayor contribución a las dimensiones principales.

La dirección de cada vector indica la relación entre las variables. Por ejemplo, “habitaciones” tiene una dirección clara hacia el cuadrante positivo de Dim1, sugiriendo que a medida que aumenta el número de habitaciones, también se incrementa la varianza en esa dimensión. Patrones Notables

Frente a las correlaciones, se puede observar que los “baños”, “habitaciones” y “area construida” parecen estar correlacionadas positivamente. Mientras que la variable “precio” parece estar en una dirección relacionada con otras variables como “estrato” y “parqueaderos”, sugiriendo que el precio podría estar influenciado por el estrato socioeconómico y la disponibilidad de parqueaderos. De igual forma se observa una independencia o correlación nula entre estrato y habitaciones.

Estrato parece estar más cerca del origen, indicando que su contribución a la varianza total es menor en comparación con otras variables.

a<-fviz_pca_ind(res.pca,axes=c(1,2),col.ind="blue")
print(a)

La gráfica muestra que no hay una clara separación entre los puntos en función de las dimensiones. Esto puede indicar que no hay grupos bien definidos en los datos, o que la variabilidad no se agrupa de manera evidente en las dos dimensiones analizadas. Aunque no se observan agrupaciones claras, se podría realizar un análisis adicional (como clustering) para identificar si existen subgrupos dentro de los datos que no son evidentes a simple vista.

////////////////////////////////////////////////////////

2) Análisis de Conglomerados

Para el análisis de clustering, tomamos las variables zona, estrato, precio, area construida, parqueaderos, baños, habitaciones y tipo

vivienda_3<-vivienda[,c(2,4,5,6,7,8,9,10)]

Posteriormente, codificamos la variable zona y tipo, entendiendo que para posteriores análisis; como Clustering por KNN Mean, es necesario que contemos con variables númericas para poder aplicar los algoritmos.

Codificar la variable zona:

vivienda_3 <- vivienda_3 %>% mutate(zona = replace(zona, 
                                               zona == "Zona Centro", 1))
vivienda_3<- vivienda_3 %>% mutate(zona = replace(zona, 
                                               zona == "Zona Norte", 2))
vivienda_3 <- vivienda_3 %>% mutate(zona = replace(zona, 
                                               zona == "Zona Oeste", 3))
vivienda_3 <- vivienda_3 %>% mutate(zona = replace(zona, 
                                               zona == "Zona Oriente",
                                               4))
vivienda_3<- vivienda_3 %>% mutate(zona = replace(zona, 
                                               zona == "Zona Sur", 5))
vivienda_3$zona <- as.numeric(vivienda_3$zona)

Codificar la variable tipo:

vivienda_3 <- vivienda_3 %>% mutate(tipo = replace(tipo, 
                                               tipo == "Casa", 1))
vivienda_3 <- vivienda_3 %>% mutate(tipo = replace(tipo, 
                                               tipo == "Apartamento", 2))
vivienda_3$tipo <- as.numeric(vivienda_3$tipo)

Estandarizamos las variables de tal forma que no se vean afectadas los cálculos de las distancias

vivienda3c<-scale(vivienda_3)

Método del Codo

wss <- numeric(10)  
for (k in 1:10) {
  kmeans_model <- kmeans(vivienda3c, centers = k, nstart = 10)
  wss[k] <- kmeans_model$tot.withinss
}

# Graficar el resultado
ggplot(data.frame(Clusters = 1:10, WSS = wss), aes(x = Clusters, y = WSS)) +
  geom_line() +
  geom_point() +
  labs(title = "Método del Codo", x = "Número de Clusters", y = "Suma de Errores Cuadráticos (WSS)")

Al observar la gráfica, se puede identificar que la tasa de disminución de la WSS se estabiliza alrededor de 4 o 5 clústeres, lo que sugiere que este es el número óptimo para dividir los datos sin sobreajustar el modelo.

Gráfico de GAP para determinación de la cantidad de clusters.

# Definir el número máximo de clusters a probar
max_clusters <- 10

# Inicializar vectores para almacenar los resultados
gap_values <- numeric(max_clusters)
wss_original <- numeric(max_clusters)
wss_random <- numeric(max_clusters)

# Calcular WSS para diferentes números de clusters
for (k in 1:max_clusters) {
  # WSS para los datos originales
  kmeans_model <- kmeans(vivienda3c, centers = k, nstart = 10)
  wss_original[k] <- kmeans_model$tot.withinss
  
  # Generar un conjunto de datos aleatorio
  random_data <- matrix(runif(nrow(vivienda3c) * ncol(vivienda3c)), nrow = nrow(vivienda3c))
  
  # WSS para los datos aleatorios
  kmeans_random <- kmeans(random_data, centers = k, nstart = 10)
  wss_random[k] <- kmeans_random$tot.withinss
  
  # Calcular el Gap
  gap_values[k] <- log(wss_random[k]) - log(wss_original[k])
}

# Crear un data frame para graficar
gap_df <- data.frame(Clusters = 1:max_clusters, Gap = gap_values)

# Graficar los resultados
ggplot(gap_df, aes(x = Clusters, y = Gap)) +
  geom_line() +
  geom_point() +
  labs(title = "Método del Gap", x = "Número de Clusters", y = "Gap") +
  theme_minimal()

options(warn = -1)

Para el análisis de GAP se debe buscar el punto donde el Gap alcanza su máximo o donde la tasa de cambio comienza a disminuir. En este caso, el Gap sigue aumentando, pero el crecimiento es más lento después de un cierto número de clusters. Esto sugiere que el número óptimo de clusters podría estar entre 3 y 5. A pesar de que el GAP sigue aumentando , se podrían explorar más de 5 clusters, pero se debe tener en cuenta que agregar más clusters puede no proporcionar una mejora significativa en la interpretación o utilidad de los resultados.

Conclusión:

Teniendo en cuenta los resultados arrojados por los 2 métodos de validación del número de grupos/clusteres, seleccionamos 4 para efectos del análisis, pues es el promedio generado de ambos graficos.

Aplicación de K Means

set.seed(150)
modelo_kmeans <- kmeans(vivienda3c, 4) # Ajuste
vivienda3c <- data.frame(vivienda3c,
                             modelo_kmeans$cluster) # Cluster
aggregate(vivienda_3,
          by = list(vivienda3c$modelo_kmeans.cluster),
          FUN = median) # Medianas  
##   Group.1 zona estrato preciom areaconst parqueaderos banios habitaciones tipo
## 1       1    5       4     350       200            1      3            4    1
## 2       2    3       6     560       151            2      4            3    2
## 3       3    5       4     215        75            1      2            3    2
## 4       4    5       6     950       400            4      5            5    1

Los grupos 1, 3 y 4 tienen se encuentran en la zona 5, mientras que el grupo 2 tiene una zona de 3. Esto podría indicar que los grupos 1, 3 y 4 están ubicados en una zona más similar, mientras que el grupo 2 se encuentra en una zona diferente. En cuanto al estrato, el grupo 2 tiene un estrato de 6, mientras que los grupos 1 y 3 tienen un estrato de 4, y el grupo 4 tiene un estrato de 6. Esto sugiere que el grupo 2 podría estar asociado a un nivel socioeconómico diferente. Precio:

El precio de los inmuebles varía significativamente entre los grupos. El grupo 4 tiene el precio más alto (950), seguido por el grupo 2 (560), el grupo 1 (350) y el grupo 3 (215). Esto puede indicar que el grupo 4 tiene propiedades de mayor valor, posiblemente debido a su ubicación o características. Área Construida:

El área construida también varía entre los grupos. El grupo 4 tiene el área construida más grande (400), mientras que el grupo 3 tiene la más pequeña (75). Esto puede correlacionarse con el precio, ya que generalmente, un área construida mayor puede estar asociada a un precio más alto. Parqueaderos, Baños y Habitaciones:

El número de parqueaderos, baños y habitaciones también varía entre los grupos. Por ejemplo, el grupo 4 tiene más parqueaderos (4) y baños (5), lo que podría indicar que las propiedades en este grupo son más espaciosas o lujosas. En contraste, el grupo 3 tiene menos parqueaderos (1) y baños (2), lo que podría indicar propiedades más pequeñas o menos equipadas. Tipo:

El tipo de propiedad también parece variar entre los grupos. El grupo 1 tiene un tipo de 1, mientras que el grupo 2 tiene un tipo de 2, y los grupos 3 y 4 tienen un tipo de 1. Esto puede indicar diferentes clasificaciones de propiedades (por ejemplo, apartamentos, casas, etc.).

Cluster plot:

fviz_cluster(list(data = vivienda3c[,1:7], 
                  cluster = vivienda3c$modelo_kmeans.cluster),
             palette = c("#cd1076",  "#8deeee", "#00FF00","#FFA500"),
             ellipse.type = "convex",repel = F, 
             show.clust.cent = FALSE, ggtheme = theme_minimal())

Análisis del gráfico de dispersión:

En el gráfico de dispersión, se pueden observar claramente los 4 grupos identificados en el análisis de k-means. Cada color en el gráfico representa uno de estos grupos, lo que confirma la segmentación en 4 categorías distintas basada en las características analizadas.

La variación en el precio de los inmuebles entre los grupos también puede observarse en el gráfico. El grupo 4, que tiene el precio más alto (950), esta representado en el costado izquierdo, mientras que el grupo 3, con el precio más bajo (215), se encuentra en el otro costado.

///////////////////////////////////////////////////////////////////////////////////

3) Analisis de Correspondencia

vivienda2=vivienda[,c(2,10,11)]
head(vivienda2)
## # A tibble: 6 × 3
##   zona         tipo        barrio     
##   <chr>        <chr>       <chr>      
## 1 Zona Oriente Casa        20 de julio
## 2 Zona Oriente Casa        20 de julio
## 3 Zona Oriente Casa        20 de julio
## 4 Zona Sur     Casa        3 de julio 
## 5 Zona Norte   Apartamento acopi      
## 6 Zona Norte   Apartamento acopi

3.1.) Analisis de correspondencia Zona vs Tipo

En primer lugar analizamos la relación entre la variable zona y tipo. Para ello, generamos la tabla de contigencia y aplicamos la prueba chi cuadrado, para averiguar la independencia entre las variables:

tabla1<-table(vivienda2$tipo,vivienda2$zona)
print(tabla1)
##              
##               Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
##   Apartamento          24       1198       1029           62     2787
##   Casa                100        722        169          289     1939
#Prueba chi cuadrado
#H0:Zona vs Tipo son independientes
#H1: Zona vs Tipo son dependientes
chisq.test(tabla1)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla1
## X-squared = 690.93, df = 4, p-value < 2.2e-16

El resultado indica que se rechaza la hipótesis de independencia de las variables (p-value: 0.0000), indicando grado tipo de relación entre ellas.

tabla1<-as.data.frame(table(vivienda2$zona,vivienda2$tipo))
colnames(tabla1)<-c("Zona","Tipo","Frecuencia")

#Convertir a proporciones para un grafico de barras apiladas normalizado
tabla1$Proporcion <- with(tabla1, Frecuencia / sum(Frecuencia))
tabla1
##            Zona        Tipo Frecuencia  Proporcion
## 1   Zona Centro Apartamento         24 0.002884962
## 2    Zona Norte Apartamento       1198 0.144007693
## 3    Zona Oeste Apartamento       1029 0.123692752
## 4  Zona Oriente Apartamento         62 0.007452819
## 5      Zona Sur Apartamento       2787 0.335016228
## 6   Zona Centro        Casa        100 0.012020676
## 7    Zona Norte        Casa        722 0.086789278
## 8    Zona Oeste        Casa        169 0.020314942
## 9  Zona Oriente        Casa        289 0.034739752
## 10     Zona Sur        Casa       1939 0.233080899

Grafico de barras apiladas:

#Crear grafico manualmente con ggplot2
library(ggplot2)
ggplot(tabla1, aes(x = Zona, y = Proporcion, fill = Tipo)) +
  geom_bar(stat = "identity", position = "fill") +  # Corrección en las comillas
  scale_fill_manual(values = c("blue", "red")) +
  coord_flip() +
  labs(title = "Tipos de vivienda por Zona",  # Corrección de 'Title' a 'title'
       x = "Tipo de vivienda",
       y = "Proporción",
       fill = "Tipo") +
  theme_minimal()

Analisis del grafico de barras apiladas:

El grafico nos permite analizar las siguiente situaciones: en primer lugar, el tipo de vivienda Apartamento es predominante en la Zona Oeste, Zona Norte y Zona Sur, mientras que para las Casas, se observa una mayor predominancia en la Zona Centro y Zona Oriente.

Análisis de correspondencias:

3.2.) Correspondencia entre Zona, Tipo y Estrato

library(FactoMineR)
library(factoextra)
library(dplyr)

# Seleccionamos la columna "Zona", "Tipo" y "Estrato"
mca_data <- vivienda %>%
  select("zona","tipo","estrato") %>%
  mutate(across(everything(), as.factor))

# Realizamos el análisis de correspondencia múltiple
mca_result <- MCA(mca_data, graph = TRUE)

mca_result
## **Results of the Multiple Correspondence Analysis (MCA)**
## The analysis was performed on 8319 individuals, described by 3 variables
## *The results are available in the following objects:
## 
##    name              description                       
## 1  "$eig"            "eigenvalues"                     
## 2  "$var"            "results for the variables"       
## 3  "$var$coord"      "coord. of the categories"        
## 4  "$var$cos2"       "cos2 for the categories"         
## 5  "$var$contrib"    "contributions of the categories" 
## 6  "$var$v.test"     "v-test for the categories"       
## 7  "$var$eta2"       "coord. of variables"             
## 8  "$ind"            "results for the individuals"     
## 9  "$ind$coord"      "coord. for the individuals"      
## 10 "$ind$cos2"       "cos2 for the individuals"        
## 11 "$ind$contrib"    "contributions of the individuals"
## 12 "$call"           "intermediate results"            
## 13 "$call$marge.col" "weights of columns"              
## 14 "$call$marge.li"  "weights of rows"

El gráfico nos permite establecer las siguientes relaciones: 1)El estrato 6 se encuentra ubicado en la Zona Oeste y el tipo de vivienda predominante en este sector son los Apartamentos. 2) El estrato 3 se encuentra en la Zona Oriente y Centro y tiende a predominar mayoritariamente el tipo Casa. 3) El estrato 4 y 5 estan ubicados principalmente en la Zona Norte y Sur. 4) El tipo de vivienda “Casa” se encuentra más cerca de la Zona Norte, lo que sugiere que en esta zona es más común encontrar casas. Mientras que en la Zona Sur pueden ser mas comunes los tipos Apartamntso. 5) De igual forma se puede observar que la Zona Oriente y la Zona Centro comparten caracteristicas similares. Al igual que la Zona Sur y Norte, pues los puntos se encuentran cercanos entre si. La Zona Oeste, puede ser una región que poco comparte simulitud con las otras Zonas.

3.3) Correspondencia entre la Zona vs Barrios (Top 5):

library(dplyr)
library(FactoMineR)  # Asegúrate de tener este paquete para MCA

barrios_seleccionados <- c("valle del lili", "ciudad jardín", "pance", "la flora", "santa teresita")  

mca_data <- vivienda %>%
  filter(barrio %in% barrios_seleccionados) %>%  # Filtrar los barrios específicos
  select("barrio", "zona") %>%
  mutate(across(everything(), as.factor))

mca_result <- MCA(mca_data, graph = TRUE)

mca_result
## **Results of the Multiple Correspondence Analysis (MCA)**
## The analysis was performed on 2561 individuals, described by 2 variables
## *The results are available in the following objects:
## 
##    name              description                       
## 1  "$eig"            "eigenvalues"                     
## 2  "$var"            "results for the variables"       
## 3  "$var$coord"      "coord. of the categories"        
## 4  "$var$cos2"       "cos2 for the categories"         
## 5  "$var$contrib"    "contributions of the categories" 
## 6  "$var$v.test"     "v-test for the categories"       
## 7  "$var$eta2"       "coord. of variables"             
## 8  "$ind"            "results for the individuals"     
## 9  "$ind$coord"      "coord. for the individuals"      
## 10 "$ind$cos2"       "cos2 for the individuals"        
## 11 "$ind$contrib"    "contributions of the individuals"
## 12 "$call"           "intermediate results"            
## 13 "$call$marge.col" "weights of columns"              
## 14 "$call$marge.li"  "weights of rows"

Análisis de la gráfica: En relación con el análisis de la gráfica, se puede observar que el barrio Santa Teresita se ubica en la Zona Oeste, mientras que la Flora se encuentra en la Zona Norte. En el caso de los barrios Pance, Ciudad Jardín y Valle de Lili, se presenta una situación particular, ya que estos barrios están muy próximos a la Zona Oriente y la Zona Sur. Esta proximidad podría sugerir un posible error en la parametrización de los datos, ya que no están claramente asignados a una zona específica, a diferencia de lo que se puede validar para la Flora y Santa Teresita.

Es importante señalar que esta observación es una percepción inicial, basada en la visualización de los datos.

3.4) Grado de representatividad - Zona vs Tipo

library(FactoMineR)
library(factoextra)
tablac<-table(vivienda2$zona,vivienda2$tipo)
resultados_ac <- CA(tablac)
valores_prop <-resultados_ac$eig ; valores_prop
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.08305442                    100                               100
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?

A partir del análisis de la gráfica, podemos observar que la primera dimensión del análisis explica el 100% de la varianza, lo que sugiere que es suficiente para capturar la variabilidad en los datos, simplificando la interpretación de los resultados.

3.5 Grado de representatividad - Zona vs Barrio

library(FactoMineR)
library(factoextra)
tablac<-table(vivienda2$zona,vivienda2$barrio)
resultados_ac <- CA(tablac)

valores_prop <-resultados_ac$eig ; valores_prop
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1  0.9619479               27.27168                          27.27168
## dim 2  0.9298275               26.36105                          53.63272
## dim 3  0.8951910               25.37909                          79.01181
## dim 4  0.7403118               20.98819                         100.00000
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")

La primera dimensión (dim 1) explica aproximadamente el 27.27% de la varianza total. La segunda dimensión (dim 2) explica un 26.36%, lo que significa que juntas las dos primeras dimensiones explican más de la mitad (53.63%) de la varianza total. No obstante, es un porcentaje pequeño, entendiendo que deberia ser superior al 80%, por tal razón se recomendaría incluir la tercera dimensión, pues asi se llevaría a un total del 79,01% de la explicación de la varianza total.

3.6 Grado de representatividad - Tipo vs Barrio

library(FactoMineR)
library(factoextra)
tablac<-table(vivienda2$tipo,vivienda2$barrio)
resultados_ac <- CA(tablac)
valores_prop <-resultados_ac$eig ; valores_prop
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1  0.2967032                    100                               100
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?

///////////////////////////////////////////////////////////////////////////////////

4) Conclusiones finales

4.1.Análisis de Componentes Principales

A partir del análisis presentado, se pueden extraer conclusiones clave que guiarán las decisiones estratégicas de la empresa inmobiliaria. En primer lugar, la primera dimensión (componente principal) es fundamental, ya que explica el 57.3% de la varianza total. Esto indica que es crucial para entender los datos y que las variables más relevantes en esta dimensión son el precio, el número de baños, el área construida y la cantidad de parqueaderos. Además, la combinación de la primera y segunda dimensión explica casi el 80% de la variabilidad, lo que sugiere que centrar las estrategias en estas dimensiones puede ser muy efectivo.

Las variables que contribuyen significativamente a la segunda dimensión son las habitaciones y el estrato, mientras que en la tercera dimensión, los parqueaderos y el estrato son las más relevantes. Esto indica que el número de habitaciones y el estrato socioeconómico son factores importantes a considerar en la estrategia de la empresa. Asimismo, se observa una correlación positiva entre baños, habitaciones y área construida, lo que sugiere que estos factores están interrelacionados. Por otro lado, el precio parece estar influenciado por el estrato y la disponibilidad de parqueaderos, lo que resalta la importancia de estos elementos en la fijación de precios.

Con base en estas conclusiones, se recomienda que la empresa se enfoque en optimizar las características relacionadas con la primera dimensión, como el precio, los baños, el área construida y los parqueaderos en sus propiedades. Además, es fundamental considerar la segmentación del mercado basada en la zona y el estrato, lo que permitirá personalizar las ofertas y estrategias de marketing para diferentes grupos de clientes. También se sugiere realizar un análisis más profundo sobre cómo el estrato y la disponibilidad de parqueaderos afectan el precio de las propiedades, lo que puede ayudar a establecer precios más competitivos y atractivos para los compradores.

Asimismo, la empresa debería invertir en propiedades que ofrezcan un número adecuado de baños y parqueaderos, ya que estas características son altamente valoradas por los compradores. Es crucial mantener un monitoreo constante de las tendencias del mercado inmobiliario, especialmente en relación con las variables que más contribuyen a la variabilidad, para ajustar las estrategias de manera proactiva. Por último, considerar campañas de educación para los clientes sobre la importancia de las características de las propiedades, como los parqueaderos y el estrato, puede influir positivamente en sus decisiones de compra. Al implementar estas recomendaciones, la empresa inmobiliaria puede mejorar su posicionamiento en el mercado y maximizar su rentabilidad.

4.1.Análisis de Conglomerados Con base en el análisis de los grupos de propiedades y sus características, la inmobiliaria podría considerar varias decisiones estratégicas para optimizar su posicionamiento en el mercado. En primer lugar, es fundamental implementar una segmentación del mercado que permita identificar y clasificar a los diferentes grupos de clientes según sus necesidades y preferencias. Esto facilitará el desarrollo de estrategias de marketing específicas para cada segmento, asegurando que la oferta se ajuste a las expectativas de los compradores.

Además, la inmobiliaria debería enfocarse en el desarrollo de proyectos en zonas estratégicas, como la zona 5, donde se encuentran los grupos 1, 3 y 4. Esta área parece ser más homogénea y posiblemente más deseable, lo que representa una oportunidad para construir propiedades que ofrezcan características atractivas, como áreas comunes y servicios adicionales. Al mismo tiempo, es importante revisar la estrategia de precios, especialmente para el grupo 2, que se ubica en una zona menos deseable pero tiene un estrato más alto. Ajustar los precios en función de la demanda del mercado y las características de cada grupo permitirá que la inmobiliaria se mantenga competitiva.

La diversificación de la oferta de propiedades también es clave. La inmobiliaria podría considerar incluir diferentes tipos de inmuebles que se adapten a las necesidades de los distintos segmentos de mercado, desde propiedades más lujosas y espaciosas en el grupo 4 hasta opciones más asequibles y compactas en el grupo 3. Además, mejorar las características de las propiedades, especialmente en aquellos grupos que tienen menos parqueaderos, baños y habitaciones, podría aumentar su atractivo y valor en el mercado.