1 PROBLEMA

Una empresa inmobiliaria líder en una gran ciudad está buscando comprender en profundidad el mercado de viviendas urbanas para tomar decisiones estratégicas más informadas. La empresa posee una base de datos extensa que contiene información detallada sobre diversas propiedades residenciales disponibles en el mercado. Se requiere realizar un análisis holístico de estos datos para identificar patrones, relaciones y segmentaciones relevantes que permitan mejorar la toma de decisiones en cuanto a la compra, venta y valoración de propiedades.

2 DESARROLLO

Para dar solución al requerimiento planteado, se iniciará realizando un análisis exploratorio de datos, en aras de conocer las variables y su contenido, que en este caso corresponde a una muestra de viviendas de la ciudad de Cali. Posteriormente, se aplicará análisis de componentes principales para reducir la dimensionalidad del conjunto de datos, mientras se preserva la mayor cantidad posible de la varianza; análisis de conglomerados para agrupar datos en clústeres basados en su similitud; y análisis de correspondencias para estudiar las relaciones entre variables categóricas.

2.1 Análisis de Datos

vf <- vivienda
vf
## # A tibble: 8,322 × 13
##       id zona   piso  estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <chr>   <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 … 02          4     400       280            3      5            3
##  5  1212 Zona … 01          5     260        90            1      2            3
##  6  1724 Zona … 01          5     240        87            1      3            3
##  7  2326 Zona … 01          4     220        52            2      2            3
##  8  4386 Zona … 01          5     310       137            2      3            4
##  9  1209 Zona … 02          5     320       150            2      4            6
## 10  1592 Zona … 02          5     780       380            2      3            3
## # ℹ 8,312 more rows
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Como preámbulo, se describe la base de datos original, la cual consta de 13 atributos y 8.322 registros, que describen características de viviendas en cuanto a su ubicación, distribución y precio. Sin embargo, como es una data extensa, se recomienda renombrar las variables y verificar la calidad e integridad de los registros, por lo que se procede con:

Renombrar variables

Las variables se renombran para identificarlas con mayor facilidad.

renombrar_variables <- function(df, nuevas_variables) {
  df %>%
    rename_with(~nuevas_variables, everything())
}
vf <- renombrar_variables(vf, c("Id", "Zona", "Piso", "Estrato", "Precio", "Área", "Parqueaderos", "Baños", "Habitaciones", "Tipo", "Barrio", "Longitud", "Latitud"))
print(names(vf))
##  [1] "Id"           "Zona"         "Piso"         "Estrato"      "Precio"      
##  [6] "Área"         "Parqueaderos" "Baños"        "Habitaciones" "Tipo"        
## [11] "Barrio"       "Longitud"     "Latitud"

Verificar tipo de dato

Tipo <- sapply(vf, class)
Tipo
##           Id         Zona         Piso      Estrato       Precio         Área 
##    "numeric"  "character"  "character"    "numeric"    "numeric"    "numeric" 
## Parqueaderos        Baños Habitaciones         Tipo       Barrio     Longitud 
##    "numeric"    "numeric"    "numeric"  "character"  "character"    "numeric" 
##      Latitud 
##    "numeric"

Se observa que el atributo Piso está como texto o string, por lo que se debe convertir a numérico.

vf$Piso <- as.numeric(as.character(vf$Piso))
str(vf$Piso)
##  num [1:8322] NA NA NA 2 1 1 1 1 2 2 ...

Definir operacionalmente las variables

Se observa que la muestra contiene información de 8 variables cuantitativas y 4 cualitativas (descartando el id), las cuales se describen de la siguiente manera, según su definición operacional:

Descripción.v <- data.frame(
  Variable = c("Zona", "Piso", "Estrato", "Precio", "Área",  "Parqueaderos", "Baños", "Habitaciones", "Tipo", "Barrio", "Longitud", "Latitud"),
  Tipo.variabe = c("Cualitativa-Nominal", "Cualitativa-Ordinal" ,"Cualitativa-Ordinal", "Cuantitativa-Continua", "Cuantitativa-Continua", "Cuantitativa-Discreta", "Cuantitativa-Discreta", "Cuantitativa-Discreta", "Cualitativa-Categórica", "Cualitativa-Nominal", "Cuantitativa-Continua", "Cuantitativa-Continua"),
  Unidad.medida = c("Ninguna", "Ninguna", "Nivel", "Millones de COP", "Metros2", "Cantidad", "Cantidad", "Cantidad", "Ninguna", "Ninguna", "Grados" , "Grados"),
  Definición.variable = c("Sector de ubicación de la vivienda", "Nivel de altura en el que se encuentra la vivienda", "Nivel socioeconómico de la vivienda", "Valor de venta de la vivienda", "Extensión de la vivienda", "Número de parqueaderos con que cuenta la vivienda", "Número de baños con que cuenta la vivienda", "Número de habitaciones con que cuenta la vivienda", "Clasificación de la vivienda", "Lugar de ubicación de la vivienda", "Georeferenciación de la vivienda", "Georeferenciación de la vivienda")
)
print(Descripción.v)
##        Variable           Tipo.variabe   Unidad.medida
## 1          Zona    Cualitativa-Nominal         Ninguna
## 2          Piso    Cualitativa-Ordinal         Ninguna
## 3       Estrato    Cualitativa-Ordinal           Nivel
## 4        Precio  Cuantitativa-Continua Millones de COP
## 5          Área  Cuantitativa-Continua         Metros2
## 6  Parqueaderos  Cuantitativa-Discreta        Cantidad
## 7         Baños  Cuantitativa-Discreta        Cantidad
## 8  Habitaciones  Cuantitativa-Discreta        Cantidad
## 9          Tipo Cualitativa-Categórica         Ninguna
## 10       Barrio    Cualitativa-Nominal         Ninguna
## 11     Longitud  Cuantitativa-Continua          Grados
## 12      Latitud  Cuantitativa-Continua          Grados
##                                   Definición.variable
## 1                  Sector de ubicación de la vivienda
## 2  Nivel de altura en el que se encuentra la vivienda
## 3                 Nivel socioeconómico de la vivienda
## 4                       Valor de venta de la vivienda
## 5                            Extensión de la vivienda
## 6   Número de parqueaderos con que cuenta la vivienda
## 7          Número de baños con que cuenta la vivienda
## 8   Número de habitaciones con que cuenta la vivienda
## 9                        Clasificación de la vivienda
## 10                  Lugar de ubicación de la vivienda
## 11                   Georeferenciación de la vivienda
## 12                   Georeferenciación de la vivienda

Verificar datos faltantes

Registros <- nrow(vf)
Faltantes <-  colSums(is.na(vf))
Participación <- round(Faltantes/Registros,4)*100
datosparciales <- data.frame(Faltantes = Faltantes, 
                             Participación = Participación)
datosparciales <- datosparciales[order(-datosparciales$Participación), ]
datosparciales
##              Faltantes Participación
## Piso              2638         31.70
## Parqueaderos      1605         19.29
## Id                   3          0.04
## Zona                 3          0.04
## Estrato              3          0.04
## Área                 3          0.04
## Baños                3          0.04
## Habitaciones         3          0.04
## Tipo                 3          0.04
## Barrio               3          0.04
## Longitud             3          0.04
## Latitud              3          0.04
## Precio               2          0.02

Los atributos piso y parqueaderos son los que más datos faltantes presentan, 31.70% y 19.29% respectivamente. Eliminarlos representaría una pérdida de información, por lo que se procederá a tratarlos vía imputación. Por otra parte, el resto de variables contienen entre 2 y 3 datos faltantes, por lo que en este caso si se pueden suprimir los registros.

Tratamiento de datos faltantes

vf$Parqueaderos[is.na(vf$Parqueaderos)] <- 0
median_piso <- median(vf$Piso, na.rm = TRUE)
vf$Piso[is.na(vf$Piso)] <- median_piso
vf<- vf[!is.na(vf$Id),]
faltantes2<- colSums(is.na(vf))

Los datos faltantes del atributo Parqueaderos pueden generarse por un problema de representación de datos, es decir, que la ausencia del atributo puede corresponder a que la vivienda no tiene parqueadero, por lo que se imputaron con cero.

Por su lado, los datos faltantes de la variable piso, se reemplazaron por la mediana de la misma, para que no se distorsione en caso de la existencia de datos atípicos, no obstante, resulta prudente aclarar que, no se tiene información precisa de que esta variable represente el mismo atributo para casas como para apartamentos, dado que en el primero puede corresponder al número de pisos de la vivienda, mientras que en el segundo, al nivel en donde se encuentra ubicada la vivienda, por lo que termina siendo una variable generadora de ruido, más aún porque al filtrar el dataset por casas y pisos, se encuentran casas de 10 pisos, lo que no tiene sentido, caso contrario si se hiciera referencia al piso de un apartamento.

Finalmente, se eliminaron los registros de las demás variables que tenían sólo 2 y 3 datos faltantes.

A continuación, se verifica que no hayan quedado datos faltantes:

library(naniar)
gg_miss_var(vf) + labs(x="Variables", y = "Datos Faltantes") +
  theme_grey()

El gráfico anterior proporciona información acerca de las variables y la cantidad de datos no observados, por lo que se concluye que la base de datos ahora se encuentra completa, sin embargo, aún se debe continuar con la limpieza de la misma.

Verificar registros duplicados

duplicados = vf[duplicated(vf), ]
if (nrow(duplicados) == 0) {
  message("No se detectaron registros duplicados")
} else {
  print(duplicados)
}
## No se detectaron registros duplicados

Verificar datos atípicos

par(mfrow = c(1, 4))
boxplot(x = vf$Piso, col="#00B2EE", main="Variable Piso")
boxplot(x = vf$Estrato, col="#CDAD00", main="Variable Estrato")
boxplot(x = vf$Parqueaderos, col="#B23AEE", main="Variable parqueaderos")
boxplot(x = vf$Baños, col="#CD1076", main="Variable Baños")

par(mfrow = c(1, 3))
boxplot(x = vf$Precio, col="#7FFF00", main="Variable Precio")
boxplot(x = vf$Área, col="aquamarine2", main="Variable Área")
boxplot(x = vf$Habitaciones, col="#C1CDC1", main="Variable Habitaciones")

Mediante el diagrama de cajas y bigotes, se encuentra que, los atributos Piso, Parqueaderos, Baños, Precio, Área y Habitaciones son los que presentan datos extremos. Ahora, se procederá a cuantificar y corroborar esta información mediante el método matemático de la desviación estándar, en donde se consideran datos atípicos a todos aquellos que se encuentran por encima o por debajo de 3 desviaciones respecto a la media de la variable:

# Calcular la media
mean_Piso <- mean(vf$Piso, na.rm = TRUE)
mean_Parqueaderos <- mean(vf$Parqueaderos, na.rm = TRUE)
mean_Baños <- mean(vf$Baños, na.rm = TRUE)
mean_Habitaciones <- mean(vf$Habitaciones, na.rm = TRUE)
mean_Precio <- mean(vf$Precio, na.rm = TRUE)
mean_Área <- mean(vf$Área, na.rm = TRUE)

# Calcular la desviación estándar
std_Piso <- sd(vf$Piso, na.rm = TRUE)
std_Parqueaderos <- sd(vf$Parqueaderos, na.rm = TRUE)
std_Baños <- sd(vf$Baños, na.rm = TRUE)
std_Habitaciones <- sd(vf$Habitaciones, na.rm = TRUE)
std_Precio <- sd(vf$Precio, na.rm = TRUE)
std_Área <- sd(vf$Área, na.rm = TRUE)

# Calcular el número de outliers
outliers_Piso <- sum(abs(vf$Piso - mean_Piso) > 3 * std_Piso)
outliers_Parqueaderos <- sum(abs(vf$Parqueaderos - mean_Parqueaderos) > 3 * std_Parqueaderos)
outliers_Baños <- sum(abs(vf$Baños - mean_Baños) > 3 * std_Baños)
outliers_Habitaciones <- sum(abs(vf$Habitaciones - mean_Habitaciones) > 3 * std_Habitaciones)
outliers_Precio <- sum(abs(vf$Precio - mean_Precio) > 3 * std_Precio)
outliers_Área <- sum(abs(vf$Área - mean_Área) > 3 * std_Área)

# Mostrar los resultados
resultados_outliers <- list( outliers_Piso = outliers_Piso,
                             outliers_Parqueaderos = outliers_Parqueaderos,
                             outliers_Baños = outliers_Baños,
                             outliers_Habitaciones = outliers_Habitaciones,
                             outliers_Precio = outliers_Precio,
                             outliers_Área = outliers_Área)
print(resultados_outliers)
## $outliers_Piso
## [1] 167
## 
## $outliers_Parqueaderos
## [1] 115
## 
## $outliers_Baños
## [1] 72
## 
## $outliers_Habitaciones
## [1] 272
## 
## $outliers_Precio
## [1] 176
## 
## $outliers_Área
## [1] 130

Se eliminan los datos atípicos

outlier_indices <- unique(c(
  which(vf$Piso %in% outliers_Piso),
  which(vf$Parqueaderos %in% outliers_Parqueaderos),
  which(vf$Baños %in% outliers_Baños),
  which(vf$Habitaciones %in% outliers_Habitaciones),
  which(vf$Precio %in% outliers_Precio),
  which(vf$Área %in% outliers_Área)
))
vf <- vf[-outlier_indices, ]
shape <- dim(vf)
print(shape)
## [1] 8243   13

Una vez eliminados los registros con datos atípicos, queda una dataset final de 8.243 registros y 13 atrributos.

Se visualizan los datos categóricos

tipovivienda = ggplot(vf, aes(Zona, fill=Tipo) ) +
  labs(title = "Tipo de vivienda x Zona")+ylab("Cantidad") +
  theme(plot.title = element_text(size = rel(1.5), colour = "black"))

tipovivienda+geom_bar(position="stack") + scale_fill_manual(values = c("green", "yellow")) +
  theme(axis.title.x = element_text(face="bold", size=10))

Se observa que el atributo Zona se divide en cinco zonas, mientras que el atributo Tipo en dos tipos, resaltando que la mayor cantidad de viviendas se encuentra en la Zona Sur y que mayoritariamente son apartamentos, seguido de la Zona Norte que concentran la segunda mayor cantidad de viviendas, en donde también sobresalen que la mayoría son apartamentos.

Se calcula la correlación entre atributos

# Seleccionar las columnas específicas
selected_columns <- c("Piso", "Parqueaderos", "Estrato", "Baños", "Habitaciones", "Precio", "Área", "Longitud", "Latitud")
numerical_data <- vf[, selected_columns]

# Calcular la matriz de correlación
correlation_matrix <- cor(numerical_data, use = "complete.obs")

# Mostrar la matriz de correlación
corrplot(correlation_matrix, method = "color", col = colorRampPalette(c("red", "white", "blue"))(200), 
         tl.cex = 0.8, tl.col = "black", number.cex = 0.7, addCoef.col = "black", 
         title = "Matriz de Correlación", mar = c(0,0,1,0))

# Identificar atributos redundantes (correlación mayor a 0.85 o menor a -0.85)
redundant_pairs <- data.frame(A = character(), B = character(), Correlation = double())

threshold <- 0.85

for (i in 1:(ncol(correlation_matrix)-1)) {
  for (j in (i+1):ncol(correlation_matrix)) {
    if (abs(correlation_matrix[i, j]) > threshold) {
      redundant_pairs <- rbind(redundant_pairs, data.frame(A = colnames(correlation_matrix)[i], 
                                                           B = colnames(correlation_matrix)[j], 
                                                           Correlation = correlation_matrix[i, j]))
    }
  }
}

# Mostrar atributos redundantes
if (nrow(redundant_pairs) > 0) {
  for (i in 1:nrow(redundant_pairs)) {
    cat(sprintf("Par de atributos redundantes: %s y %s con correlación de %.2f\n", 
                redundant_pairs$A[i], redundant_pairs$B[i], redundant_pairs$Correlation[i]))
  }
} else {
  cat("No se evidencian atributos redundantes a través del método de correlación.\n")
}
## No se evidencian atributos redundantes a través del método de correlación.

A pesar de que no son redundantes debido a que la correlación no es fuerte, si se logra observar que los atributos con mayor correlación positiva moderada son Área y Precio, lo cual es consistente con la realidad, dado que indica que a mayor área de la vivienda, mayor será el precio de venta. Esta relación se puede reflejar mejor en el siguiente gráfico:

ggplot(vf, aes(x = Área, y = Precio, color= factor(Tipo))) +
  geom_point() +
  facet_wrap(~ Tipo) +
  stat_smooth(method = "loess", formula = y ~ x) +
  scale_x_continuous(labels = scales::number_format(scale = 2, accuracy = 2, big.mark = ",")) +
  scale_y_continuous(labels = scales::number_format(scale = 2, accuracy = 2, big.mark = ","))+
 labs(title = "Precio x Área y Tipo")

Hasta este punto se puede inferir que, la relación entre precio y área es mayor en las viviendas tipo casas que en apartamentos, esto se debe a que se valoran más las extensiones de las casas, dado que se le pueden crear más atributos en la construcción, tales como habitaciones, baños, parqueaderos, entre otros, mientras que para los apartamentos hay una limitación por el espacio. En consecuencia, el área no es una variable que explique en alto grado el precio de los apartamentos, como si podría serlo el estrato y la zona, mientras que si podría explicar mejor la variabilidad del precio en las casas.

Finalmente, en esta primera parte del informe, no se utilizarán las variables Longitud y Latitud, debido a que las Zonas de la ciudad también pueden representar la ubicación de las viviendas dentro del sistema de coordenadas.

2.2 Análisis de componentes principales

Reducir la dimensionalidad del conjunto de datos y visualizar la estructura de las variables en componentes principales para identificar características clave que influyen en la variación de precios y oferta del mercado.

El método de PCA, además de lo anterior, busca conservar la mayor parte de la variabilidad presente en el conjunto de datos original, por lo que transforma las variables originales en un nuevo conjunto de datos de variables no correlacionadas, que se denominan componentes principales. Para llegar a esto, se ejecutan los siguientes pasos:

Normalización de variables

Debido a que para calcular las componentes principales, primero se deben hallar las varianzas y covarianzas de los datos, las cuales son sensibles a grandes valores, por lo tanto, se procede con la estandarización de los atributos que se utilizaran para hallar las PCA.

vfz=vf[,c(4,5,6,7,8,9)]
vfz= scale(vfz)
head(vfz)
##         Estrato     Precio       Área Parqueaderos       Baños Habitaciones
## [1,] -1.5872053 -0.5592655 -0.7340478   -0.3874333 -0.07760334    1.6355960
## [2,] -1.5872053 -0.3470407 -0.3857262   -0.3874333 -0.77594871   -0.4150354
## [3,] -1.5872053 -0.2560873  0.3109171    0.4151836 -0.77594871    0.2685084
## [4,] -0.6149005 -0.1044981  0.7289031    1.2178004  1.31908739   -0.4150354
## [5,]  0.3574043 -0.5289477 -0.5947192   -0.3874333 -0.77594871   -0.4150354
## [6,]  0.3574043 -0.5895834 -0.6156184   -0.3874333 -0.07760334   -0.4150354

Cálculo de componentes principales

vfz.pca=prcomp(vfz)
vfz.pca
## Standard deviations (1, .., p=6):
## [1] 1.8491646 1.1219551 0.6768456 0.6581724 0.4906751 0.4355848
## 
## Rotation (n x k) = (6 x 6):
##                    PC1        PC2         PC3         PC4         PC5
## Estrato      0.3307231 -0.5817181  0.55349643  0.09489379 -0.46079107
## Precio       0.4779451 -0.1887478 -0.02561413 -0.36089498  0.22290663
## Área         0.4418804  0.2381815 -0.26779429 -0.62706453 -0.28070102
## Parqueaderos 0.4096592 -0.2604913 -0.67379212  0.55038693 -0.04911713
## Baños        0.4667978  0.1925411  0.35632780  0.19597534  0.67804660
## Habitaciones 0.2849764  0.6814104  0.20076484  0.35525757 -0.44388228
##                      PC6
## Estrato       0.15663557
## Precio       -0.74522086
## Área          0.45198947
## Parqueaderos  0.07063669
## Baños         0.34627259
## Habitaciones -0.30153348
res.pca <- PCA(vfz, ncp=6,graph = F)
fviz_eig(res.pca, addlabels = TRUE, barcolor = "#4682B4", barfill = "#4F94CD")

Se observa que la primer componente explica el 57% de la varianza de los datos, mientras que la segunda el 21% y la tercera el 7.6%, lo que indica que las tres primeras componentes explican el 85.6% de la variabilidad, recogiendo así buena parte del total de varianza con menos variables.

Cálculo de la contribución

var <- get_pca_var(res.pca)
var$contrib
##                  Dim.1     Dim.2       Dim.3      Dim.4      Dim.5      Dim.6
## Estrato      10.937779 33.839598 30.63582940  0.9004831 21.2328409  2.4534701
## Precio       22.843149  3.562573  0.06560836 13.0245190  4.9687367 55.5354137
## Área         19.525831  5.673044  7.17137815 39.3209926  7.8793061 20.4294477
## Parqueaderos 16.782067  6.785571 45.39958160 30.2925777  0.2412493  0.4989541
## Baños        21.790020  3.707206 12.69695043  3.8406335 45.9747192 11.9904705
## Habitaciones  8.121154 46.432008  4.03065206 12.6207941 19.7031478  9.0922439
fviz_pca_var(res.pca, col.var = "contrib", gradient.cols =c("yellow", "green", "red"), repel = TRUE)

fviz_contrib(res.pca, choice = "var", axes = 1, top = 10, fill ="#C0FF3E")

fviz_contrib(res.pca, choice = "var", axes = 2, top = 10, fill ="#00CDCD")

Se observa que en la primer componente principal, los atributos Precio, Baños y Área son los que mayor contribución realizan, mientras que para la segunda componente los atributos Habitaciones y Estrato son los de mayor contribución. Así, en este punto se puede indicar que la demanda de viviendas está en función del Precio, el área construida, la distribución interna y el estrato socioeconómico.

Revisión de casos individuales

Para explicar mejor el sentido de las dimensiones, se proceden a seleccionar cuatro viviendas, que se describen a continuación:

vfindividual <- vf[,c(1,4,5,6,7,8,9)]

vfindividual=textshape::column_to_rownames(vfindividual, loc = 1)

datos <- rbind(vfindividual["6100",], 
              vfindividual["7510",],
              vfindividual["78",],
              vfindividual["855",])

datos = as.data.frame(datos)
rownames(datos) = c("Id 6100","Id 7510","Id 0078","Id 0855")
datos
##         Estrato Precio Área Parqueaderos Baños Habitaciones
## Id 6100       5   1999  800            5     7            5
## Id 7510       6   1950  400            4     5            3
## Id 0078       3     58   50            1     1            2
## Id 0855       3     62   61            0     1            2
casos1 <- rbind(vfz.pca$x[6100,1:2],vfz.pca$x[7510,1:2]) # CP1
rownames(casos1) = c("6100","7510")
casos1 <- as.data.frame(casos1)

casos2 <- rbind(vfz.pca$x[78,1:2], vfz.pca$x[855,1:2]) # CP2
rownames(casos2) = c("0078","0855")
casos2 <- as.data.frame(casos2)

fviz_pca_ind(vfz.pca, col.ind = "#E0EEEE", gradient.cols = c("#FFD700", 
                                                                    "#97FFFF",
                                                                    "#E066FF"))+
  geom_point(data = casos1, aes(x = PC1, y = PC2), color = "red", size = 3) +
  geom_point(data = casos2, aes(x = PC1, y = PC2), color = "green", size = 3)

En conjunto, estas dos dimensiones capturan el 78% de la variabilidad en los datos, se observa que las viviendas seleccionadas (puntos rojos y verdes) están situadas cerca del origen, lo que sugiere que no están muy alejadas de la mayoría de las observaciones en las dos dimensiones, en otras palabras, tienen perfiles similares en las dimensiones principales en comparación con el resto de los datos, por lo que no hay una diferencia significativa en las características capturadas por las dos primeras dimensiones del PCA.

2.3 Análisis de Conglomerados

Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas de las ofertas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.

El método de análisis de conglomerados se utiliza para descubrir estructuras subyacentes en los datos, permitiendo agrupar objetos de manera lógica y útil, teniendo en cuenta la similitud y distancia de los individuos de los grupos. Para llegar a esto, se ejecutan los siguientes pasos:

Selección del número de clúster método codo

vfc=vf[,c(4,5,6,7,8,9)]
vfc= scale(vfc)
fviz_nbclust(vfc, kmeans, method = "wss") +geom_vline(xintercept = 4, lty = 2, col="red")

Bajo el método del codo de distribución, que es el punto en la gráfica donde la reducción en la suma de las distancias se vuelve menos pronunciada, se podría afirmar que el número de clúster a utilizar es 4.

Selección del número de clúster método Calinski-Harabasz

ch_scores <- vector()
for (k in 2:5) {
  kmeans_result <- kmeans(vfc, centers = k, nstart = 25)
  ch_scores[k] <- cluster.stats(dist(vfc), kmeans_result$cluster)$ch
}
plot(2:5, ch_scores[2:5], type = "b", pch = 19, frame = FALSE,
     xlab = "Número de clústeres", ylab = "Índice de Calinski-Harabasz",
     main = "Método de Calinski-Harabasz")

En este método, se considera como óptimo, el número de clústers en donde el índice sea más alto. Para este caso se sitúa en 2.

Selección del número de clúster método silueta

fviz_nbclust(vfc, kmeans, method = "silhouette")

El anterior método, también sugiere tomar solo dos clúster, no obstante, se prefiere tomar un rango intermedio, para también esperar contar con una mayor cantidad de varianza. En consecuencia, una vez evaluado el número de clúster por los tres métodos anteriores, se decide seleccionar 3 clúesters, cuyos grupos se muestran a continuación:

set.seed(123)
kmeans3 =kmeans(vfc, centers = 3, nstart = 25)
fviz_cluster(kmeans3, data = vfc)

observaciones <- table(kmeans_result$cluster)
print(observaciones)
## 
##    1    2    3    4    5 
## 1652 2577 2604  573  837
vfo=vf[,c(4,5,6,7,8,9)]
kmeans_result <- kmeans(vfo, centers = 3, nstart = 25)
cluster_means <- aggregate(vfo, by = list(Cluster = kmeans_result$cluster), FUN = mean)
print(cluster_means)
##   Cluster  Estrato    Precio     Área Parqueaderos    Baños Habitaciones
## 1       1 5.788756 1347.2913 435.8043     3.427598 5.119250     4.287905
## 2       2 4.250543  256.5007 111.2060     1.033490 2.469406     3.288740
## 3       3 5.303471  644.2523 269.9108     2.111163 4.220919     4.244841

De los clústeres anteriores, se puede aseverar que:

Los clústeres 1 y 2 se encuentran claramente separados, lo que sugiere que los puntos en estos clústeres son diferentes entre sí en las dimensiones capturadas, especialmente en la dimensión 1, que hace referencia a los valores de Precio, Baños y Área. Por su parte, el clúster 3, cuenta con características intermedias de ambas dimensiones.

Ahora, bajo un análisis más detallado se tiene que:

El clúster 1 se caracteriza en promedio por tener las viviendas con el estrato socioeconómico más alto (6), los Precios de las viviendas ($1.347 millones) y el Área (435 mts2) son los más altos de toda la muestra, también cuentan con más de 3 parqueaderos, más de 5 baños y más de 4 habitaciones. Estas características se asocian más con el tipo de vivienda Casas.

El clúster 2, que se encuentra al otro extremo de las dimensiones, se caracteriza en promedio por tener las viviendas con el estrato socioeconómico más bajo (4), los Precios de las viviendas ($256 millones) y el Área (111 mts2) son los más bajos de toda la muestra, además cuentan con 1 parqueadero, más de 2 baños y más de 3 habitaciones. Estas características se asocian más con el tipo de vivienda Apartamentos.

El clúster 3, que se encuentra en el centro, se caracteriza en promedio por tener viviendas con estrato socioeconómico (5), los Precios de las viviendas ($644 millones) y el (Área 269 mts2) son los segundos más altos de toda la muestra, además cuentan con más de 2 parqueaderos, más de 4 baños y más de 4 habitaciones. Estas características se asocian tanto para casas como para apartamentos.

2.4 Análisis de Correspondencia

Examinar la relación entre las variables categóricas (tipo de vivienda, zona y Estrato), para identificar patrones de comportamiento de la oferta en mercado inmobiliario.

La técnica de análisis de correspondencia se utiliza en esencia para las variables categóricas, permitiendo explorar y visualizar las relaciones entre atributos en una tabla de contingencia. Para realizarlo se siguen los siguientes pasos:

Construcción de la tabla cruzada

ftable(vf$Tipo, vf$Zona, vf$Estrato)
##                              3    4    5    6
##                                              
## Apartamento Zona Centro     13    7    3    0
##             Zona Norte     337  244  494  115
##             Zona Oeste      29   58  227  707
##             Zona Oriente    58    2    1    1
##             Zona Sur       201 1090 1020  446
## Casa        Zona Centro     90    7    1    1
##             Zona Norte     228  160  270   55
##             Zona Oeste      25   26   59   59
##             Zona Oriente   280    6    1    0
##             Zona Sur       177  517  649  579

No se utilizará la varible barrio, debido a que los mismos se pueden ubicar mejor en cada zona de la ciudad, es decir, los barrios son fijos en cuanto ubicación, como también lo son las zonas.

Ahora, la tabla de frecuencia anterior también se puede representar con el siguiente gráfico:

ggplot(vf,mapping=aes(x=Tipo, y=Estrato, fill=Zona )) +
  geom_boxplot()+
  labs(title = "Estrato x Tipo y Zona",
       x = "Tipo de vivienda",
       y = "Estrato de vivienda")+
  theme(plot.title = element_text(hjust = 0.5))

Se observa que la zona Centro tiene una menor variabilidad en el estrato, concentrándose en el estrato 3, mientras que las zonas Norte y Oriente, presentan mayor variabilidad con viviendas desde el estrato 3 hasta el 6 tanto para casas como para apartamentos. Por su parte, la zona Sur concentra más las viviendas en los estratos 4 y 5.

Verificación de independencia

tabla1 <- table(vf$Zona, vf$Estrato)
colnames(tabla1) <- c("Estrato 3", "Estrato 4", "Estrato 5", "Estrato 6" )
chisq.test(tabla1)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla1
## X-squared = 3809.9, df = 12, p-value < 2.2e-16

Se encuentra que el valor p es muy inferior al nivel de significancia alpha del 5%, por lo que existe evidencia estadística significativa para rechazar la hipótesis nula, por tanto, si existe asociación entre las variables Zona - Estrato.

tabla2 <- table(vf$Tipo, vf$Zona)
chisq.test(tabla2)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla2
## X-squared = 684.91, df = 4, p-value < 2.2e-16

Se encuentra que el valor p también es muy inferior al nivel de significancia alpha del 5%, por lo que existe evidencia estadística significativa para rechazar la hipótesis nula, por tanto, si existe asociación entre las variables Tipo - Zona.

tabla3 <- table(vf$Tipo, vf$Estrato)
chisq.test(tabla3)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla3
## X-squared = 212.91, df = 3, p-value < 2.2e-16

Se encuentra que de nuevo el valor p es muy inferior al nivel de significancia alpha del 5%, por lo que existe evidencia estadística significativa para rechazar la hipótesis nula, por tanto, si existe asociación entre las variables Tipo - Estrato.

Gráfico de correspondencias

A continuación, se presentan las correspondencias dobles para cada par de atributos y al final, se muestra el resultado al combinar las 3 variables categóricas en dos dimensiones.

ASOCIACIÓN ZONA - ESTRATO

resultados_ac1 <- CA(tabla1)

Se pueden observar relaciones entre los estratos y las zonas; las viviendas del estrato 6 se encuentran en la Zona Oeste; las del estrato 3 se encuentran en las Zonas Oriente y Centro; las de los estratos 4 y 5 se ubican en la Zona Sur; y finalmente no es posible establecer una asociación clara entre la Zona norte y los estratos, aunque si se encuentran más próximos a los estratos 5 y 4.

ASOCIACIÓN TIPO - ZONA

datoscor <- data.frame(
  Var1 = as.factor(c(vf$Tipo)),
  Var2 = as.factor(c(vf$Zona))
)
mca <- MCA(datoscor, graph = FALSE)

fviz_mca_var(mca, repel = TRUE) 

categorias_coords <- mca$var$coord
coord = as.data.frame(categorias_coords[, 1:2])
coord = rownames_to_column(coord, var = "Categoria")

En el gráfico anterior si bien no se establecen correspondencias claras, debido a la distancia entre los atributos, se puede apreciar que, tanto apartamentos como casas se encuentran más cerca de las zonas sur y norte. La zona oeste concentra más apartamentos que casas, mientras que las zonas centro y oriente más casas que apartamentos.

Ahora, se integran los tres atributos en un mismo gráfico para ver las correspondencias múltiples:

ASOCIACIÓN ZONA - ESTRATO - TIPO

datoscorcom <- data.frame(
  Var1 = as.factor(c(vf$Tipo)),
  Var2 = as.factor(c(vf$Zona)),
  Var3 = as.factor(c(vf$Estrato))
)
mca2 <- MCA(datoscorcom, graph = FALSE)
fviz_mca_var(mca2, repel = TRUE, col.var = "purple") 

categorias_coordscom <- mca$var$coord
coordenadas = as.data.frame(categorias_coordscom[, 1:2])
coord = rownames_to_column(coordenadas, var = "Categoria")

Se observa que al realizar el análisis con tres variables, la varianza explicada disminuye, esto puede ocurrir porque una de las variable no contribuye significativamente a la explicación de la variabilidad en las primeras dimensiones, lo que provoca que cada dimensión capture una menor proporción de la varianza total.

calcular grado de representatividad

valores_prop <-resultados_ac1$eig ; valores_prop
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.32199794              69.667174                          69.66717
## dim 2 0.12922418              27.958822                          97.62600
## dim 3 0.01097252               2.374005                         100.00000
fviz_screeplot(resultados_ac1, addlabels = TRUE, barcolor = "#4682B4", barfill = "#4F94CD")  +
  ggtitle("Importancia de las Dimensiones en el MCA ZONA - ESTRATO")

Se observa que la primer componente explica el 69.6% de la varianza de los datos, mientras que la segunda el 28%, lo que indica que, las dos primeras componentes explican el 97.6% de la variabilidad.

valores_prop <-mca$eig ; valores_prop
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1  0.6441265               25.76506                          25.76506
## dim 2  0.5000000               20.00000                          45.76506
## dim 3  0.5000000               20.00000                          65.76506
## dim 4  0.5000000               20.00000                          85.76506
## dim 5  0.3558735               14.23494                         100.00000
fviz_screeplot(mca , addlabels = TRUE, barcolor = "#FF8C00", barfill = "orange")  +
  ggtitle("Importancia de las Dimensiones en el MCA TIPO - ZONA")

Se observa que la primer componente explica el 25.7% de la varianza de los datos, mientras que la segunda el 20%, lo que indica que, las dos primeras componentes solo explican el 45.7% de la variabilidad. Lo anterior indica que, ninguna dimensión explica más varianza que una variable original promedio en los datos, por esta razón no era posible apreciar asociaciones directas en el gráfico de dos dimensiones, pues las componentes no alcanzan a recoger una adecuada representación de la variabilidad. Esto también se puede soportar en la lógica de que en una Zona de la ciudad pueden haber tanto casas como apartamentos o también porque la base de datos no se encuentra balanceada entre la cantidad de registros de viviendas para cada una de las Zonas representadas.

valores_prop <-mca2$eig ; valores_prop
##       eigenvalue percentage of variance cumulative percentage of variance
## dim 1  0.5612732              21.047744                          21.04774
## dim 2  0.4538625              17.019844                          38.06759
## dim 3  0.3798355              14.243831                          52.31142
## dim 4  0.3334083              12.502810                          64.81423
## dim 5  0.3245827              12.171849                          76.98608
## dim 6  0.2715077              10.181539                          87.16762
## dim 7  0.2004957               7.518588                          94.68620
## dim 8  0.1417012               5.313796                         100.00000
fviz_screeplot(mca2 , addlabels = TRUE, barcolor = "#CD4F39", barfill = "#FF6347")  +
  ggtitle("Importancia de las Dimensiones en el MCA TIPO - ZONA - ESTRATO")

En este caso, al haber más variables en el modelo, se requiere una mayor cantidad de dimensiones para explicar la varianza total. Esta situación se presenta principalmente en datos categóricos, debido a que una misma característica puede estar presente en varios atributos; por ejemplo, tanto casas como apartamentos se encuentran en todos los estratos y en todas las zonas. Al observar las componentes, se obtiene que la primer explica el 21% de la varianza de los datos, mientras que la segunda explica el 17%, lo que indica que las dos primeras componentes explican tan sólo el 38% de la variabilidad.

3 CONCLUSIONES

Teniendo en cuenta la relevancia que tiene el sector inmobiliario en la economía nacional, que es generadora de empleos y de ingresos para el país, se puede afirmar que para el caso de la empresa que está interesada en expandir sus operaciones a la ciudad de Cali, cuenta con un panorama alentador para generar beneficios socioeconómicos. Lo anterior es producto de las características que tienen las viviendas observadas, de las cuales se puede inferir que:

  • Desde el análisis de datos, hay diversificación de las viviendas en cada una de las zonas de la ciudad, sobresaliendo el precio de las viviendas tipo casa, que tiende a incrementar en la medida en que aumenta el área construida, lo que conlleva a pensar en estrategias para ofrecer las casas a grupos de personas o clientes de mayores ingresos, que prefieran más espacio que cualquier otro atributo. Caso contrario ocurre con los apartamentos, en donde prácticamente el precio no se determina tanto por el área construida, sino por la zona y estrato, por lo que este tipo de viviendas se puede ofrecer mejor a un público que prefiera la ubicación como atributo de decisión.

  • Desde el análisis de componentes principales se encontró que con sólo realizar una combinación lineal de menos variables, se puede establecer que en una de las dimensiones los atributos precio, cantidad de baños y área Construida son los que recogen la mayor variabilidad de la muestra de viviendas, mientras que en la otra dimensión los atributos cantidad de habitaciones y estrato socioeconómico son las más relevante agrupando la mayor parte de la variación. En consecuencia, se puede afirmar que estas dos dimensiones capturan la mayor parte de la información esencial de las viviendas, que, además, van a mejorar la eficiencia de modelos predictivos cuando se requieran ejecutar, dado que disminuye la complejidad y el sobreajuste al reducir las dimensiones.

  • Desde el análisis de conglomerados la muestra de viviendas se puede dividir en 3 grupos o segmentos representativos, destacando que el clúster 1 abarca mayoritariamente a las viviendas tipo casas, y que tienen precios promedio de venta más altos, con más área construida y mayores atributos en cuanto a la cantidad de habitaciones, baños y parqueaderos. El clúster 2 abarca mayoritariamente a las viviendas tipo apartamento, y que tienen precios promedio de venta más bajos, con menor área construida y menores atributos en cuanto a la distribución interna de las viviendas. Por su parte, el clúster 3 es intermedio en cuanto al precio promedio de venta y la demás cantidad de atributos de las viviendas, está compuesto por casas y apartamentos. Por lo anterior, las viviendas del clúster 1 pueden ser ofrecidas a clientes que tienen mayores ingresos y que prefieren casas con mayor área construida; las del clúster 2 a clientes con ingresos menores y que prefieran apartamentos; y las del clúster 3 a personas con ingresos promedios y que prefieran mejor ubicación que área construida.

  • Desde el análisis de correspondencia múltiples se identificó que hay una asociación entre los atributos zona y estrato, destacando que, las viviendas con el estrato más alto se encuentran en la zona oeste y las de estrato más bajo en las zonas centro y oriente. Por su parte, las zonas sur y norte concentran viviendas de estrato medio – alto. También se pudo establecer que, las zonas sur y norte son las que más cantidad de viviendas concentra, mientras que la Zona centro y oriente son las que menor cantidad de viviendas tienen. Adicional, la zona oeste está más relacionada con los apartamentos. Así, resulta ventajoso para la inmobiliaria establecer una segmentación de clientes, de acuerdo con las preferencias de ubicación y estrato de las viviendas, que a su vez se relacionan con el área construida, puesto que las casas que son las que mayor área tienen están en el norte y sur de la Ciudad, mientras que los apartamentos con mayor área se encuentran en el oeste.

4 RECOMENDACIONES

Con el objetivo de posicionarse en el mercado, obteniendo mayores beneficios, se plantea la necesedidad de recomendar a la empresa:

  • Realizar campañas de mercadeo y publicidad orientadas a la segmentación del público, según las preferencias de las viviendas; casas - apartamentos y estrato – ubicación. De esta manera podrán clasificar a los potenciales clientes de acuerdo con su nivel de ingresos promedio.

  • Promover la venta de viviendas en las zonas sur y norte, dado que son las de mayores precios de venta promedio, especialmente las casas, que resultan ofreciéndose a un precio mayor debido al área construida. Asimismo, en la zona oeste promover la venta de apartamentos, que mayoritariamente se encuentran ubicadas en el estrato 6, teniendo un precio promedio de venta alto en función del estrato socioeconómico.

  • Las zonas centro y oriente son las de menores cantidad de viviendas y a la vez las de menores precios promedios de venta, por lo que se podría pensar en realizar inversiones de largo plazo, adquiriendo viviendas económicas para que se valoricen o también, adquirir lotes para desarrollar nuevos proyectos, buscando maximizar beneficios a través de una mayor cantidad de viviendas que se puedan vender, caso contrario a lo que sucede en la zona oeste, en donde hay menor cantidad de viviendas, en este caso apartamentos, pero que por su ubicación se venden a un precio promedio mayor.

  • En general, la compañía se debe centrar en ofrecer viviendas a la medida de las necesidades de los clientes en cuanto a preferencias de ubicación y tamaño, partiendo de las características identificadas para cada segmento.

  • Finalmente, resulta relevante realizar un estudio de mercado en la zona sur, para descubrir otros factores asociados al nivel de valorización que han tenido las viviendas, dado que es la Zona que más cantidad de viviendas concentra, por lo que es probable que el precio promedio de las mismas se incremente en el mediano plazo.