# Librerias a Utilizar
# install.packages("devtools") # solo una vez
# devtools::install_github("dgonxalex80/paqueteMETODOS") 
library(paqueteMETODOS)
library(dplyr)
library(ggplot2)
library(gridExtra)
library(ggfortify)
library(mice)
library(factoextra)
library(tidyverse)
library(cluster)
library(tidyr)
library(ade4)
library(FactoMineR)
library(naniar)
library(patchwork)
library(summarytools)
library(sf)
library(leaflet)
library(leaflet.extras)
library(htmlwidgets)

# Se importa la base de datos
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")=
##   .. cols(
##   ..   id = col_double(),
##   ..   zona = col_character(),
##   ..   piso = col_character(),
##   ..   estrato = col_double(),
##   ..   preciom = col_double(),
##   ..   areaconst = col_double(),
##   ..   parqueaderos = col_double(),
##   ..   banios = col_double(),
##   ..   habitaciones = col_double(),
##   ..   tipo = col_character(),
##   ..   barrio = col_character(),
##   ..   longitud = col_double(),
##   ..   latitud = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>

Al cargar la base de datos se logra ver que, esta cuenta con 8322 registros u observaciones y 13 atributos los cuales se pueden clasificar de tipo cualitativa y de tipo cuantitativa, dentro de las cuantitativas encontramos 9 variables las cuales son: el ID o identificador de la vivienda, el piso, el estrato, el precio de la vivienda, el area construida, el numero de parqueaderos con que cuenta la vivienda, el numero de baños, el numero de habitaciones, y las coordenadas geograficas de longitud y latitud, del lado de las cualitativas estan: la zona, el tipo de vivienda, el barrio y el piso. Aqui detectamos que la variable piso es numerica, sin embargo el sistema la reconoce como de tipo caracter por lo que sera necesario convertirla a numerica ya que puede generar problemas mas adelante.

1 Analisis Exploratorio

En esta primera parte el objetivo sera identificar si la base cuenta con datos faltantes

par(cex = 0.7, las = 1)
md.pattern(vivienda, rotate.names = TRUE) 

##      preciom id zona estrato areaconst banios habitaciones tipo barrio longitud
## 4808       1  1    1       1         1      1            1    1      1        1
## 1909       1  1    1       1         1      1            1    1      1        1
## 876        1  1    1       1         1      1            1    1      1        1
## 726        1  1    1       1         1      1            1    1      1        1
## 1          1  0    0       0         0      0            0    0      0        0
## 2          0  0    0       0         0      0            0    0      0        0
##            2  3    3       3         3      3            3    3      3        3
##      latitud parqueaderos piso     
## 4808       1            1    1    0
## 1909       1            1    0    1
## 876        1            0    1    1
## 726        1            0    0    2
## 1          0            0    0   12
## 2          0            0    0   13
##            3         1605 2638 4275
gg_miss_var(vivienda) # grafico de datos faltantes

vivienda2 <- na.omit(vivienda)

Como se puede observar en los graficos, las variables piso y parqueadero son las que mas datos faltantes tienen, con 2638 y 1605 cada una respectivamente y al momento de crear una nueva base de datos, eliminando las filas que no contienen esa informacion pasa de 8322 a 4808 observaciones, por lo que se esta perdiendo un 43% de la informacion, lo que hace que esta opcion no sea viable, una alternativa es reemplazar por la mediana de las variables donde hay faltantes.

# se convierte la variable piso de caracter a numerica para que al momento de rellenar con la mediana los datos faltantes se pueda realizar la operacion.
vivienda$piso <- as.numeric(vivienda$piso)

# Rellenar los valores faltantes con la mediana de cada columna
vivienda <- vivienda %>%
  mutate(across(everything(), ~ ifelse(is.na(.), median(., na.rm = TRUE), .)))

gg_miss_var(vivienda) # grafico de datos faltantes

par(cex = 0.7, las = 1)
md.pattern(vivienda, rotate.names = TRUE) 
##  /\     /\
## {  `---'  }
## {  O   O  }
## ==>  V <==  No need for mice. This data set is completely observed.
##  \  \|/  /
##   `-----'

##      id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## 8322  1    1    1       1       1         1            1      1            1
##       0    0    0       0       0         0            0      0            0
##      tipo barrio longitud latitud  
## 8322    1      1        1       1 0
##         0      0        0       0 0

Despues de haber reemplazado los datos faltantes por la mediana correspondiente a cada atributo, como se puede verificar en los 2 graficos, todas las variables no cuentas con datos faltantes.

summarytools::descr(vivienda)
## Descriptive Statistics  
## vivienda  
## N: 8322  
## 
##                     areaconst    banios   estrato   habitaciones        id   latitud   longitud
## ----------------- ----------- --------- --------- -------------- --------- --------- ----------
##              Mean      174.92      3.11      4.63           3.61   4160.00      3.42     -76.53
##           Std.Dev      142.94      1.43      1.03           1.46   2401.20      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   2081.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   6239.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   3082.33      0.05       0.02
##               IQR      149.00      2.00      1.00           1.00   4157.50      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.64      0.00      0.03       0.65
##       SE.Skewness        0.03      0.03      0.03           0.03      0.03      0.03       0.03
##          Kurtosis       12.92      1.13     -1.11           3.99     -1.20     -1.15       0.58
##           N.Valid     8322.00   8322.00   8322.00        8322.00   8322.00   8322.00    8322.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.87      3.53    433.87
##           Std.Dev           1.01      2.19    328.61
##               Min           1.00      1.00     58.00
##                Q1           1.00      2.00    220.00
##            Median           2.00      3.00    330.00
##                Q3           2.00      4.00    540.00
##               Max          10.00     12.00   1999.00
##               MAD           1.48      1.48    207.56
##               IQR           1.00      2.00    320.00
##                CV           0.54      0.62      0.76
##          Skewness           2.48      1.81      1.85
##       SE.Skewness           0.03      0.03      0.03
##          Kurtosis          10.58      3.36      3.67
##           N.Valid        8322.00   8322.00   8322.00
##         Pct.Valid         100.00    100.00    100.00

Del anterior resumen descriptivo podemos destacar que, la mayoria de las variables tienen una gran variabilidad en los datos, ya que si nos fijamos en el coeficiente de variacion (CV), casi todas las variables se encuentran por encima de 0.3 lo que me indica una alta heterogeneidad en la informacion, lo que me puede generar incertidumbre y difcultar la prediccion de mi variable de interes en este caso el precio de las viviendas. con base a esta alta dispersion en los datos, por tanto se recomienda no tener en cuenta la media como indicador de promedio, en cambio se puede utilizar la mediana el cual es un indicador mas robusto para este caso en particular.

Entonces basandonos en la mediana, se puede decir que el precio promedio en el que fueron vendidos la mayoria de la viviendas fue de 330 millones. aunque el 50% de las viviendas oscilaba entre 220 y 540 millones, pero tambien se encontraron caso particulares en el cual una vivienda fue vendida en un precio minimo de 58 millones y en el caso extremo un vivienda fue vendida en 1999 millones.

Si analizamos el Area construida promedio de las viviendas encontramos que fue de 123 metros cuadrados, el 50% de las viviendas oscilaban en 80 y 229 metros cuadrados, pero tambien se encontraron casos particulares en el cual una vivienda fue construida con tan solo 30 metros cuadrados y en el caso extremo con 1745 metros cuadrados.

# Gráficos de Dispersión para Relaciones entre el precio de la vivienda vs el area construida Segmentadas por Zona, Estrato y tipo de vivienda

# Gráfico de dispersión entre Metros Construidos y Precio por zona
scatter_plot_zona <- ggplot(vivienda, aes(x = areaconst, y = preciom, color = zona)) +
  geom_point(alpha = 0.6) +
  labs(title = "Area Construida Vs Precio por zona", x = "Area Construida", y = "Precio") +
  theme_minimal()

# Gráfico de dispersión entre Metros Construidos y Precio por Estrato
scatter_plot_estrato <- ggplot(vivienda, aes(x = areaconst, y = preciom, color = estrato)) +
  geom_point(alpha = 0.6) +
  labs(title = "Area Construia Vs Precio por Estrato", x = "Area Construida", y = "Precio") +
  theme_minimal()

# Gráfico de dispersión entre Número de Baños y Precio por zona
scatter_plot_tipo <- ggplot(vivienda, aes(x = areaconst, y = preciom, color = tipo)) +
  geom_point(alpha = 0.6) +
  labs(title = "Area construida Vs Precio por tipo de vivienda", x = "Area Construida", y = "Precio") +
  theme_minimal()

# Combinar gráficos
library(patchwork)

Graficos_combinados <-  (scatter_plot_zona + scatter_plot_estrato) / 
                  (scatter_plot_tipo)

Graficos_combinados

Continuando con el analisis exploratorio nos apoyamos en los grafico de dispersion, los cuales pueden revelar informacion relevante, por ejemplo en el primer grafico de dispersion de izquierda a derecha encontramos que en la Zona Oeste, las mayoria de las viviendas que fueron vendidas tienen entre 30 y 500 metros construidos y alcanzaron buenos precios de venta siguiendo una tendencia lineal y directamente proporcional al tamaño de la vivienda. Por otra parte destacamos que de todas las 5 zonas que tiene la ciudad de cali la Zona Oriental fue la que menor precio alcanzaron las viviendas a pesar de que tuvieron casas que tenian bastante metros construidos, por lo que se puede decir que en esta zona el tamaño de la casa no es consistente con el valor de venta de la vivienda.

Del ultimo grafico de dispersion el cual fue segmentado segun el tipo de vivienda, podemos observar que los apartamentos, tienen menos area construida que las casas, sin embargo alcanzan a obtener muy buenos precios de ventas, en comparacion con su contraparte, ya que se evidencia que hay casas que tienen bastante metros construidos sin embargo el precio de venta no es tan consistente con su tamaño.

# Gráfico de caja para Precio por zona
boxplot_price_zona <- ggplot(vivienda, aes(x = zona, y = preciom)) +
  geom_boxplot(aes(fill = zona), color = "black") +
  labs(title = "Caja del Precio por zona", x = "zona", y = "Precio") +
  theme_minimal() +
  theme(legend.position = "none")


# Gráfico de caja para Precio por Estrato
boxplot_price_estrato <- ggplot(vivienda, aes(x = factor(estrato), y = preciom)) +
  geom_boxplot(aes(fill = estrato), color = "black") +
  labs(title = "Caja del Precio por Estrato", x = "Estrato", y = "Precio") +
  theme_minimal() +
  theme(legend.position = "none")


# Gráfico de caja para Metros Construidos por zona
boxplot_met_construidos_zona <- ggplot(vivienda, aes(x = zona, y = areaconst)) +
  geom_boxplot(aes(fill = zona), color = "black") +
  labs(title = "Caja de Metros Construidos por zona", x = "zona", y = "Metros Construidos") +
  theme_minimal() +
  theme(legend.position = "none")


# Gráfico de caja para Metros Construidos por Estrato
boxplot_met_construidos_estrato <- ggplot(vivienda, aes(x = estrato, y = areaconst)) +
  geom_boxplot(aes(fill = factor(estrato)), color = "black") +
  labs(title = "Metros Construidos vs Estrato", x = "Estrato", y = "Metros Construidos") +
  theme_minimal() +
  theme(legend.position = "none")


Graficos_combinados2 <-  (boxplot_price_zona + boxplot_price_estrato) / 
                  (boxplot_met_construidos_zona + boxplot_met_construidos_estrato)

Graficos_combinados2

Siguiendo en el analisis exploratorio con los graficos de cajas, el primer grafico de izquierda a derecha en la parte superior, nos confirma lo que se habia encontrado en el grafico de dispersion y es que en la zona Oeste, es donde las casas alcanzan mayores precios, en cambio en la Zona oriental los precios fueron los mas bajos, por otra parte si se analiza el precio de las viviendas por estrato, se evidencia una tendencia directamente proporcional, es decir entre mas alto sea el estrato, las casas alcanzan un mayor precio.

Por ultimo si se analiza el area construida, en la zona del centro es donde se encuentran viviendas mas pequeñas, esto quizas por el poco espacio que se pueda encontrar disponible para construir, en cambio en la Zona Oriente, es donde las viviendas tienen mas metros construido, pero tal como se habia mencionado, el valor de las viviendas no es directamente proporcional a su tamaño en esta Zona.

summarytools::freq(vivienda$tipo, cumul = FALSE)    
## Frequencies  
## vivienda$tipo  
## Type: Character  
## 
##                     Freq   % Valid   % Total
## ----------------- ------ --------- ---------
##       Apartamento   5103     61.32     61.32
##              Casa   3219     38.68     38.68
##              <NA>      0                0.00
##             Total   8322    100.00    100.00
summarytools::freq(vivienda$zona, cumul = FALSE) 
## Frequencies  
## vivienda$zona  
## Type: Character  
## 
##                      Freq   % Valid   % Total
## ------------------ ------ --------- ---------
##        Zona Centro    124      1.49      1.49
##         Zona Norte   1920     23.07     23.07
##         Zona Oeste   1198     14.40     14.40
##       Zona Oriente    351      4.22      4.22
##           Zona Sur   4729     56.83     56.83
##               <NA>      0                0.00
##              Total   8322    100.00    100.00

Segun el Analisis de Frecuencia, se vendieron mas apartamentos que casas, con un 61.32% frente a un 38.68% respectivamente, por otra parte realizando el analisis por zonas, la zona en donde mas apartamentos se vendieron fue en la Zona Sur con 4729 unidades vendidas lo que representa un 56.83% en cambio la zona en donde menos unidades se vendieron fue en la zona del centro con tan solo 124 unidades lo cual representa un 1.49% del total de la base de datos.

Finalizando esta etapa exploratoria, acontinuacion iniciaremos la fase del Analisis de Componentes Principales.

2 Analisis De Componentes Principales

La tecnica que vamos a utilizar a continuacion es util para reducir las dimensiones de nuestra base de datos, con el fin de eliminar variables que se encuentren altamente correlacionadas evitando la redundancia de informacion, haciendo que el modelo que estamos a punto de construir sea mucho mas eficiente, hay que tener presente que, esta tecnica sera aplicada solo a las variables numericas y dentro de las variables numericas no se incluiran, el ID, Latitud y Longitud ya que estas variables no aportan informacion relevante para nuestro modelo, la variable estrato tampoco sera incluida, porque si bien es numerica, su intepretacion es de tipo categorica, ademas se dejara por fuera la variable preciom, ya que es nuestra variable dependiente y es nuestro objetivo predecir por lo que si se incluye puede afectar en el sesgo de la varianza de las variables independiente.

names(vivienda)
##  [1] "id"           "zona"         "piso"         "estrato"      "preciom"     
##  [6] "areaconst"    "parqueaderos" "banios"       "habitaciones" "tipo"        
## [11] "barrio"       "longitud"     "latitud"
vivienda1 = vivienda[,c("piso", "areaconst","parqueaderos", "banios", "habitaciones")]

Se le aplica Normalizacion a la base de datos, ya que como se habia evidenciado en el analisis exploratorio hecho en la primera parte, los datos presentaban una gran heterogeneidad y diferentes escalas entre variables, por lo que que la estandarizacion es un paso clave para poder hacer analisis de componentes principales

vivienda1z= scale(vivienda1)
summary(vivienda1z)
##       piso           areaconst        parqueaderos         banios        
##  Min.   :-1.1534   Min.   :-1.0138   Min.   :-0.8561   Min.   :-2.17883  
##  1st Qu.:-0.6969   1st Qu.:-0.6640   1st Qu.:-0.8561   1st Qu.:-0.77823  
##  Median :-0.2404   Median :-0.3632   Median : 0.1314   Median :-0.07792  
##  Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.00000  
##  3rd Qu.: 0.2161   3rd Qu.: 0.3784   3rd Qu.: 0.1314   3rd Qu.: 0.62238  
##  Max.   : 3.8683   Max.   :10.9841   Max.   : 8.0310   Max.   : 4.82419  
##   habitaciones    
##  Min.   :-2.4704  
##  1st Qu.:-0.4147  
##  Median :-0.4147  
##  Mean   : 0.0000  
##  3rd Qu.: 0.2706  
##  Max.   : 4.3821

2.1 Eleccion del numero de componentes

# eleccion grafica del numero de componentes principales
prcomp(vivienda1z)
## Standard deviations (1, .., p=5):
## [1] 1.6013855 0.9884425 0.8719521 0.6118385 0.5691213
## 
## Rotation (n x k) = (5 x 5):
##                     PC1         PC2         PC3           PC4        PC5
## piso          0.1676910 -0.95204369  0.21997641  0.0009680962  0.1307745
## areaconst    -0.5364755 -0.05532205 -0.06938924 -0.7337620092  0.4073230
## parqueaderos -0.4247542 -0.22165750 -0.72338741  0.4757597073  0.1442745
## banios       -0.5367912 -0.16714749  0.16636509 -0.0591573312 -0.8079233
## habitaciones -0.4642336  0.11611180  0.62914928  0.4813995094  0.3787227
res.pca <- prcomp(vivienda1z)
fviz_eig(res.pca, addlabels = TRUE)

El anterior grafico muestra la varianza explicada por cada componente y se observa que el PC1 captura una varianza del 51.3% seguido del PC2 que tiene una varianza del 19.5% y del PC3 con 15.2%, estos 3 componentes se puede decir que son los mas significativos debido al aporte que en conjunto hacen casi de un 86% de la varianza explicada que tiene la base de datos.

Dentro del analisis destacamos que en el primer componente las variables que mas aportan a la varianza del modelo son numero de baños, area construida y numero de parqueaderos hay que recalcar que el signo es negativo, por tanto se debe realizar una correlacion de este primer componente con la variable precio, con el fin de mejorar la interpretacion de los resultados.

# Extraer los scores de los componentes principales
scores <- as.data.frame(res.pca$x)  # pca_result$x contiene los scores

# Extraer el score del primer componente principal (PC1)
pc1_scores <- scores$PC1

# Extraer los precios de las viviendas
precio<- vivienda$preciom

# Suponiendo que tienes un vector 'precio' que contiene los precios de las viviendas
# Calcular la correlación entre PC1 y el precio de las viviendas
correlacion_pc1_precio <- cor(pc1_scores, precio)

# Mostrar el resultado
print(correlacion_pc1_precio)
## [1] -0.6964072

Segun los resultados de la correlacion entre el precio de la vivienda y el primer componente este dio negativo y como los signos de la variables que mas aportan en el modelo tambien son negativos, se puede concluir que entre mayor numero de baños, mayor area construida y mayor numero de parqueaderos tenga la vivienda, esta alcanzara un mayor precio de venta.

# Visualizacion en el plano caretasiano
fviz_pca_var(res.pca,
             col.var = "contrib", # Color by contributions to the PC
             gradient.cols = c("#FF7F00",  "#034D94"),
             repel = TRUE     # Avoid text overlapping
)

Tal como lo muestra el siguiente grafico podemos ver que las variables Area construida, baños y habitaciones tienen una alta contribución a la Dimension 1, por tanto pueden aportar mayor valor a la hora de alcanzar un precio mas alto en las viviendas, en su contraparte esta el numero de pisos, el cual está en el cuadrante positivo, pero si bien la correlacion con el precio de las viviendas dio negativo, lo que indica que entre mas numero de pisos este ubicada la vivienda, esto puede afectar de manera negativa al precio de está.

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

Como se logra evidenciar en este grafico las variables que mas tienen peso en los 2 componentes principales son piso, baños y area construida, en cambio parqueadero y habitaciones tienen menos relevancia.

datos<- rbind(vivienda1[1582,], 
vivienda1[5717,],
vivienda1[6516,],
vivienda1[1092,])

datos <- as.data.frame(datos)
rownames(datos) = c("Vivienda 1582","Vivienda 5717","Vivienda 6516","Vivienda 1092")
datos
##               piso areaconst parqueaderos banios habitaciones
## Vivienda 1582    4       836            8      9            5
## Vivienda 5717    3        84            1      0            0
## Vivienda 6516    9       480            4      6            5
## Vivienda 1092    9       120            2      0            0
casos1 <- rbind(res.pca$x[1582,1:2],res.pca$x[5717,1:2]) # CP1
rownames(casos1) = c("1582","5717")
casos1 <- as.data.frame(casos1)

casos2 <- rbind(res.pca$x[6516,1:2], res.pca$x[1092,1:2]) # CP2
rownames(casos2) = c("6516","1092")
casos2 <- as.data.frame(casos2)

fviz_pca_ind(res.pca, col.ind = "#DEDEDE", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07")) +
geom_point(data = casos1, aes(x = PC1, y = PC2), color = "red", size = 3) +
geom_point(data = casos2, aes(x = PC1, y = PC2), color = "blue", size = 3)

Tal como se puede observar en la grafica siguiente, se presentan 2 casos opuestos, de viviendas que fueron vendidas, en el caso # 1 compuesto por los puntos de color rojo, se encuentra el caso de la vivienda (1582) y la vivienda (5717), estas 2 viviendas se encuentran en polos opuestos, ya que la vivienda (1582) tiene mas area construida con 836 metros y la vivienda (1517) cuenta con tan solo 84 metros construidos, por lo que confirma lo que se habia mostrado en la parte de arriba, que la variable area construida, es un factor importante dentro del primer componente y que puede afectar significativamente el precio de las viviendas.

En el segundo caso se logra evidenciar lo mismo que en el primer caso, se encuentran las viviendas (6156) y (1092), la primera cuenta con 480 metros construidos y la segunda con tan solo 120 metros por eso se encuentran en direcciones opuestas en el plano de 2 dimensiones, aunque en menor medida que en el primer caso ya que la diferencias no es tan abismal.

fviz_pca_biplot(res.pca, 
repel = TRUE,
habillage = vivienda$tipo,
col.var = "#034A94", # Variables color
col.ind = c("#DEDEDE", "#034A94")  # Individuals color
)

Segun la grafica de biplot, se observa claramente que las casas identificadas con el color verde, logran estar asociadas con variables como, el Area construida, el numero de baños y el numero de habitaciones, variables que tiene mas influencia en el primer componente con una varianza del 51.3% y asociadas con menor numero de pisos, en cambio los apartamentos, suelen estar mas asociados con mayor numero de pisos, el cual tiene una influencia en el segundo componente con una varianza de 19.5% y menos asociados con las variables area construida, numero de baños y numero de habitaciones.

3 Analisis de Conglomerados

Acontinuacion realizaremos el analisis de conglomerados, el cual es una tecnica de aprendizaje no supervisado con el fin de realizar una segmentacion de las variables independientes y poder encontrar patrones o agrupamientos entre variables que no son tan facil de observar en el analisis exploratorio.

#Estimar el numero de clusters mediante el metodo wss
fviz_nbclust(vivienda1z, kmeans, method = "wss")

Tal como lo muestra la siguiente grafica, al aplicar el metodo del codo el numero de cluster optimo que podemos encontrar es 4 ya que apartir de alli, la pendiente de las lineas no cambia abruptamente y se vuelve mas plana.

set.seed(123)
# Aplicar K-means con el número óptimo de clusters
kmeans_mod <- kmeans(vivienda1z, centers = 4, nstart = 25)
vivienda1$cluster = as.factor(kmeans_mod$cluster)
table(vivienda1$cluster)
## 
##    1    2    3    4 
## 4247 1039 2313  723
colores <- c("#FFF68F", "#CAFF70", "#EEE0E5","#FFD39B")
ggplot(vivienda1, aes(x = factor(cluster))) +
  geom_bar(fill = colores) +  
  labs(title = "Distribucion de viviendas por cluster",
       x = "Numero de Cluster",
       y = "Cantidad de viviendas") +
  theme_minimal() +
  geom_text(stat='count', aes(label=..count..), vjust=-0.5)

Al aplicar Kmeans con 4 Cluster la segmentacion queda de la siguiente manera, se obtiene un primer cluster con 4247 viviendas, un segundo cluster con 1039 viviendas, un tercer cluster con 2313 viviendas y por ultimo un cluster con 723 viviendas

fviz_cluster(kmeans_mod, data = vivienda1z,
             geom = "point",
             ellipse.type = "convex",
             ggtheme = theme_minimal(),
             main = "Grafico segmentado")

# se crea una nueva base de datos para incluir la variable precio ya que esta no hacia parte de la base filtrada por ser la variable dependiente

vivienda3 = vivienda1
vivienda3$preciom = vivienda$preciom
vivienda3$cluster = kmeans_mod$cluster


# Resumen de características por cluster
cluster_summary <- vivienda3 %>%
  group_by(cluster) %>%
  summarise(
    precio= median(preciom, na.rm = TRUE),
    area = median(areaconst, na.rm = TRUE),
    baños = median(banios, na.rm = TRUE),
    habitaciones = median(habitaciones, na.rm = TRUE),
    parqueaderos = median(parqueaderos, na.rm = TRUE),
    piso = median(piso, na.rm = TRUE)
  )

print(cluster_summary)
## # A tibble: 4 × 7
##   cluster precio  area baños habitaciones parqueaderos  piso
##     <int>  <dbl> <dbl> <dbl>        <dbl>        <dbl> <dbl>
## 1       1    240    88     2            3            1     3
## 2       2    320    98     3            3            2     8
## 3       3    490   230     4            4            2     3
## 4       4    950   420     5            5            4     3

De lo anterior se puede decir que, el cluster numero 1 esta compuesto por las viviendas mas baratas, esto se debe a que en promedio el tamaño de las viviendas es mas pequeño con menor area construida, menor numero de baños, habitaciones y parqueaderos.

A pesar de que los cluster 2 y 3 tienen caracteristicas muy parecidas en cuanto al numero de baños, habitaciones y parqueadero, el precio de estos marca la diferencia ya que en el segundo cluster el precio promedio de las viviendas alcanza un valor de 320 millones en el cluster numero 3 el precio promedio alcanza un valor de 490 millones, esto se debe al tamaño de las casa ya que en este ultimo cluster el area construida en promedio es de 230 metros en cambio en el cluster numero 2, el area construida es de 98 metros cuadrados en promedio.

Por ultimo el cluster numero 4 se identifican las viviendas mas caras, esto se debe a que tienen en promedio mayor area construida, tienen en promedio mas baños, habitaciones y parqueadero.

Por tanto los Clusters van aumentando de menor a mayo en cuanto a tamaño y precio.

# Define los colores más intensos pero elegantes para cada clúster
colores_intensos <- c("#E41A1C", "blue", "#4DAF4A", "#984EA3")

# Crea el gráfico con colores personalizados
ggplot(vivienda3, aes(x = areaconst, y = preciom, color = as.factor(cluster))) +
  geom_point(size = 2) +
  labs(title = "Area construida vs Precio por Cluster",
       x = "Area construida", y = "Precio",
       color = "Cluster") +  # Cambia el título de la leyenda
  theme_minimal() +
  scale_color_manual(values = colores_intensos)

Este grafico confirma, el anterior analisis, en donde se evidencia que el precio de las viviendas se ve influenciado por el tamaño de estas y se logra ver que el cluster 4 tal como lo habiamos mencionado mas arriba es el cluster compuesto por casas de mayor tamaño y de mejor precio de venta, en su contraparte el cluster numero 1, son las casas que tienen menor tamaño construido y por ende son las mas baratas.

4 Analisis De Correspondencia

A continuacion se hara el Análisis de Correspondencia el cual sera utilizado para representar posibles asociaciones entre las variables categóricas, con el fin de establecer si existe, patrones o estructuras en los datos.

iniciaremos con las variables zona y el estrato

# se convierte la variable estrato que es numerica como una variable categorica
vivienda$estrato <- as.character(vivienda$estrato)
tabla_cruzada <- ctable(vivienda$zona, vivienda$estrato)
tabla_cruzada
## Cross-Tabulation, Row Proportions  
## zona * estrato  
## Data Frame: vivienda  
## 
## -------------- --------- -------------- -------------- -------------- -------------- ---------------
##                  estrato              3              4              5              6           Total
##           zona                                                                                      
##    Zona Centro              105 (84.7%)     14 (11.3%)      4 ( 3.2%)      1 ( 0.8%)    124 (100.0%)
##     Zona Norte              572 (29.8%)    407 (21.2%)    769 (40.1%)    172 ( 9.0%)   1920 (100.0%)
##     Zona Oeste               54 ( 4.5%)     84 ( 7.0%)    290 (24.2%)    770 (64.3%)   1198 (100.0%)
##   Zona Oriente              340 (96.9%)      8 ( 2.3%)      2 ( 0.6%)      1 ( 0.3%)    351 (100.0%)
##       Zona Sur              382 ( 8.1%)   1616 (34.2%)   1688 (35.7%)   1043 (22.1%)   4729 (100.0%)
##          Total             1453 (17.5%)   2129 (25.6%)   2753 (33.1%)   1987 (23.9%)   8322 (100.0%)
## -------------- --------- -------------- -------------- -------------- -------------- ---------------
tabla_cruzada2<-table(vivienda$zona, vivienda$estrato)
tabla_cruzada2
##               
##                   3    4    5    6
##   Zona Centro   105   14    4    1
##   Zona Norte    572  407  769  172
##   Zona Oeste     54   84  290  770
##   Zona Oriente  340    8    2    1
##   Zona Sur      382 1616 1688 1043
# Prueba X2 para determinar si existe o no una asociación significativa entre las variables
chisq.test(tabla_cruzada2)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla_cruzada2
## X-squared = 3831.8, df = 12, p-value < 2.2e-16

Segun el resultado de la prueba chi cuadrada, esta rechaza la hipotesis nula de que las variables son independientes, por tanto quiere decir que hay indicios de que hay una dependencia o asociacion entre la zona y el estrato.

# Análisis de correspondencia
resultados_ac <- CA(tabla_cruzada2)

resultados_ac
## **Results of the Correspondence Analysis (CA)**
## The row variable has  5  categories; the column variable has 4 categories
## The chi square of independence between the two variables is equal to 3831.81 (p-value =  0 ).
## *The results are available in the following objects:
## 
##    name              description                   
## 1  "$eig"            "eigenvalues"                 
## 2  "$col"            "results for the columns"     
## 3  "$col$coord"      "coord. for the columns"      
## 4  "$col$cos2"       "cos2 for the columns"        
## 5  "$col$contrib"    "contributions of the columns"
## 6  "$row"            "results for the rows"        
## 7  "$row$coord"      "coord. for the rows"         
## 8  "$row$cos2"       "cos2 for the rows"           
## 9  "$row$contrib"    "contributions of the rows"   
## 10 "$call"           "summary called parameters"   
## 11 "$call$marge.col" "weights of the columns"      
## 12 "$call$marge.row" "weights of the rows"

El siguiente mapa muestra visualmente los resultados de la tabla cruzada entre el estrato y la zona y segun lo que se observa se puede decir que la zona centro y la zona oriente pertenecen al estrato 3, la zona sur y Norte se encuentran los estratos 4 y 5 y por ultimo en la zona oeste es donde se ubica el estrato 6.

valores_prop <-resultados_ac$eig ; valores_prop
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.32216522              69.968477                          69.96848
## dim 2 0.12750077              27.690868                          97.65934
## dim 3 0.01077739               2.340655                         100.00000
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")

Los resultados indican que el primer eje resume el 70% de los datos prepresentados en el plano factorial, mientras que los dos primeros ejes resumen un 97.7% la varianza de los datos.

vivienda$estrato <- as.character(vivienda$estrato)
varcategoricas <- vivienda[, c("tipo", "zona", "estrato")]
resultados_ac2 <- MCA(varcategoricas)

Tal como se puede apreciar en las graficas la mayoria de los apartamentos vendidos se encuentran concentrados en la zona Sur, en cambio el mayor porcentaje de casas vendidas se encuentra ubicada en la zona Norte

5 Analisis Espacial

5.1 Mapa Cloropletico Segun el Precio de la Vivienda

# Leer el archivo Shapefile
mapacali <- st_read("C:/Users/HP/Downloads/mc_barrios/mc_barrios.shp")
## Reading layer `mc_barrios' from data source 
##   `C:\Users\HP\Downloads\mc_barrios\mc_barrios.shp' using driver `ESRI Shapefile'
## Simple feature collection with 335 features and 5 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 1054098 ymin: 860192.1 xmax: 1068492 ymax: 879000.7
## Projected CRS: MAGNA-SIRGAS / Cali urban grid
# saco un resumen descriptivo de la base de datos en busqueda de NA
summary(vivienda)
##        id           zona                piso          estrato         
##  Min.   :   1   Length:8322        Min.   : 1.000   Length:8322       
##  1st Qu.:2081   Class :character   1st Qu.: 2.000   Class :character  
##  Median :4160   Mode  :character   Median : 3.000   Mode  :character  
##  Mean   :4160                      Mean   : 3.527                     
##  3rd Qu.:6239                      3rd Qu.: 4.000                     
##  Max.   :8319                      Max.   :12.000                     
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  30.0   Min.   : 1.000   Min.   : 0.000  
##  1st Qu.: 220.0   1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 330.0   Median : 123.0   Median : 2.000   Median : 3.000  
##  Mean   : 433.9   Mean   : 174.9   Mean   : 1.867   Mean   : 3.111  
##  3rd Qu.: 540.0   3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1999.0   Max.   :1745.0   Max.   :10.000   Max.   :10.000  
##   habitaciones        tipo              barrio             longitud     
##  Min.   : 0.000   Length:8322        Length:8322        Min.   :-76.59  
##  1st Qu.: 3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median : 3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   : 3.605                                         Mean   :-76.53  
##  3rd Qu.: 4.000                                         3rd Qu.:-76.52  
##  Max.   :10.000                                         Max.   :-76.46  
##     latitud     
##  Min.   :3.333  
##  1st Qu.:3.381  
##  Median :3.416  
##  Mean   :3.418  
##  3rd Qu.:3.452  
##  Max.   :3.498
# Eliminar filas con valores faltantes en longitud y latitud
vivienda <- vivienda[complete.cases(vivienda$longitud, vivienda$latitud), ]


# Obtener la mediana de las coordenadas para centrar el mapa
origen <- c(median(vivienda$latitud), median(vivienda$longitud))

# Crear paletas de colores para precio 
palette_precio <- colorNumeric(palette = "Blues", domain = vivienda$preciom)


# Crear el mapa coroplético
mapa1 <- leaflet(vivienda) %>%
  setView(lng = median(vivienda$longitud), lat = median(vivienda$latitud), zoom = 12) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = 2,
    color = ~palette_precio(preciom),
    fillColor = ~palette_precio(preciom),  # Usar la misma paleta de colores para fillColor
    fillOpacity = 0.8,
    stroke = FALSE,
    popup = ~paste("Precio:", preciom)
  ) 

mapa1

Segun el mapa realizado se puede observar por el color azul intenso, que las viviendas que tienen mayor precio estan ubicadas en la zona sur, la cual comprende los estratos 5,6 y parte del 4 tambien se logra identificar que en la zona oeste de la ciudad las viviendas se venden a un buen precio puesto que alla tambien se encuentra ubicado el estrato 6 y tal como se habia identificado y mencionado en los analisis exploratorios al inicio la zona oriental es la que tiene los menores precios en las viviendas esto se puede ver graficamente por el color azul palido que presenta el mapa por esta zona.

5.2 Mapa Cloropletico Segun el Estrato de la Vivienda

# Crear paletas de colores para precio y estrato
palette_precio <- colorNumeric(palette = "Blues", domain = vivienda$preciom)
palette_estrato <- colorFactor(palette = "Set1", domain = vivienda$estrato)

# Crear el mapa combinando las dos variables
mapa2 <- leaflet(vivienda) %>%
  setView(lng = median(vivienda$longitud), lat = median(vivienda$latitud), zoom = 12) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = ~sqrt(preciom)/200,  # Tamaño según el precio, ajustado para visualización
    color = ~palette_estrato(estrato),  # Color según el estrato
    fillColor = ~palette_estrato(estrato),  # Color de relleno según el estrato
    fillOpacity = 0.7,
    stroke = TRUE,  # Añadir un contorno para mayor visibilidad
    weight = 1,
    popup = ~paste("Precio:", preciom, "<br>", "Estrato:", estrato)
  ) %>%
  addLegend("bottomright", pal = palette_estrato, values = ~estrato,
            title = "Estrato",
            opacity = 1)

# Mostrar el mapa
mapa2

Del anterior grafico podemos destacar que el estrato 6 se encuentra repartido entre 2 zonas, uno en la zona sur y otra parte ubicada en la zona oeste de la ciudad, tambien es interesante destacar, que la zona Norte de la ciudad que es donde en la mayoria de ciudades se encuentran las viviendas mas caras y de mayor estrato, para el caso de la ciudad de cali no aplica, ya que en el Norte se encuentra es el estrato 5 y 4, ademas las casas no son las mas costosas de la ciudad, quizas se deba a que existan muchas viviendas antiguas y la gente prefiera comprar en nuevas viviendas que destaquen por la modernidad de la construccion.

5.3 Mapa Cloropletico Por Clusters

vivienda$cluster<-vivienda1$cluster


# Crear paletas de colores para precio y cluster
palette_precio <- colorNumeric(palette = "Blues", domain = vivienda$preciom)
palette_cluster <- colorFactor(palette = "Set1", domain = vivienda$cluster)

# Crear el mapa combinando las dos variables
mapa3 <- leaflet(vivienda) %>%
  setView(lng = median(vivienda$longitud), lat = median(vivienda$latitud), zoom = 12) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = ~sqrt(preciom)/200,  # Tamaño según el precio
    color = ~palette_cluster(cluster),  # Color según el cluster
    fillColor = ~palette_cluster(cluster),  # Color de relleno según la cluster
    fillOpacity = 0.7,
    stroke = TRUE,  # Añadir un contorno para mayor visibilidad
    weight = 1,
    popup = ~paste("Precio:", preciom, "<br>", "cluster:", cluster)
  ) %>%
  addLegend("bottomright", pal = palette_cluster, values = ~cluster,
            title = "cluster",
            opacity = 1)

# Mostrar el mapa
mapa3

Segun lo observado en el mapa de Cluster, se puede evidenciar como se encuentra distribuida por casi toda la ciudad el cluster numero 1, el cual es el que tiene el mayor numero de viviendas vendidas con mas del 50% de la muestra, con lo precios mas bajos del mercado en promedio de 240 millones, si bien esta informacion es util para la compañia pues revela las preferencias de los consumidores por este tipo de edificaciones, tambien puede ser un arma de doble filo puesto que si muchas personas conocen de esta informacion, se daran cuenta que casi en cualquier parte de la ciudad pueden encontrar viviendas asequibles incluso en los estratos mas altos de la ciudad, haciendo que el precio de las viviendas en estos estratos disminuya, ya que descubran que pueden vivir en estos lugares tranquilos y de mayor comodida pero que se puede ajustar a un presupuesto mas limitado.

5.4 Mapa Cloropletico Segun La Zona de la Vivienda

# Crear paletas de colores para precio y zona
palette_precio <- colorNumeric(palette = "Blues", domain = vivienda$preciom)
palette_zona <- colorFactor(palette = "Set1", domain = vivienda$zona)

# Crear el mapa combinando las dos variables
mapa4 <- leaflet(vivienda) %>%
  setView(lng = median(vivienda$longitud), lat = median(vivienda$latitud), zoom = 12) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = ~sqrt(preciom)/200,  # Tamaño según el precio
    color = ~palette_zona(zona),  # Color según la zona
    fillColor = ~palette_zona(zona),  # Color de relleno según la zona
    fillOpacity = 0.7,
    stroke = TRUE,  # Añadir un contorno para mayor visibilidad
    weight = 1,
    popup = ~paste("Precio:", preciom, "<br>", "Zona:", zona)
  ) %>%
  addLegend("bottomright", pal = palette_zona, values = ~zona,
            title = "Zona",
            opacity = 1)

# Mostrar el mapa
mapa4

Del anterior mapa se observa que hay unos puntos de color que no corresponden al lugar geografico de la ciudad, por lo que se puede intuir que la base de datos contiene muchos errores de clasificacion a la hora de especificar correctamente la zona geografica, esto puede sesgar los resultados del modelo a la hora de predecir el precio de las viviendas teniendo en cuenta esta variable.

6 Recomendaciones

A la luz de los resultados hechos por todos los analisis empleados en la base de datos se realizaran las siguientes recomendaciones:

  • Segun el analisis exploratorio y el analisis de componentes principales un factor que influye bastante en el precio de las viviendas es el tamaño de las viviendas, puesto que se encontro que aquellas viviendas que tenian mas area construida, mas baños y mas habitaciones, estas alcanzaban un mayor precio, entonces se recomienda hacer enfasis en el tamaño de las edificaciones.

  • Tal como se evidencia en el analisis exploratorio y en los mapas, se observa que hay una tendencia positiva entre el estrato y el precio de las viviendas, aquellas viviendas que se encuentran ubicadas en los estratos mas altos, alcanzan los precios mas altos de ventas.

  • Para efectos de maximizar las ganancias de la inmobiliaria, se recomienda invertir en construcciones y viviendas que se encuentre en la zona sur y la zona oeste ya que se identifico a travez de los mapas y los analisis exploratorio, que en estos lugares las viviendas tiene un mayor precio de venta.

  • No se recomienda invertir mucho en la zona oriental de la ciudad, ya que fue la zona en la que las viviendas se vendian con los precios mas bajos del mercado.

  • Se recomienda para mejorar el analisis a futuro, de incluir una nueva variable que indique el tiempo de antiguedad de la vivienda, ya que se pudo identificar en el mapa que la Zona Norte que es muy comun que en otras ciudades, sea la que mejor precio tengan las casas en esta caso no se vea reflejado, es muy probable que en esta parte de la ciudad la antiguedad de las edificaciones este jugando en contra, para que estas viviendas alcancen un mejor precio.

  • A traves de los mapa se descubrio que hay problemas en la base de datos, al momento de clasificar las viviendas con su lugar geografico correctamente, por lo que se recomienda, uno revisar nuevamente la base de datos, acompañado de un experto que conozca la ciudad para que puedam hacer estas correcciones, ademas de que se recomienda que quien digitalice la base de datos o quien tome la informacion, sea una persona natural de la ciudad de cali y que conozca muy bien a la ciudad, ya que es muy probable sobre todo con urbanizaciones o edificaciones nuevas, las cuales no esten siendo ubicadas correctamente y esto puede afectar seriamente el analisis de precios.

  • Segun el analisis de los graficos de dispersion, se identifico que los apartamentos, tienen menos area construida sin embargo alcanzan precios bastante altos incluso similar a la de las casas que duplican el tamaño construido, por tanto se recomienda que las campañas de marketing de la inmobiliaria se enfoque en este tipo de edificaciones, claro esta teniendo en cuenta las zonas en donde mas se valorizan.

  • Del analisis de cluster, se sacaron 4 grupos de segmentacion, confirmando que el tamaño de las viviendas influye positivamente en el precio de estas.

  • Un hallazgo de ultima hora, encontrado en el analisis de cluster es que el cluster 1 si bien es el que tiene las viviendas de menor tamaño construido y por ende con el precio mas bajo, esto lo hace muy asequible a gran parte de la poblacion caleña, encontrandose que mas de las mitad de la muestra, compraban casa en promedio de 240 millones, por lo que hay que analizar el costo de construccion de las viviendas, ya que se puede ver compensado por la alta demanda que tienen, comparado con el margen de beneficios que puede dejar una vivienda que cuesta mas, porque es mas grande, sin embargo la demanda es baja ya que no todos se pueden dar el lujo de comprar este tipo de edificaciones o construcciones.

7 Conclusiones

A modo de conclusion, se puede decir que para este caso en especifico y quizas por el diseño de la base de datos, la cual en cuanto a dimension es muy pequeña, los analisis de componentes principales y de correspondencia, no revelan informacion nueva y significativa, como la que se hallo en el analisis exploratorio inicial, sacando las estadisticas descriptivas y graficos de dispersion, los cuales resultaron ser muy eficientes en cuanto a la sencillez del calculo y a la informacion que aportaban, sin embargo el analisis por conglomerado revelo que hay una alta demanda de viviendas que tiene precios promedios de 240 millones muy asequible a la mayoria de la poblacion que es de clase media y baja; por otra parte la visualizacion espacial a traves de los mapas si nos aporto informacion nueva y relevante como por ejemplo, de problemas de clasificacion de las variables, lo que puede generar sesgo en los modelos. por tanto destacamos que fue de gran provecho emplear todas estas tecnicas de analisis descriptivo, para explorar las ventajas y desventajas de cada tecnica con el fin de extraer las recomendaciones mas importantes para nuestro cliente.