Para esta actividad se trabaja con el dataset de Viviendas de Cali, esto incluye sus precios y características como tipo de vivienda (casa o apartamento), número de baños, metros cuadrados, estrato en el que está ubicada, entre otras características.

El objetivo es hacer un análisis holístico de los datos y encontrar patrones, relaciones, segmentaciones. Para esto se hicieron análisis de Componentes Principales, Conglomerados y de Correspondecia.

PUNTO 1:

Primero se hará un análisis de Componentes Principales:

Exploramos los datos:

data("vivienda")
head(vivienda)

Se dejan solo las variables cuantitativas:

vivienda2 = vivienda[,4:9]
head(vivienda2)

Se revisa si hay registros con nulos:

md.pattern(vivienda2)

##      preciom estrato areaconst banios habitaciones parqueaderos     
## 6717       1       1         1      1            1            1    0
## 1602       1       1         1      1            1            0    1
## 1          1       0         0      0            0            0    5
## 2          0       0         0      0            0            0    6
##            2       3         3      3            3         1605 1619

Como hay registros nulos tomamos una decisión para saber qué hacer con ellos. Revisemos cuántos registros tenemos en nuestro dataset:

number_of_rows <- nrow(vivienda2)
print(number_of_rows)
## [1] 8322

Segun lo anterior tenemos un total de 8322 registros. Anteriormente vimos que la variable “parqueadero” tiene 1605 datos nulos. Las demás variables tienen 2 a 3 registros nulos. El total de registros nulos es 1619, como el dataset es mucho más grande (8322 registros en total), se toma la decisión de borrar los registros con datos nulos, sabiendo que no le hará mayor daño al dataset:

vivienda3 <- na.omit(vivienda2)

Escalamos el dataset para prepararlo para el PCA:

viviendaScal= scale(vivienda3)
head(viviendaScal)
##         estrato    preciom  areaconst parqueaderos     banios habitaciones
## [1,] -1.9279348 -0.6532909 -0.7712458   -0.7424551 -0.1850976    1.7511897
## [2,] -1.9279348 -0.4443626 -0.4242642   -0.7424551 -0.9096316   -0.4477275
## [3,] -1.9279348 -0.3548218  0.2696991    0.1465058 -0.9096316    0.2852449
## [4,] -0.8746661 -0.2055873  0.6860770    1.0354668  1.2639704   -0.4477275
## [5,]  0.1786025 -0.6234440 -0.6324532   -0.7424551 -0.9096316   -0.4477275
## [6,]  0.1786025 -0.6831378 -0.6532721   -0.7424551 -0.1850976   -0.4477275

Generamos un gráfico de barras para ver la dimensión que más aporta a la variabilidad:

viv.pca <- prcomp(viviendaScal)
fviz_eig(viv.pca, addlabels = TRUE)

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

Según lo anterior se puede deducir que lo que más aporta a la variabilidad del precio de una vivienda es el estrato y el número de parqueaderos, no tanto así el número de habitaciones. Podemos deducir que en estratos altos puede haber menos habitaciones que en estratos mas bajos.

Esto se puede ver en la siguiente tabla que ejemplifica como una vivienda de estrato 3 tiene más habitaciones que una de estrato 6:

datos<- rbind(vivienda[4620,], # ok
              vivienda[1258,],
              vivienda[2250,],
              vivienda[6552,])

datos <- as.data.frame(datos)
rownames(datos) = c("Cliente 4620","Cliente 1258","Cliente 2250","Cliente 6552")
datos
casos1 <- rbind(viv.pca$x[4620,1:2],viv.pca$x[1258,1:2]) # CP1
rownames(casos1) = c("98","299")
casos1 <- as.data.frame(casos1)

casos2 <- rbind(viv.pca$x[2250,1:2], viv.pca$x[6552,1:2]) # CP2
rownames(casos2) = c("6","190")
casos2 <- as.data.frame(casos2)

Esto mismo lo podemos ver en los siguientes gráficos y el gráfico Biplot:

fviz_pca_ind(viv.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)

datos<- rbind(vivienda[4620,], # ok
              vivienda[1258,],
              vivienda[2250,],
              vivienda[6552,])
datos
fviz_pca_biplot(viv.pca, 
                repel = TRUE,
                habillage = vivienda3$estrato,
                col.var = "#034A94", # Variables color
                col.ind = c("#DEDEDE", "#034A94")  # Individuals color
)

PUNTO 2:

  1. Ahora avanzaremos hacia el Análisis de Conglomerados:

Iniciamos con el dataset original y lo iremos acondicionando a nuestras necesidades para hacer el análisis

Omitimos los nulos:

viviendas_sinNulos <- na.omit(vivienda)

Solo dejamos las variables cuantitativas:

vivienda2 = vivienda[,4:9]

Adicionamos las variables “latitud” y “longitud”, el dataset nos queda de la siguiente manera:

vivienda2$latitud = vivienda$latitud
vivienda2$longitud = vivienda$longitud

head(vivienda2)

Revisamos si existen datos nulos.

md.pattern(vivienda2)

##      preciom estrato areaconst banios habitaciones latitud longitud
## 6717       1       1         1      1            1       1        1
## 1602       1       1         1      1            1       1        1
## 1          1       0         0      0            0       0        0
## 2          0       0         0      0            0       0        0
##            2       3         3      3            3       3        3
##      parqueaderos     
## 6717            1    0
## 1602            0    1
## 1               0    7
## 2               0    8
##              1605 1625

Realizamos lo mismo que con el análisis de Componentes principales, al haber 1605 nulos los podemos eliminar ya que hay 8322 registros en total y la supresión no es tan crítica:

vivienda3 <- na.omit(vivienda2)
md.pattern(vivienda3)
##  /\     /\
## {  `---'  }
## {  O   O  }
## ==>  V <==  No need for mice. This data set is completely observed.
##  \  \|/  /
##   `-----'

##      estrato preciom areaconst parqueaderos banios habitaciones latitud
## 6717       1       1         1            1      1            1       1
##            0       0         0            0      0            0       0
##      longitud  
## 6717        1 0
##             0 0

Escalamos la data:

viviendaScal= scale(vivienda3)
viviendaScal= as.data.frame(viviendaScal)
vivienda4= as.data.frame(vivienda3)

Aplicamos la técnica de K-means, se ponen 4 clusters, que en última son los cuatro estratos:

set.seed(123)
k <- 4  # Número de clusters 
resultados_kmeans <- kmeans(viviendaScal, centers = k, nstart = 25)
vivienda4$Grupo <- as.factor(resultados_kmeans$cluster)

head(vivienda4)

Visualizamos los clusters:

ggplot(vivienda4, aes(x = areaconst, y = preciom, color = Grupo)) +
  geom_point(size = 1.5, alpha = 0.6) +
  labs(
    title = "Clustering con K-means",
    x = "Area",
    y = "Precios",
    color = "Grupo"
  ) +
  theme_minimal()

Como se puede observar las viviendas en el grupo 4 son las que menos cuestan, mientras que en el grupo 2 se encuentran viviendas de mas alto costo, el grupo 3 y el grupo 1 se puede decir que estan viviendas de estrato medio

# 5. Visualizar los clusters
ggplot(vivienda4, aes(x = estrato, y = preciom, color = Grupo)) +
  geom_point(size = 1.5, alpha = 0.6) +
  labs(
    title = "Clustering con K-means",
    x = "Estrato",
    y = "Precios",
    color = "Grupo"
  ) +
  theme_minimal()

En el siguiente gráfico podemos observar la ubicación de las viviendas en las coordenadas dadas. Se puede observar que las viviendas de todos los estratos están homogeneamente organizadas en toda la ciudad, a diferencia del sur en donde se puede observar una predominancia por las viviendas mas costosas.

ggplot(vivienda4, aes(x = longitud, y = latitud, color = Grupo)) +
  geom_point(size = 1.5, alpha = 0.6) +
  labs(
    title = "Clustering con K-means",
    x = "Longitud",
    y = "Latitud",
    color = "Grupo"
  ) +
  theme_minimal()

PUNTO 3:

  1. Analisis de Correspondencia:

Eliminamos nuevamente los nulos del dataset:

viviendas_sinNulos <- na.omit(vivienda)

Se seleccionan las variables zona, tipo y barrio:

data_acs <- viviendas_sinNulos %>%
  select(zona, tipo, barrio)

Compararemos barrio con tipo de vivienda y zona con tipo de vivienda para saber como se correlacionan:

barriosvstipos <- table(data_acs$barrio, data_acs$tipo)
zonasvstipos <- table(data_acs$zona, data_acs$tipo)
#barriosvstipos
#zonasvstipos

Establecemos hipótesis para establecer la correlación primero de Barrio y Tipo de vivienda:

Hipotesis nula; Ho: Barrio y tipo de casa son independientes Hipotesis nula; H1: Barrio y tipo de casa son dependientes

Lo averiguaremos con una prueba ce Chi cuadrado:

chicuadrado = chisq.test(barriosvstipos)
## Warning in chisq.test(barriosvstipos): Chi-squared approximation may be
## incorrect
chicuadrado
## 
##  Pearson's Chi-squared test
## 
## data:  barriosvstipos
## X-squared = 1325.8, df = 272, p-value < 2.2e-16

Esta prueba Chi cuadrado arroja la advertencia “Chi-squared approximation may be incorrect” Esto es porque los valores en tipo de vivienda (casa o apartamento) son muy pequeños y no sirven para la prueba. Esta relación se descarta y hacemos la prueba Chi Cuadrado con la tabla Zonas vs Tipos

Hipotesis nula; Ho: Zona y tipo de casa son independientes Hipotesis nula; H1: Zona y tipo de casa son dependientes

chicuadrado = chisq.test(zonasvstipos)
chicuadrado
## 
##  Pearson's Chi-squared test
## 
## data:  zonasvstipos
## X-squared = 367.47, df = 4, p-value < 2.2e-16

Como el valor P de la prueba Chi Cuadrado es tan pequeña, rechazamos la hipotesis nula y acojemos la hipótesis alternativa. Es decir, las variables son dependientes.

Ahora hacemos el análisis de correspondecia con Zona y Tipo de vivienda:

tabla_frecuencia <- as.data.frame(table(data_acs$zona, data_acs$tipo))
colnames(tabla_frecuencia) <- c("zona", "tipo", "frecuencia")


tabla_frecuencia <- tabla_frecuencia %>% 
  group_by(tipo) %>% 
  mutate(Proporcion = frecuencia / sum(frecuencia))

Observamos la tabla de frecuencia:

tabla_frecuencia
ggplot(tabla_frecuencia, aes(x = tipo, y = Proporcion, fill = zona)) + 
  geom_bar(stat = "identity", position = "fill") + # "fill" para normalizar proporciones
  scale_fill_manual(values = c("blue", "red", "green", "yellow", "gray")) + 
  coord_flip() + # Girar el gráfico para organizar nombres en eje Y
  labs(title = "Distribucion de tipos de vivienda por zona",
       x = "tipo de vivienda",
       y = "Proporcion",
       fill = "zona") +
  theme_minimal()

Según el cuadro en la zona sur impera las casas pero la diferencia no es tan marcada, practicamente que se pueden encontrar tanto casas como apartamentos en la misma proporcion, solo un poco mas casa. En la zona oriente imperan mucho más las casas, se tiene poca oferta de apartamentos, quizás sea una buena oportunidad para la inmobiliaria de ofertar más apartamentos debido a lo extenso de la zona. La zona oeste tiene más oferta de apartamentos, muy pocas casas. La zona norte tiene igual de oferta de casas y apartamentos.

En conclusión, para la inmobiliaria la zona sur trae muy buenas oportunidades ya que se ve que es una zona de alta oferta y demanda, esto puede indicar que sea una zona de expansión de la ciudad.

# Perfil Columna
tabla_frecuencia <- table(data_acs$tipo, data_acs$zona)
tabla_frecuencia
##              
##               Zona Centro Zona Norte Zona Oeste Zona Oriente Zona Sur
##   Apartamento           4        632        669           17     1860
##   Casa                 32        254         84           80     1176
# se convierte la tabla en un dataframe
tabla_dataframe <- as.data.frame(tabla_frecuencia)
tabla_dataframe
# Renombrar columnas
colnames(tabla_dataframe) <- c("tipo_df", "zona_df", "frecuencia")

# Calcular proporciones por columna
tabla_dataframe <- tabla_dataframe %>%
  group_by(zona_df) %>% 
  mutate(Proporcion = frecuencia / sum(frecuencia) * 100)
tabla_dataframe
library(scales)
## 
## Adjuntando el paquete: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
# Grafico de barras apiladas normalizado por columna
ggplot(tabla_dataframe, aes(x = zona_df, y = Proporcion, fill = tipo_df)) + 
  geom_bar(stat = "identity", position = "fill") + 
  labs(title = "Distribucion de tipos de vivienda por zona",
       x = "zona",
       y = "Proporcion (%)",
       fill = "tipo") + 
  scale_y_continuous(labels = percent_format()) + # Muestra eje Y con porcentajes
  theme_minimal()

La anterior gráfica contrasta lo anteriormente dicho en la penúltima gráfica, esta vez en un tipo de barras apiladas.

Nuevamente se recomienda altamente a la inmobiliaria centrarse en la zona sur ya que según los datos esta zona es altamente demandada y puede ser una zona de expansión de la ciudad.

# Analisis de correspondencia:
library(FactoMineR)
library(factoextra)
#ca_result <- CA(tabla_frecuencia, graph = TRUE)
#tabla_frecuencia
#fviz_ca_biplot(ca_result, repel = TRUE, title = "CA Factor Map")

PUNTO 4:

Referente a los resultados obtenidos y las gráficas generadas se recomienda a la inmobiliaria altamente centrarse en la zona sur ya que hay más oferta de viviendas allí lo que puede darnos a entender que es una zona de expansión en la ciudad.

En base al precio y el área construida también la zona sur ofrece un abanico más amplio en estos conceptos, teniendo viviendas pequeñas hasta viviendas amplias, con precios promedio hasta precios altos.