library(paqueteMODELOS)
library(dplyr)
library(ggplot2)
library(tidyr)
library(naniar)
library(reshape2)
library(mice)
library(ggbiplot)
library(factoextra)
library(FactoMineR)
library(cluster)
library(dendextend)
library(fpc)
data("vivienda")
class(vivienda)
## [1] "spec_tbl_df" "tbl_df" "tbl" "data.frame"
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>
El conjunto de datos obtenido corresponde a un data.frame que contiene 8322 registros correspondientes a propiedades inmobiliarias de la ciudad de Cali, y 13 variables con información de estos registros los cuales se describen a continuación:
head(vivienda, 6)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona O… <NA> 3 250 70 1 3 6
## 2 1169 Zona O… <NA> 3 320 120 1 2 3
## 3 1350 Zona O… <NA> 3 350 220 2 2 4
## 4 5992 Zona S… 02 4 400 280 3 5 3
## 5 1212 Zona N… 01 5 260 90 1 2 3
## 6 1724 Zona N… 01 5 240 87 1 3 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
tail(vivienda, 6)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 6417 Zona S… <NA> 6 1800 400 3 6 5
## 2 6998 Zona S… <NA> 6 1000 189 3 5 4
## 3 8139 Zona S… <NA> 5 530 142 2 4 4
## 4 NA <NA> <NA> NA NA NA NA NA NA
## 5 NA <NA> <NA> NA NA NA NA NA NA
## 6 NA <NA> <NA> NA 330 NA NA NA NA
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
Antes de realizar el análisis exploratorio propiamente dicho procedemos a revisar la integridad de nuestros datos mediante la determinación de duplicados, datos faltantes, información inconsistente o tipos de datos que no correspondan a la naturaleza de la variable. Estas tareas podrían obligar a realizar actividades de eliminación, adición o transformación de los datos con el objeto de preparar el conjunto de datos para el modelado.
# Verificar si hay filas duplicadas en el dataframe completo
duplicados <- vivienda %>%
filter(duplicated(.))
# Ver los duplicados
print(duplicados)
## # A tibble: 1 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 NA <NA> <NA> NA NA NA NA NA NA
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
El conjunto de datos no contiene registros duplicados. Al aplicar la función para determinarlos solo arroja una columna con todos los valores NA. Esto sugiere que el conjunto de datos contiene dos columnas con todos los valores NA. Esto será abordado al momento de efectuar el tratamiento de los datos faltantes.
gg_miss_var(vivienda)
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
Para corregir el problema de los datos faltantes se procedió de la siguiente forma:
vivienda <- vivienda[rowSums(is.na(vivienda)) != ncol(vivienda), ]
vivienda <- vivienda[apply(is.na(vivienda), 1, function(x) sum(x) != ncol(vivienda) - 1), ]
moda_piso_por_zona <- vivienda %>%
group_by(zona) %>%
summarise(moda_piso = as.numeric(names(sort(table(piso), decreasing = TRUE)[1])), .groups = 'drop')
vivienda <- vivienda %>%
mutate(parqueaderos = replace_na(parqueaderos, 0))
vivienda <- vivienda %>%
left_join(moda_piso_por_zona, by = "zona") %>%
mutate(piso = ifelse(is.na(piso), moda_piso, piso)) %>%
select(-moda_piso)
Una vez aplicado el código donde se aplica el tratamiento a los datos faltantes verificamos que todo haya sido aplicado correctamente.
gg_miss_var(vivienda)
Se cambia el tipo de datos de chr a factor de las variables zona, tipo y barrio. Estas variables claramente corresponden a variables categóricas que pueden ser transformadas para facilitar el análisis.
# columnas categóricas
vivienda %>% count(zona)
## # A tibble: 5 × 2
## zona n
## <chr> <int>
## 1 Zona Centro 124
## 2 Zona Norte 1920
## 3 Zona Oeste 1198
## 4 Zona Oriente 351
## 5 Zona Sur 4726
vivienda %>% count(barrio)
## # A tibble: 436 × 2
## barrio n
## <chr> <int>
## 1 20 de julio 3
## 2 3 de julio 1
## 3 Belalcazar 1
## 4 Brisas De Los 1
## 5 Bueno Madrid 1
## 6 Cali 37
## 7 Camino Real 1
## 8 Centenario 1
## 9 Chiminangos 1
## 10 Ciudad 2000 1
## # ℹ 426 more rows
vivienda %>% count(tipo)
## # A tibble: 2 × 2
## tipo n
## <chr> <int>
## 1 Apartamento 5100
## 2 Casa 3219
vivienda %>% count(piso)
## # A tibble: 15 × 2
## piso n
## <chr> <int>
## 1 01 860
## 2 02 1450
## 3 03 1097
## 4 04 607
## 5 05 567
## 6 06 245
## 7 07 204
## 8 08 211
## 9 09 146
## 10 1 198
## 11 10 130
## 12 11 84
## 13 12 83
## 14 2 2044
## 15 3 393
# Convertir variables categoricas a factor
vivienda <- vivienda %>% mutate(
zona = as.factor(zona),
tipo = as.factor(tipo),
barrio = as.factor(barrio)
)
Por otra parte la variable ‘piso’ puede ser convertida de tipo chr a int dado que en realidad corresponde a un numero entero que por alguna razón esta mal formateado en el conjunto de datos original, por lo que duplica categorías que en realidad deben ser una sola, por ejemplo 01 y 1. Con este enfoque quedan correctamente etiqueda las categorias de esta variable.
vivienda <- vivienda %>%
mutate(piso = as.integer(piso))
Finalmente verificamos que se hayan aplicado correctamente la limpieza y transformación del conjunto de datos.
head(vivienda)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <fct> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona O… 1 3 250 70 1 3 6
## 2 1169 Zona O… 1 3 320 120 1 2 3
## 3 1350 Zona O… 1 3 350 220 2 2 4
## 4 5992 Zona S… 2 4 400 280 3 5 3
## 5 1212 Zona N… 1 5 260 90 1 2 3
## 6 1724 Zona N… 1 5 240 87 1 3 3
## # ℹ 4 more variables: tipo <fct>, barrio <fct>, longitud <dbl>, latitud <dbl>
3.1. Análisis Univariado.
Generamos las estadísticas descriptivas del conjunto de datos:
summary(vivienda)
## id zona piso estrato
## Min. : 1 Zona Centro : 124 Min. : 1.000 Min. :3.000
## 1st Qu.:2080 Zona Norte :1920 1st Qu.: 2.000 1st Qu.:4.000
## Median :4160 Zona Oeste :1198 Median : 2.000 Median :5.000
## Mean :4160 Zona Oriente: 351 Mean : 3.233 Mean :4.634
## 3rd Qu.:6240 Zona Sur :4726 3rd Qu.: 4.000 3rd Qu.:5.000
## Max. :8319 Max. :12.000 Max. :6.000
##
## preciom areaconst parqueaderos banios
## Min. : 58.0 Min. : 30.0 Min. : 0.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 : 1.000 Median : 3.000
## Mean : 433.9 Mean : 174.9 Mean : 1.482 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 Apartamento:5100 valle del lili:1008 Min. :-76.59
## 1st Qu.: 3.000 Casa :3219 ciudad jardín : 516 1st Qu.:-76.54
## Median : 3.000 pance : 409 Median :-76.53
## Mean : 3.605 la flora : 366 Mean :-76.53
## 3rd Qu.: 4.000 santa teresita: 262 3rd Qu.:-76.52
## Max. :10.000 el caney : 208 Max. :-76.46
## (Other) :5550
## latitud
## Min. :3.333
## 1st Qu.:3.381
## Median :3.416
## Mean :3.418
## 3rd Qu.:3.452
## Max. :3.498
##
A simple vista notamos que las variables de nuestro conjunto de datos se encuentran en rangos diferentes. Esto podría dificultar tanto el análisis preliminar de los datos, como la aplicación de técnicas como el Análisis de Componentes Principales (PCA) y el Análisis de Conglomerados. Por tal motivo, adicional a las transformaciones ya efectuadas procedemos a estandarizar las variables numericas del conjunto.
vivienda_estandarizado <- vivienda %>%
select(-zona, -barrio, -tipo, -id) %>%
scale() %>%
as.data.frame()
head(vivienda_estandarizado)
## piso estrato preciom areaconst parqueaderos banios
## 1 -0.9643519 -1.5872276 -0.5595498 -0.7339949 -0.3875522 -0.07793773
## 2 -0.9643519 -1.5872276 -0.3465670 -0.3842568 -0.3875522 -0.77811479
## 3 -0.9643519 -1.5872276 -0.2552886 0.3152194 0.4168506 -0.77811479
## 4 -0.5325734 -0.6156201 -0.1031580 0.7349051 1.2212534 1.32241640
## 5 -0.9643519 0.3559875 -0.5291236 -0.5940997 -0.3875522 -0.77811479
## 6 -0.9643519 0.3559875 -0.5899759 -0.6150839 -0.3875522 -0.07793773
## habitaciones longitud latitud
## 1 1.6406840 0.9728466 0.3793708
## 2 -0.4147626 0.9331875 0.3763219
## 3 0.2703863 0.7607566 0.4225243
## 4 -0.4147626 -0.6549016 0.4070454
## 5 -0.4147626 0.8682385 0.9678065
## 6 -0.4147626 0.6670691 -1.1242009
Inicialmente haremos la observaciones de las variables numéricas estandarizadas mediante diagramas de caja y bigotes para cada una de ellas:
library(RColorBrewer)
vivienda_pivot <- vivienda_estandarizado %>%
select_if(is.numeric) %>%
pivot_longer(cols = everything(), names_to = "variable", values_to = "valor")
n_colores <- length(unique(vivienda_pivot$variable))
colores_pastel <- RColorBrewer::brewer.pal(n_colores, "Pastel1")
ggplot(vivienda_pivot, aes(x = variable, y = valor, fill = variable)) +
geom_boxplot() +
scale_fill_manual(values = colores_pastel) +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(title = "Boxplot de todas las variables numéricas",
x = "Variable", y = "Valor") +
theme_minimal() +
theme(legend.position = "none")
Los diagramas de boxplot nos muestran que en efecto las variables se encuentran con distribuciones muy diversas, la mayoría de ellas con sesgo y valores atípicos, sin embargo por ser el sector inmobiliario muy dependiente de las condiciones socio-económicas de la población no le daremos tratamiento a estos valores atípicos ya que corresponden a un patrón normal e incluso esperable en las ciencias económicas.
cor(vivienda_estandarizado[, sapply(vivienda_estandarizado, is.numeric)], use="complete.obs")
## piso estrato preciom areaconst parqueaderos
## piso 1.000000000 0.14659113 -0.005885967 -0.17745968 0.01634177
## estrato 0.146591126 1.00000000 0.609806641 0.27432332 0.51278892
## preciom -0.005885967 0.60980664 1.000000000 0.68735196 0.63977788
## areaconst -0.177459683 0.27432332 0.687351963 1.00000000 0.48238397
## parqueaderos 0.016341771 0.51278892 0.639777883 0.48238397 1.00000000
## banios -0.074514213 0.42032178 0.669145579 0.64841648 0.52312994
## habitaciones -0.199898962 -0.07137615 0.264091206 0.51691292 0.19875551
## longitud -0.048363839 -0.44414040 -0.343588223 -0.17374283 -0.27974065
## latitud 0.042289415 -0.22749944 -0.115667569 -0.05188781 -0.15629165
## banios habitaciones longitud latitud
## piso -0.07451421 -0.199898962 -0.048363839 0.04228941
## estrato 0.42032178 -0.071376147 -0.444140396 -0.22749944
## preciom 0.66914558 0.264091206 -0.343588223 -0.11566757
## areaconst 0.64841648 0.516912916 -0.173742834 -0.05188781
## parqueaderos 0.52312994 0.198755515 -0.279740654 -0.15629165
## banios 1.00000000 0.589906412 -0.249569746 -0.13003729
## habitaciones 0.58990641 1.000000000 -0.008002016 0.02125096
## longitud -0.24956975 -0.008002016 1.000000000 0.23606961
## latitud -0.13003729 0.021250965 0.236069614 1.00000000
cor_matrix <- cor(vivienda_estandarizado[, c("preciom", "areaconst", "parqueaderos", "banios", "habitaciones", "piso", "estrato", "longitud", "latitud")], use = "complete.obs")
cor_long <- as.data.frame(as.table(cor_matrix))
ggplot(cor_long, aes(Var1, Var2, fill = Freq)) +
geom_tile() +
scale_fill_gradient2(low = "red", high = "green", mid = "yellow", midpoint = 0, limit = c(-1, 1)) +
geom_text(aes(label = round(Freq, 2)), color = "black", size = 4) +
theme_minimal() +
labs(title = "Mapa de Calor de las Correlaciones", x = "Variable", y = "Variable", fill = "Correlación") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Para el desarrollo del análisis de componentes principales, excluiremos del conjunto de datos a las tres variables que muestran menor correlación con las demás variables del conjunto de datos estas son: piso, longitud y latitud. Sobre el particular cabe resaltar que estas variables poco aportan al modelo ya que a pesar de tener formato numérico su naturaleza es meramente informativa y pueden ser consideradas categóricas, de hecho dos de estas variables corresponden a las coordenadas geográficas por lo que son explicadas por las variables categóricas zona y barrio. De igual forma se excluyó la variable estrato dado es una variable categórica ordinal.
vivienda_estandarizado_numer <- vivienda_estandarizado %>%
select(-piso, -longitud, -latitud, -estrato)
pca_resultado <- prcomp(vivienda_estandarizado_numer)
summary(pca_resultado)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5
## Standard deviation 1.7687 0.9580 0.65962 0.56977 0.44053
## Proportion of Variance 0.6257 0.1836 0.08702 0.06493 0.03881
## Cumulative Proportion 0.6257 0.8092 0.89626 0.96119 1.00000
library(factoextra)
res.pca <- prcomp(vivienda_estandarizado_numer)
fviz_eig(res.pca, addlabels = TRUE)
fviz_pca_var(res.pca,
col.var = "contrib",
gradient.cols = c("#FF7F00", "#034D94"),
repel = TRUE
)
ggbiplot(pca_resultado, obs.scale = 1, var.scale = 1, groups = vivienda$zona,
ellipse = TRUE, circle = TRUE) +
theme_minimal() +
labs(title = "PCA Biplot - Dos primeros componentes")
scores_pca <- pca_resultado$x
head(scores_pca)
## PC1 PC2 PC3 PC4 PC5
## [1,] -0.24152830 -1.56481451 0.87782085 0.005259334 0.6499093
## [2,] -1.04207572 0.14095015 -0.14392551 -0.209788875 0.1579068
## [3,] -0.09005095 0.01620188 0.18306840 -0.974807022 0.1572797
## [4,] 1.31443366 0.64126217 0.45715767 0.155313505 -1.2613214
## [5,] -1.23096999 0.09318946 0.03951942 -0.144980451 0.1185791
## [6,] -0.92302403 -0.03652024 0.15796687 0.336771657 -0.2510437
plot(scores_pca[, 1], scores_pca[, 2],
xlab = "Componente Principal 1",
ylab = "Componente Principal 2",
main = "Distribución de Observaciones en los Primeros 2 Componentes",
col = vivienda$zona, pch = 16)
El PCA aplicado sobre 5 variables numéricas del conjunto de datos, explica con dos componentes principales el 81% de la varianza de los datos. El modelo con 3 componentes principales logra explicar cerca del 90% de dicha varianza, así las cosas se pueden escoger tres componentes para efectuar los análisis subsiguientes que requiera la empresa.
El primer componente, con una proporción de varianza de 0.6257 captura en mayor medida la información de las variables ‘areaconst’ y ‘baños’, mientras que el segundo componente captura mas información de las variables ‘habitaciones’ y ‘parqueaderos’ como se puede observar el el gráfico Variable - PCA.
Anexamos ademas gráficos adicionales donde se observa la distribución de los casos. Por ejemplo, podemos notar en el PCA Biplot los casos mas influenciados por los vectores ubicados en el plano por zona.
Determinaremos primero mediante la ayuda gráfica del metodo del codo una aproximación al número de clústeres optimo para nuestros datos:
buck <- numeric(6)
for (i in 1:6) {
kmeans_result <- kmeans(vivienda_estandarizado_numer, centers = i)
buck[i] <- kmeans_result$tot.withinss }
plot(1:6, buck, type = "b", pch = 19, col = "blue",
xlab = "Número de Clusters", ylab = "WCSS",
main = "Método del Codo (Elbow Method)")
Conforme al análisis de la gráfica anterior probaremos ajustar el modelo k-means con parámetros k de 2 y 3 y escogeremos de los dos el que muestre mejor desempeño.
distancia <- dist(vivienda_estandarizado_numer, method = "euclidean")
cluster_jerarquico <- hclust(distancia, method = "complete")
plot(cluster_jerarquico, main = "Dendograma - Método Jerárquico", xlab = "Individuos", ylab = "Distancia")
rect.hclust(cluster_jerarquico, k = 3, border = "red")
set.seed(123)
kmeans_resultado <- kmeans(vivienda_estandarizado_numer, centers = 3)
table(kmeans_resultado$cluster)
##
## 1 2 3
## 942 2554 4823
vivienda$cluster_kmeans <- kmeans_resultado$cluster
ggplot(vivienda, aes(x = preciom, y = areaconst, color = factor(cluster_kmeans))) +
geom_point() +
labs(title = "Grupos según K-means", x = "Precio por metro cuadrado", y = "Área de construcción") +
theme_minimal()
clust_stats <- cluster.stats(distancia, kmeans_resultado$cluster)
cat("Índice de Rand ajustado:", clust_stats$corrected.rand, "\n")
## Índice de Rand ajustado:
cluster_jerarquico <- hclust(distancia, method = "complete")
grupo_jerarquico <- cutree(cluster_jerarquico, k = 3)
distancia_e <- dist(vivienda_estandarizado_numer, method = "euclidean")
dendograma <- hclust(distancia_e, method = "average")
barplot(sort(dendograma$height, decreasing = TRUE), horiz = TRUE,
main = "Agregaciones (distancias euclidianas)",
col = "lightblue", ylab = "Nodo", xlab = "Peso", xlim = c(0, 2.5))
El algoritmo K-means logra un mayor ajuste con un valor k=3. El gráfico de grupos en K-Means nos muestra una separación relativa y definida entre los miembros de los clusteres aunque con valores extrapolados entre los mismos. Se podría optar por enfoques mas avanzados teniendo en cuenta la complejidad y variables involucradas en este análisis.
centroides <- kmeans_result$centers
centroides
## preciom areaconst parqueaderos banios habitaciones
## 1 1.8431854 0.9261133 1.53063912 1.0663462 0.1464862
## 2 2.5347971 3.2184808 2.32658389 2.0251121 1.2611411
## 3 -0.7043255 -0.6541809 -0.67498859 -0.8761852 -0.5725476
## 4 -0.2321571 -0.3431604 0.08855472 -0.1896681 -0.2994667
## 5 0.0601238 0.9192358 -0.28452520 1.1062698 2.5024640
## 6 0.3446819 0.3716605 0.18117564 0.6794979 0.2536216
distancia_centroides <- dist(centroides, method = "euclidean")
distancia_centroides
## 1 2 3 4 5
## 2 2.920358
## 3 4.259386 6.802852
## 4 3.126365 5.717591 1.203559
## 5 3.467910 4.540218 4.074102 3.368758
## 6 2.129580 4.508829 2.447139 1.383346 2.416012
vivienda$cluster_kmeans <- kmeans_result$cluster
cluster1_data <- subset(vivienda, cluster_kmeans == 1)
cluster2_data <- subset(vivienda, cluster_kmeans == 2)
cluster3_data <- subset(vivienda, cluster_kmeans == 3)
distancia_cluster1 <- dist(cluster1_data[, c("piso", "estrato", "preciom")], method = "euclidean")
distancia_cluster2 <- dist(cluster2_data[, c("piso", "estrato", "preciom")], method = "euclidean")
distancia_cluster3 <- dist(cluster3_data[, c("piso", "estrato", "preciom")], method = "euclidean")
mean(distancia_cluster1)
## [1] 353.1534
mean(distancia_cluster2)
## [1] 431.5424
mean(distancia_cluster3)
## [1] 88.98669
heatmap(as.matrix(distancia_centroides), main = "Matriz de Distancia entre Centroides")
set.seed(123)
kmeans_result <- kmeans(vivienda[, c("piso", "estrato", "preciom")], centers = 3)
centroides <- kmeans_result$centers
distancia_centroides <- dist(centroides, method = "euclidean")
distancia_tabla <- as.matrix(distancia_centroides)
distancia_tabla
## 1 2 3
## 1 0.0000 1092.4754 387.7355
## 2 1092.4754 0.0000 704.7408
## 3 387.7355 704.7408 0.0000
DISTANCIA ENTRE CLUSTERES
Cluster 1 y 2: Tiene una distancia bastante alta, lo que indica que los centroides de los clusters 1 y 2 están bastante separados en el espacio de características para el clustering. Es decir las observaciones en estos dos clusters son bastante diferentes entre sí.
Cluster 1 y 3: La distancia es considerablemente más pequeña que la de la comparación anterior. Esto nos indica que los centroides del cluster 1 y 3 están relativamente más cerca, lo que indica que las observaciones en estos dos clusters podrían ser más similares entre sí que con el cluster 2.
Cluster 2 y 3: está entre las dos anteriores. Es una distancia intermedia, lo que significa que los clusters 2 y 3 no están tan alejados como los clusters 1 y 2, pero tampoco están tan cerca como los clusters 1 y 3.
En conclusión Los resultados indican que el cluster 1 es muy diferente del cluster 2, mientras que el cluster 1 y el cluster 3 tienen características similares. El cluster 2 parece estar más alejado de los otros dos clusters en términos de las características utilizadas para el análisis.
AC1 <- table(vivienda$tipo, vivienda$zona)
chisq.test(AC1)
##
## Pearson's Chi-squared test
##
## data: AC1
## X-squared = 690.93, df = 4, p-value < 2.2e-16
resul_AC1 <- CA(AC1)
eigen_AC1 <- resul_AC1$eig ; eigen_AC1
## eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.08305442 100 100
fviz_screeplot(resul_AC1, addlabels = TRUE, ylim = c(0, 100)) +
ggtitle("Scree Plot: Zona vs Tipo") +
ylab("Porcentaje de varianza explicado") +
xlab("Ejes")
AC2 <- table(vivienda$tipo, vivienda$barrio)
chisq.test(AC2)
##
## Pearson's Chi-squared test
##
## data: AC2
## X-squared = 2468.3, df = 435, p-value < 2.2e-16
resul_AC2 <- CA(AC2)
eigen_AC2 <- resul_AC2$eig ; eigen_AC2
## eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.2967032 100 100
fviz_screeplot(resul_AC1, addlabels = TRUE, ylim = c(0, 100)) +
ggtitle("Scree Plot: Zona vs Tipo") +
ylab("Porcentaje de varianza explicado") +
xlab("Ejes")
AC3 <- table(vivienda$barrio, vivienda$zona)
chisq.test(AC3)
##
## Pearson's Chi-squared test
##
## data: AC3
## X-squared = 29343, df = 1740, p-value < 2.2e-16
resul_AC3 <- CA(AC3)
eigen_AC3 <- resul_AC3$eig ; eigen_AC3
## 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(resul_AC3, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
acp_resultado <- CA(tabla_contingencia) # Análisis de Correspondencia
PRUEBA CHI-CUADRADO Para las tres combinaciones de las variables evaluadas:
La hipótesis nula en una prueba Chi-cuadrado es que no existe asociación entre las dos variables categóricas. La hipótesis alternativa es que sí existe una relación entre las variables categóricas. En los tres casos, los valores p son muy pequeños, menos que 0.05, lo que deja entrever que hay evidencia estadística suficiente para rechazar la hipótesis nula de que las variables no están relacionadas.
ANÁLISIS DE CORRESPONDENCIA ENTRE VARIABLES CATEGORICAS
Variables Tipo - Zona y Tipo - Barrio
En estos dos casos era previsible y evidente que solo una dimensión es significativa, de hecho la variable tipo al tener solo dos clases en combinación con las otras dos variables no aporta grandes sorpresas en este análisis. Esto lo podemos determinar por lo siguiente:
Variables Zona y Barrio
Esta combinación de variables categóricas explica los datos mediante cuatro dimensiones:
El análisis integral y multidimensional de la base de datos inmobiliaria de la Ciudad de Calí nos ha permitido tener una visión detallada de las dinámicas que rigen el mercado urbano en este municipio. Mediante la aplicación de técnicas avanzadas como el Análisis de Componentes Principales, el Análisis de Conglomerados y el Análisis de Correspondencia, se ha logrado identificar patrones clave que explican la variabilidad en los precios y la oferta inmobiliaria, así como las relaciones entre variables categóricas que afectan el comportamiento del mercado en diversas zonas y estratos socioeconómicos. La visualización de estos resultados ha facilitado la comprensión de los hallazgos y proporcionado una base sólida para la toma de decisiones estratégicas.
Con los resultados obtenidos, la empresa inmobiliaria cuenta con herramientas valiosas para optimizar sus inversiones, segmentar el mercado de manera más eficiente y, en última instancia, maximizar los beneficios. Este análisis no solo ofrece una ventaja competitiva significativa en un entorno dinámico, sino que también contribuye a una mejor comprensión del mercado, permitiendo a la empresa anticipar tendencias y adaptarse rápidamente a los cambios del sector inmobiliario.
EXITOS