1. Introducción

La expansión del mercado inmobiliario en Cali ha sido notable en los últimos años, impulsada por diversos factores como el crecimiento demográfico, la atracción de inversión extranjera directa y el desarrollo continuo de proyectos residenciales y comerciales. En 2022, las ventas del sector en Cali llegaron a $6700 millones y en 2023 a $6100 mil millones. Se espera que este sector continue creciendo durante los próximos años, permitiendo un desarrollo dinámico en la economía regional.

En este contexto, la empresa B&C ha recopilado una amplia gama de datos sobre propiedades inmobiliarias, que incluyen información detallada sobre precios, ubicaciones, características y tendencias de venta en Cali. Con el objetivo de capitalizar estas oportunidades de mercado, este informe presenta un análisis estadístico descriptivo exhaustivo, destinado a proporcionar a la empresa B&C una visión estratégica sólida para potenciar su presencia y competitividad en el sector inmobiliario de la ciudad.

2. Objetivo

Realizar un análisis descriptivo de los datos, para identificar las tendencias y patrones de la oferta de vivienda en Cali, contemplando variables como precios, tipos de viviendas y características más relevantes, con el fin de proporcionar una comprensión detallada del panorama actual del mercado inmobiliario, lo cual servirá como fundamento para el desarrollo de un plan estratégico comercial sólido y efectivo para la empresa B&C.

3. Método

Para llevar a cabo el análisis de los datos, se empleó el software estadístico R en su versión 4.3.2, siguiendo los siguientes pasos:

  • Importación de datos: Se realizo el cargue de la base de datos viviendas_faltantes desde la librería paqueteMETODOS asociada al paquete devtools.

  • Comprensión de los datos: Se llevó a cabo un análisis exploratorio exhaustivo de las variables incluidas en la base de datos. Este análisis permitió una caracterización detallada de cada una, identificando posibles fallos en la calidad de los datos, como valores nulos, datos atípicos o falta de estandarización.

  • Limpieza y fusión de datos: Se llevó a cabo una exhaustiva limpieza de datos para abordar las filas que presentaban información faltante. Aquellas observaciones con datos incompletos fueron excluidas del análisis para garantizar la integridad de los resultados. Además, se procedió a fusionar los datos de precio y área construida con el propósito de crear una nueva variable: precio por metro cuadrado. Esta fusión permitió identificar y descartar valores atípicos en el precio por metro cuadrado, asegurando la calidad de los datos utilizados en el análisis.

  • Estandarización de los datos: Se llevó a cabo el proceso de estandarización para variables como tipo, barrio, latitud y longitud. En el caso de la variable “barrio”, se realizó una investigación adicional mediante geolocalización para garantizar una agrupación adecuada de los barrios entorno a sus localizaciones.

  • Imputación de datos: Se implementaron métodos adecuados para el manejo de datos faltantes en variables significativas como numero de piso y numero de parqueaderos, asegurando así una base de datos completa y fiable.

  • Análisis descriptivo: Una vez completado el tratamiento de la base de datos, se procedió al análisis descriptivo. En este análisis se generó un informe estadístico detallado que proporciona información relevante sobre el precio de las viviendas en diferentes zonas, los tipos de viviendas más ofertadas y las características más destacadas de la oferta de vivienda en Cali.

Las etapas de importación, comprensión, limpieza y estandarización de datos se detallarán en los anexos del documento.

4. Resultados

4.1. Precio de viviendas por zona

a) Proporción de tipo de viviendas por zona: Para comprender mejor el precio de las viviendas en cada zona, es crucial analizar la distribución de la oferta de inmuebles en cada área. Según el gráfico presentado, se observa que el 80% de las viviendas disponibles se encuentran en las zonas Sur y Norte. Específicamente, el 56.8% se sitúan en la zona Sur, lo que equivale a 4675 unidades, mientras que el 23.2% se localiza en la zona Norte, representando 1909 unidades. Por otro lado, la zona Centro muestra la menor oferta, con solo el 1.4% del total, equivalente a 118 unidades.

# Distribución de viviendas por zona
frecuenciazona <- table(basedatos$zona)
pie(frecuenciazona,
    main = "Distribución de viviendas por zona",
    col = c("#f95738","#ee964b", "#f4d35e","#0d3b66", "#8FBC8F"),
    labels = sprintf("%s\n%d (%.1f%%)", names(frecuenciazona), frecuenciazona, prop.table(frecuenciazona) * 100)) 

b) Comparación de precio de vivienda por zonas: Una vez entendido la oferta de viviendas por zonas, se verifica la posible relación entre oferta por zona y su respectivo precio. Por tal motivo, en los siguientes gráficos se realiza el comparativo de precio de vivienda por zona (gráfica izquierda) y el precio/m2 por zona (gráfica derecha).

# Precio de viviendas por zona
par(mfrow = c(1, 2))
par(mar = c(5, 3, 1, 2) + 1)
boxplot(basedatos$preciom~basedatos$zona,
        main = "Precio de vivienda por zonas",
        ylab = "Precio (MM)",
        xlab = "",
        las = 2,
        col=c("#f95738","#ee964b", "#f4d35e","#0d3b66", "#8FBC8F"))
axis(side = 2, at = seq(0, 2000, by = 100), labels = FALSE, cex.axis = 0.1)
boxplot(basedatos$Preciometro~basedatos$zona,
        main = "Precio/m2 de vivienda por zonas",
        ylab = "Precio/m2(MM/m2)",
        xlab = "",
        las = 2,
        col=c("#f95738","#ee964b", "#f4d35e","#0d3b66", "#8FBC8F"))
axis(side = 2, at = seq(0, 10, by = 0.5), labels = FALSE, cex.axis = 0.1)

Realizando un análisis descriptivo por zona, desde la más valorizada hasta la más depreciada, se observa lo siguiente:

  • En la zona oeste, se encuentran los precios más altos de viviendas, con un amplio rango que va desde los $85 MM hasta los $1999 MM, una mediana es de $578 MM, y un IQR de $505 MM. En cuanto al precio/m2 se evidencia un patrón similar, siendo esta la zona más costosa, con precios por metro cuadrado que van desde los $0.8 MM hasta los $6.7 MM, con una mediana de $3.7 MM y un IQR de $1.5 MM.

  • En las zonas centro, norte y sur, los precios de las viviendas muestran medianas similares, oscilando entre $293 MM y $315 MM. La principal disparidad radica en la dispersión entre estas zonas; los precios están más concentrados en la zona centro (IQR = $174 MM) y más dispersos en la zona sur (IQR = $280 MM). En cuanto al precio/m2, tanto la zona norte como la sur presentan un IQR más alto de $1.4 MM y $1.1 MM, respectivamente. Por otro lado, la zona centro exhibe un precio por metro cuadrado más bajo y menos variable, con una mediana de $1.5 MM, un rango de $2.1 MM y IQR de $0.6 MM.

  • En la zona oriente, se concentran los precios mas bajos de vivienda, con una mediana de $206 MM y un IQR de $142 MM. Del mismo modo, el precio/m2 evidenciado es el mas bajo con tan solo una mediana de $1.3 MM y un IQR de $0.7 MM.

c) Relación precio-área construida por zona: En la siguiente gráfica se observa cómo el precio de las viviendas está relacionado con el área construida, en donde, los precios tienden a aumentar a medida que aumenta el tamaño de los inmuebles, y viceversa. Además, mediante las aproximaciones proporcionadas por las regresiones lineales, se evidencia la disparidad en los precios de vivienda entre las diferentes zonas, lo que confirma la información obtenida en el ítem anterior. En particular, se destaca que la zona oeste muestra una pendiente más pronunciada, lo que se traduce en costos por metro cuadrado más altos, mientras que la zona oriente ofrece precios más accesibles para inmuebles de mayor tamaño.

# Relación precio-área construida por zona
ggplot(data = basedatos, aes(x = areaconst, y = preciom, color = zona)) +
  geom_point() +  # Añadir los puntos
  geom_smooth(method = "lm", se = FALSE) +  
  scale_color_manual(values = c("#f95738","#ee964b", "#f4d35e","#0d3b66", "#8FBC8F")) + 
  labs(x = "Área Construida", y = "Precio", color = "Zona") + 
  ggtitle("Gráfico de Puntos: Precio vs. Área Construida por Zona") +  # Título del gráfico
  theme_minimal()  
## `geom_smooth()` using formula = 'y ~ x'

c) Mapa de geolocalización de viviendas por precio: Por medio del siguiente mapa, es posible distinguir de forma visual los diferentes hallazgos declarados en los anteriores puntos. En él, se observa una gran concentración de viviendas ofertadas en las zonas sur, norte y oeste, mientras que la densidad de puntos es menor en las zonas centro y oriente, indicando una oferta de inmuebles más reducida en estas áreas. Además, se puede notar que a medida que los precios son más altos, los puntos marcados en el mapa son más oscuros. Por lo tanto, las zonas sur y oeste presentan una mayor intensidad de color, ya que en estas áreas se encuentran las viviendas más costosas.

# Mapa por geolozalizacion de viviendas por precio
colores <- colorNumeric(palette = c("#ADD8E6","#16365C"), domain = basedatos$preciom)
leaflet(data = basedatos) %>%
  addTiles() %>%  
  addCircles(~longitud, ~latitud, weight = 1, radius = 50, color = ~colores(preciom), fillOpacity = 0.8, popup = ~paste("Precio:", preciom)) %>%
  addLegend("bottomright", colors = "#ADD8E6", labels = "Precio", opacity = 1) %>%
  setView(lng = -76.5225, lat = 3.43722, zoom = 11)

4.2. Tipo de viviendas mas ofertadas.

a) Distribución de tipos de viviendas: De las 8232 viviendas ofertadas en la ciudad de Cali, el 61.4% (5053 unidades) corresponden a inmuebles tipo apartamento, mientras que el 38.6% (3179 unidades) corresponden a inmuebles tipo casa.

# Distribución de tipos de viviendas
frecuenciatipo <- table(basedatos$tipo)
pie(frecuenciatipo,
    main = "Distribución de tipos de vivienda",
    col = c("#ee964b", "#f4d35e"),
    labels = sprintf("%s\n%d (%.1f%%)", names(frecuenciatipo), frecuenciatipo, prop.table(frecuenciatipo) * 100)) 

a) Tipos de vivienda por zona y estrato: En los gráficos posteriores, se identifica la relación entre numero de viviendas por zona y tipo (gráfica izquierda) y numero de viviendas por zona y estrato (gráfica derecha).

Para la primera gráfica, se evidencia que las zonas oriente y centro se componen principalmente de viviendas tipo casa, mientras que la zona oeste está predominantemente conformada por viviendas tipo apartamento. Por otro lado, las zonas norte y sur mantienen una proporción aproximada de 60% de apartamentos y 40% de casas.

Al profundizar en los datos, se observa que la mayoría de los apartamentos en Cali se concentran en las zonas sur, norte y oeste, donde la zona sur representa el 55% con 2756 de los 5053 inmuebles. Por el contrario, las zonas oriente y centro poseen un mix de apartamentos bajos, con tan solo 80 viviendas, lo que se traduce en un 2%. De manera similar, esta tendencia se refleja en las casas, ya que entre las tres zonas sur, norte y oeste se encuentra el 88% de las viviendas tipo casa, siendo la zona sur la más representativa con el 60%, con 1919 de 3179 casas.

# Tipo de viviendas por Zona y estrato
par(mfrow = c(1, 2))
par(mar = c(6, 5, 3, 7) )
tipovivienda1 <- table(basedatos$tipo,basedatos$zona)
bp =barplot(tipovivienda1, main="No. viviendas por zona y tipo",  
        ylab = "No. de viviendas",
        col=c("#ee964b", "#f4d35e"),
        legend.text = FALSE,
        las=2,ylim = c(0,5000))
tipovivienda2 <- table(basedatos$tipo,basedatos$estrato)
barplot(tipovivienda2, main="No. viviendas por zona y estrato",  
        ylab = "No. de viviendas",
        col=c("#ee964b", "#f4d35e"),
        legend.text = TRUE,
        las=1,ylim = c(0,3000),
        args.legend = list(x = "topright", bty = "n", inset = c(-1, 0)
        ))

Para la segunda gráfica, se puede observar que el estrato 5 presenta la mayor cantidad de viviendas, seguido por los estratos 4 y 6, mientras que el estrato 3 tiene la menor representación. Además, para los estratos 4, 5 y 6, la proporción de apartamentos es aproximadamente igual, representando alrededor del 65% de la oferta por estrato. Sin embargo, para el estrato 3, la proporción de apartamentos se reduce al 44%, predominando la oferta de casas con un 56%.

4.3. Caracteristicas de viviendas mas relevantes.

a) Estrato: De todas las viviendas disponibles en Cali, los estratos 5 y 4 destacan al concentrar la mayor proporción de inmuebles, representando conjuntamente el 59.1% (4863 viviendas). Entre ellos, el estrato 5 sobresale con un 33.3% (2741 viviendas), mientras que el estrato 3 muestra una presencia significativamente menor, aproximadamente la mitad en comparación con el estrato 5, con un 17.5% (1437 viviendas).

frecuenciaestrato <- table(basedatos$estrato)
pie(frecuenciaestrato,
    main = "Distribución de viviendas por zona",
    col = c("#ee964b", "#f4d35e","#0d3b66", "#8FBC8F"),
    labels = sprintf("%s\n%d (%.1f%%)", names(frecuenciaestrato), frecuenciaestrato, prop.table(frecuenciaestrato) * 100)) 

Se observa una relación creciente entre el estrato y el precio de las viviendas, donde a medida que el estrato aumenta, también lo hace el precio. Para los estratos 3, 4 y 5, esta relación muestra un incremento aproximadamente lineal, reflejado en un aumento gradual de la media, la mediana y el rango intercuartílico (IQR). Sin embargo, se observa una mayor presencia de valores atípicos altos en estos estratos, lo que contribuye a una asimetría positiva, indicando la existencia de muchas viviendas con valores más bajos. Por el contrario, el estrato 6 presenta un precio considerablemente más alto, con una mediana de $700 MM y un IQR de $470 MM. En este caso, la presencia de valores atípicos es menor, lo que resulta en una distribución más simétrica de los precios de las viviendas.

boxplot(preciom ~ estrato, 
        data = basedatos, 
        main = "Distribucion de precio por estrato",
        col = "#f4d35e",
        las = 1,
        xlab = "Estrato",
        ylab = "Precio del inmueble (MM)")

b) Piso: Se evidencia un comportamiento asimétrico positivo en la distribución de viviendas por piso, con un 86.7% de las mismas concentradas entre los pisos 1 al 5. Entre estos, los pisos 2 (2647 inmuebles) y 4 (1567 inmuebles) son los más ofertados. Por otro lado, se observa una agrupación descendente en los pisos 6-8, 9-10 y 11-12, representando solo el 13.3% de las viviendas restantes.

ggplot(data = data.frame(piso = basedatos$piso), aes(x = piso)) +
  geom_histogram(binwidth = 1, fill = "#ee964b", color = "black") +
  labs(title = "Distribución de pisos en viviendas", x = "Piso", y = "Frecuencia") +
  scale_x_continuous(breaks = seq(1, 12, by = 1)) +
  scale_y_continuous(breaks = seq(0, 3000, by = 500)) + 
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

Por otro lado, al analizar el precio de las viviendas en cada uno de los pisos, no se observa un comportamiento uniforme. Se destacan los pisos 2, 11 y 12 como los de precios más altos, mientras que el piso 4 parece ser el más devaluado. Entre los pisos 1 al 5, se registra un valor mínimo medio de $63 MM, con una alta presencia de valores atípicos en los precios más altos. En contraste, del piso 6 al 12, el valor mínimo promedio es de $135 MM, con una proporción mucho más baja de valores atípicos.

boxplot(preciom ~ piso, 
        data = basedatos, 
        main = "Distribucion de precio por pisos",
        col = "#f4d35e",
        las = 1,
        xlab = "Pisos",
        ylab = "Precio del inmueble (MM)")

c) Habitaciones: La variable número de habitaciones exhibe una leve simetría positiva, donde el 70% de las viviendas tienen entre 3 y 4 habitaciones, representando un total de 5775 inmuebles. Un 13% de las viviendas no posee habitaciones o cuenta con un máximo de 2, mientras que el 17% restante dispone de 5 o más habitaciones, con un máximo de 10 habitaciones.

ggplot(data = data.frame(habitac = basedatos$habitac), aes(x = habitac)) +
  geom_histogram(binwidth = 1, fill = "#ee964b", color = "black") +
  labs(title = "Distribución No. de habitaciones en viviendas", x = "Habitaciones", y = "Frecuencia") +
  scale_x_continuous(breaks = seq(0, 10, by = 1)) +
  scale_y_continuous(breaks = seq(0, 4500, by = 500)) + 
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

En el gráfico siguiente, se aprecia un incremento progresivo en el precio de las viviendas conforme aumenta el número de habitaciones, con la excepción del caso donde no hay habitaciones, que muestra un precio notablemente alto en comparación con los demás. Este caso presenta una mediana de $410 MM y un IQR de $258 MM. Para las viviendas con 2 a 4 habitaciones, se observa una cantidad significativa de valores atípicos, lo que puede deberse a otras características del mercado. En cuanto a las viviendas con 4, 6, 7 y 9 habitaciones, así como los pisos 5 y 10, muestran precios similares, con una mediana de $443 MM y $551 MM, respectivamente.

boxplot(preciom ~ habitac, 
        data = basedatos, 
        main = "Distribucion de precio por No. de habitaciones",
        col = "#f4d35e",
        las = 1,
        xlab = "Habitaciones",
        ylab = "Precio del inmueble (MM)")

d) Baños: Se destaca un patrón de asimetría positiva en la distribución de baños, con la mayor concentración de viviendas en el rango de 2 a 5 baños. Este intervalo abarca aproximadamente el 88% del total de viviendas, equivalente a 7210 inmuebles. Por otro lado, los números de baños 0, 8, 9 y 10 muestran una presencia minoritaria, cada uno representando menos de 50 viviendas, lo que sugiere una ocurrencia infrecuente de estas características.

ggplot(data = data.frame(banios = basedatos$banios), aes(x = banios)) +
  geom_histogram(binwidth = 1, fill = "#ee964b", color = "black") +
  labs(title = "Distribución No. de baños en viviendas", x = "Baños", y = "Frecuencia") +
  scale_x_continuous(breaks = seq(0, 10, by = 1)) +
  scale_y_continuous(breaks = seq(0, 3000, by = 500)) + 
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

El análisis del número de baños en relación con el precio revela patrones interesantes. Para viviendas sin baños, se observa una sobrevaloración en comparación con el resto, con una mediana de $397 MM y un IQR de $439 MM, aunque solo hay un valor atípico en este grupo. En el caso de viviendas con entre 1 y 7 baños, se observa un aumento aproximadamente lineal en el precio, acompañado de una mayor dispersión; sin embargo, los precios atípicos son notablemente más comunes en este rango. Por último, para viviendas con 8 a 10 baños, no se aprecia una relación clara, observando oscilación de las medianas entre $710 MM y $850 MM.

boxplot(preciom ~ banios, 
        data = basedatos, 
        main = "Distribucion de precio por No. de baños",
        col = "#f4d35e",
        las = 1,
        xlab = "Baños",
        ylab = "Precio del inmueble (MM)")

e) Parqueaderos: La distribución de la variable de parqueaderos muestra una notable asimetría positiva. El 87% de las viviendas (7153 inmuebles) poseen entre 1 y 2 parqueaderos, el 11% (898 inmuebles) entre 3 a 4 parqueaderos y tan solo el 2% (181 inmuebles)restante entre 5 a 10 parqueaderos.

ggplot(data = data.frame(parquea = basedatos$parquea), aes(x = parquea)) +
  geom_histogram(binwidth = 1, fill = "#ee964b", color = "black") +
  labs(title = "Distribución No. de parqueaderos en viviendas", x = "Parqueaderos", y = "Frecuencia") +
  scale_x_continuous(breaks = seq(1, 10, by = 1)) +
  scale_y_continuous(breaks = seq(0, 4500, by = 500)) + 
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

En cuanto al precio de las viviendas en relación con el número de parqueaderos, se observa un aumento gradual en el precio para aquellas que tienen entre 1 y 6 parqueaderos. Sin embargo, se nota una cantidad significativa de precios atípicos, especialmente para 1 y 2 parqueaderos. Por otro lado, para viviendas con 9 y 10 parqueaderos, se evidencia una mediana similar cercana a los $1143 MM, con un IQR de $913 MM y $850 MM, respectivamente.

boxplot(preciom ~ parquea, 
        data = basedatos, 
        main = "Distribucion de precio por No. de parqueaderos",
        col = "#f4d35e",
        las = 1,
        xlab = "Parqueaderos",
        ylab = "Precio del inmueble (MM)")

f) Barrio: El siguiente gráfico representa los 15 barrios más ofertados en la ciudad de Cali de un total de 304 estandarizados en los anexos. Esta segmentación permite identificar que el 52% de la oferta de vivienda está concentrada en estos barrios. Destacan Valle de Lili como el más ofertado con 1009 viviendas, seguido de Ciudad Jardín con 516 y Pance con 397. Además, se distingue un conjunto de datos denominado ‘Otros’, que agrupa el resto de los barrios.

barrios <- table(basedatos$barrio)
topbarrios <- head(sort(barrios, decreasing = TRUE), 15)
FRtop <- sum(topbarrios) / length(basedatos$barrio) * 100
tabla_frecuencias <- data.frame(
  Barrio = names(topbarrios),
  FA = as.numeric(topbarrios),
  stringsAsFactors = FALSE
)
tabla_frecuencias <- bind_rows(tabla_frecuencias, 
                               data.frame(Barrio = "Otros",
                                          FA = sum(barrios) - sum(topbarrios),
                                          stringsAsFactors = FALSE))
tabla_frecuencias <- tabla_frecuencias %>% arrange(desc(FA))
tabla_frecuencias$Barrio <- factor(tabla_frecuencias$Barrio, levels = tabla_frecuencias$Barrio)
ggplot(tabla_frecuencias, aes(x = Barrio, y = FA)) +
  geom_bar(stat = "identity", fill = "#ee964b", color = "black") +
  labs(title = "Frecuencia Absoluta de Barrios", x = "Barrio", y = "Frecuencia Absoluta") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  theme(plot.title = element_text(hjust = 0.5))

5. Discusión

La oferta de viviendas en Cali presenta un patrón de distribución notable, destacando una concentración significativa en la zona del sur de la ciudad con participación de barrios como Valle de lili, ciudad jardín, pance y el caney. Esta tendencia se atribuye principalmente a la proximidad de estos barrios a importantes instituciones educativas, centros de salud, restaurantes y complejos comerciales, entre otros aspectos clave. Asi mismo, la zona norte se posiciona como la segunda área con mayor oferta con barrios como la flora, acopi y prados del norte, debido a la presencia de barrios tradicionales y una notable cantidad de complejos industriales, que incentivan a las personas a residir cerca de sus lugares de trabajo. En contraste, las zonas centro y oriente muestran una menor oferta, ya que son áreas con predominio de viviendas unifamiliares, lo que limita la disponibilidad de espacio para proyectos inmobiliarios.

En cuanto a los tipos de viviendas más ofertados, se destaca que más de la mitad de los inmuebles son apartamentos, con una proporción menor de casas. Este fenómeno se debe a las tendencias actuales de la industria inmobiliaria, que buscan maximizar el aprovechamiento del espacio urbano, junto con una creciente preferencia del público por vivir en edificaciones que ofrecen ventajas adicionales en términos de seguridad, bienestar y calidad de vida. En relación con las zonas, se observa que la zona oeste concentra principalmente la oferta de apartamentos, mientras que en las zonas norte y sur también se encuentran, aunque en menor medida. Por otro lado, las zonas centro y oriente presentan una mayor variedad de casas, siendo estos barrios más populares y con una menor participación del sector inmobiliario en el mercado de apartamentos.

Desde una perspectiva económica, el mercado de viviendas en Cali presenta una diversidad de precios que abarcan un amplio espectro. En términos generales, los precios de las viviendas en todas las zonas de la ciudad comienzan entre $58 y $100 MM. Sin embargo, en las zonas oeste, sur y norte, se observa un rango de precios más elevado con una mayor dispersión, lo que se atribuye a las distintas comodidades y características particulares de cada inmueble. Particularmente, la zona norte se destaca por ofrecer la mejor relación entre precio y área construida frente a las otras zonas, lo que permite encontrar viviendas con áreas más amplias a precios relativamente accesibles para el público. Por otro lado, la zona centro y oriente, al tener una menor oferta de viviendas, se caracteriza por tener los precios más bajos y una mayor homogeneidad, debido a condiciones similares de los inmuebles.

En cuanto a la estratificación, se observa que las viviendas más ofertadas se concentran principalmente en los estratos 5, 4 y 6, mientras que hay una menor presencia en el estrato 3. Este patrón estratificado posiciona a Cali como una ciudad con estándares de vivienda relativamente altos en comparación con otras ciudades importantes como Bogotá, donde prevalece una estratificación principalmente entre los estratos 2 al 4. Por otro lado, en términos de precios de vivienda, es evidente que estos aumentan conforme se incrementa el estrato socioeconómico. Esta relación entre estrato y precio refleja las diferencias en el poder adquisitivo y las condiciones socioeconómicas de los habitantes en cada estrato, así como las características y comodidades asociadas a las viviendas en cada segmento.

La mayoría de las viviendas ofertadas en la ciudad se encuentran en los pisos del 1 al 5, representando más del 87% del total. Por el contrario, los pisos superiores al 5 muestran una proporción mucho menor de oferta. Al analizar los precios de las viviendas en relación con el número de piso, no se observa una relación clara entre ambos factores. Esto podría atribuirse a posibles errores en el proceso de recopilación de datos. Al validar la base de datos, se detectaron valores atípicos, como personas reportando vivir en el décimo piso de una vivienda tipo casa. Por lo tanto, es crucial mejorar los métodos de recolección de información para garantizar la precisión de los datos.

Finalmente, en cuanto a la distribución de las viviendas, se destaca que la mayoría de ellas cuentan con una cantidad de habitaciones y baños que oscila entre 2 y 5, así como entre 1 y 2 parqueaderos. Se observa que a medida que aumenta el número de habitaciones, baños y parqueaderos, también tiende a incrementarse el precio de las viviendas. Este fenómeno se explica por el hecho de que una mayor cantidad de espacios implica, en general, una mayor área construida, lo que resulta en un costo más elevado para la propiedad.

6. Conclusiones

En conclusión, el análisis realizado sobre la base de datos de la empresa B&C proporciona una visión clara de las principales características del mercado de viviendas en Cali. Se destaca la notable oferta en las zonas sur, norte y oeste de la ciudad, siendo la zona norte particularmente atractiva debido a sus precios por metro cuadrado más bajos en comparación con otras áreas.

Para B&C, se sugiere concentrar sus esfuerzos comerciales en estas zonas, con especial énfasis en la zona norte, priorizando la adquisición de apartamentos con potencial para remodelación y una óptima relación costo-beneficio. Se recomienda que estas propiedades cuenten con al menos 3 habitaciones, 2 baños y 2 parqueaderos, dado que son las características más demandadas por los compradores en la oferta actual de viviendas.

Además, se hace hincapié en la importancia de mejorar el proceso de recopilación de datos, proporcionando claridad en las distintas características de las propiedades y realizando un filtro de verificación inicial para garantizar la calidad de los datos iniciales. Esto permitirá una toma de decisiones estratégicas más informada y precisa por parte de la empresa.

7. Anexos

7.1. Importación de datos

La importación de los datos se obtuvo mediante el siguiente repositorio:

install.packages("devtools") # solo una vez
devtools::install_github("dgonxalex80/paqueteMETODOS") # solo una vez
library(paqueteMETODOS)
data(vivienda_faltantes)

7.2. Comprensión de los datos

La base de datos vivienda_faltantes presenta la siguiente estructura:

vivienda <- vivienda_faltantes
str(vivienda)
## 'data.frame':    8330 obs. of  14 variables:
##  $ X        : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ id       : int  8312 8311 8307 8296 8297 8298 8299 8300 8286 8287 ...
##  $ zona     : chr  "Zona Oeste" "Zona Oeste" "Zona Oeste" "Zona Sur" ...
##  $ piso     : int  4 1 NA 2 NA NA 2 NA NA 2 ...
##  $ estrato  : int  6 6 5 3 5 5 6 5 5 5 ...
##  $ preciom  : int  1300 480 1200 220 330 1350 305 480 275 285 ...
##  $ areaconst: num  318 300 800 150 112 390 125 280 74 120 ...
##  $ parquea  : int  2 1 4 1 2 8 2 4 1 2 ...
##  $ banios   : int  4 4 7 2 4 10 3 4 2 4 ...
##  $ habitac  : int  2 4 5 4 3 10 3 4 3 3 ...
##  $ tipo     : chr  "Apartamento" "Casa" "Casa" "Casa" ...
##  $ barrio   : chr  "arboleda" "normandía" "miraflores" "el guabal" ...
##  $ longitud : num  -76576 -76571 -76568 -76565 -76565 ...
##  $ latitud  : num  3454 3454 3455 3417 3408 ...

En esta se evidencia una configuración de 8330 registros o filas y 14 variables o columnas. La caracterización de la base de datos se describe de la siguiente manera:

  • Id: Variable de identificación.
  • Zona: Variable cualitativa nominal.
  • Piso: Variable cualitativa ordinal.
  • Estrato: Variable cualitativa ordinal.
  • Precio (millones): Variable cuantitativa continua.
  • Área construida: Variable cuantitativa continua.
  • Parqueaderos: Variable cuantitativa discreta.
  • Baños: Variable cuantitativa discreta.
  • Habitación: Variable cuantitativa discreta.
  • Tipo: Variable cualitativa nominal.
  • Barrio: Variable cualitativa nominal.
  • Longitud: Variable cuantitativa continua.
  • Latitud: Variable cuantitativa continua.

Con lo anterior, se realizó la revisión de la calidad de la base teniendo en cuenta los los valores nulos y los valores no estandarizados (datos de la misma naturaleza con alteración en su escritura).

  • Valores nulos o faltantes: En la siguiente tabla se representa la cantidad de valores faltantes por cada una de las variables, encontrando que existen 3 filas de registros que no cuentan con ningún tipo de información y aun más relevante, para las variables piso y parqueaderos existe una carencia de 2641 y 1606 registros, respectivamente.
kable(data.frame(CantidadNA=colSums(is.na(vivienda))))
CantidadNA
X 0
id 3
zona 3
piso 2641
estrato 3
preciom 2
areaconst 3
parquea 1606
banios 3
habitac 3
tipo 3
barrio 3
longitud 3
latitud 3
  • Valores no estandarizados: Teniendo en cuenta la estructura de la base de datos se observo que las variables tipo, barrio, latitud y longitud poseían alteraciones en su escritura.

    Variable Hallazgo
    Tipo Solo existen dos clasificaciones Apartamento y Casa, sin embargo, hay variación en su escritura y combinación de mayúsculas y minúsculas
    Barrio Existen 436 barrios incluidos en la base de datos, pero muchos de ellos comparten una misma distinción, estos se ven modificados por el uso de mayúsculas, minúsculas y caracteres especiales
    Longitud y Latitud Los datos expresados presentan variaciones en su escala, teniendo valores enteros en miles y valores decimales

7.3. Limpieza y fusión de datos:

Se llevó a cabo un proceso de limpieza para eliminar aquellas filas que no contenían ningún tipo de información, asegurando así que los datos restantes fueran completos y coherentes.

# Eliminacion de filas con Id vacio
vivienda <- vivienda[!is.na(vivienda$id),]

Por medio de la siguiente gráfica es visible la eliminación de las 3 filas que no tenían ningún tipo de dato

gg_miss_var(vivienda)

Por otro lado, se incorporo una nueva variable al conjunto de datos que relaciona el precio de las viviendas con su área construida, con el fin de hacer comparable los inmuebles en términos de precio por m2. Esta inclusión facilitó la identificación de precios atípicos en las viviendas, lo cual condujo a una depuración de la base de datos, reduciéndola a 8232 registros válidos al eliminar aquellos con precios por metro cuadrado que excedían los valores esperados según la distribución de datos.

vivienda <- vivienda %>% mutate(Preciometro=round(preciom/areaconst,digits = 1))
vivienda <- vivienda %>%
  group_by(zona) %>%
  filter(Preciometro >= quantile(Preciometro, 0.25) - 1.5 * IQR(Preciometro) &
           Preciometro <= quantile(Preciometro, 0.75) + 1.5 * IQR(Preciometro)) %>%
  ungroup()

7.4. Estandarización de los datos

Se llevó a cabo el proceso de estandarización para variables como tipo, barrio, latitud y longitud.

  • Tipo: Se encontraron variaciones como Apartamento, APARTAMENTO, apto, casa, Casa, CASA. Por tanto, se estandarizaron en dos únicas categorías Apartamento y Casa utilizando el siguiente código:
vivienda <- vivienda %>% mutate(tipo=tolower(vivienda$tipo))
vivienda <- vivienda %>%
  mutate(tipo = case_when(
    tipo %in% c("apartamento", "apto") ~ "Apartamento",
    tipo %in% c("casa") ~ "Casa",
    TRUE ~ tipo  # Mantener valores que no necesitan agrupación
  ))
data.frame(Tipo=unique(sort(vivienda$tipo)))
  • Barrio: Se realizó una investigación mediante geolocalización para garantizar una agrupación adecuada de los barrios en torno a sus localizaciones, reduciendo el numero de barrio de 436 a 304.
# Dejar todo en miniscula y sin tildes
limpiar_barrios <- function(names){nombres<-tolower(
                                  trimws(iconv(names,from="UTF-8",to="ASCII//TRANSLIT")))
                                  nombres<-gsub("[_]","",nombres)
                    return(nombres)
}
vivienda$barrio<-limpiar_barrios(vivienda$barrio)
# Estandarizar nombres
vivienda <- vivienda %>%
  mutate(barrio = case_when(
    barrio %in% c("aguablanca") ~ "agua blanca",
    barrio %in% c("alamos","los alamos") ~ "ciudad los alamos",
    barrio %in% c("bajo aguacatal","miradol del aguacatal","sector aguacatal") ~ "aguacatal",
    barrio %in% c("alameda") ~ "alameda del rio",
    barrio %in% c("alf?crez real") ~ "alferez real",
    barrio %in% c("alfonso lopez i") ~ "alfonso lopez",
    barrio %in% c("arboleda") ~ "arboledas",
    barrio %in% c("altos de menga","colinas de menga") ~ "menga",
    barrio %in% c("la alborada") ~ "alborada",
    barrio %in% c("barrio 7de agosto","siete de agosto") ~ "7 de agosto",
    barrio %in% c("barrio el recuerdo") ~ "recuerdo",
    barrio %in% c("barrio eucaristico") ~ "eucaristico",
    barrio %in% c("barrio obrero") ~ "obrero",
    barrio %in% c("base a?crea") ~ "base aerea",
    barrio %in% c("ed benjamin herrera") ~ "benjamin herrera",
    barrio %in% c("bella suiza alta") ~ "bella suiza",
    barrio %in% c("bloques del limonar") ~ "bosques del limonar",
    barrio %in% c("el gran limonar") ~ "gran limonar",
    barrio %in% c("brisas de los") ~ "brisas de los alamos",
    barrio %in% c("ciudad bochalema") ~ "bochalema",
    barrio %in% c("cali","cali bella") ~ "calibella",
    barrio %in% c("cali canto","calicanto viii") ~ "calicanto",
    barrio %in% c("caney especial","el caney"," el caney") ~ "caney",
    barrio %in% c("cañaverales los samanes") ~ "cañaverales",
    barrio %in% c("Chiminangosr","chiminangos 1 etapa","chiminangos 2 etapa") ~ "chiminangos",
    barrio %in% c("capri") ~ "ciudad capri",
    barrio %in% c("ciudad cordoba reservado") ~ "ciudad cordoba",
    barrio %in% c("ciudad jardin pance","ciudad antejardin") ~ "ciudad jardin",
    barrio %in% c("ciudadela paso ancho") ~ "ciudadela pasoancho",
    barrio %in% c("ciudad mel?cndez","ciudadela melendez","meléndez","melendez") ~ "ciudad melendez",
    barrio %in% c("colseguros") ~ "colseguros andes",
    barrio %in% c("colon") ~ "cristobal colon",
    barrio %in% c("cristales","los cristales","tejares cristales") ~ "los cristales tejares",
    barrio %in% c("centro") ~ "zona centro",
    barrio %in% c("el ingenio i","ingenio i") ~ "ingenio I",
    barrio %in% c("ingenio ii","el ingenio ii") ~ "ingenio II",
    barrio %in% c("el ingenio 3","el ingenio iii","ingenio iii") ~ "ingenio III",
    barrio %in% c("el tr?cbol") ~ "el trebol",
    barrio %in% c("fuentes de la") ~ "fuentes",
    barrio %in% c("brisas del guabito") ~ "el guabito",
    barrio %in% c("el ingenio","el ingenio") ~ "ingenio",
    barrio %in% c("altos de guadalupe","brisas de guadalupe","cerros de guadalupe","guadalupe alto","sector cañaveralejo guadalupe") ~ "guadalupe",
    barrio %in% c("juanamb??") ~ "juanambu",
    barrio %in% c("jamundi alfaguara") ~ "jamundi",
    barrio %in% c("la ceibas","las ceibas") ~ "ceibas",
    barrio %in% c("la primavera") ~ "primavera",
    barrio %in% c("laflora","norte la flora","flora") ~ "la flora",
    barrio %in% c("la riviera") ~ "la rivera",
    barrio %in% c("la rivera i") ~ "la rivera I",
    barrio %in% c("la rivera ii") ~ "la rivera II",
    barrio %in% c("lares de comfenalco") ~ "comfenalco",
    barrio %in% c(" las am?cricas") ~ "las americas",
    barrio %in% c("las vegas de","mayapan las vegas") ~ "las vegas",
    barrio %in% c("los alcazares","los alcázares") ~ "alcazares",
    barrio %in% c("cambulos") ~ "los cambulos",
    barrio %in% c("guaduales") ~ "los guaduales",
    barrio %in% c("libertadores") ~ "los libertadores",
    barrio %in% c("marroquin iii") ~ "marroquin III",
    barrio %in% c("normandía west point") ~ "normandia",
    barrio %in% c("nueva base") ~ "la base",
    barrio %in% c("rep??blica de israel") ~ "republica de israel",
    barrio %in% c("san judas tadeo") ~ "san judas",
    barrio %in% c("santa elene","santa helena de") ~ "santa helena",
    barrio %in% c("tequendema","urbanización tequendama") ~ "tequendama",
    barrio %in% c("refugio") ~ "el refugio",
    barrio %in% c("las quintas de") ~ "quintas de salomia",
    barrio %in% c("quintas de don") ~ "quintas de don simon",
    barrio %in% c("valle de lili") ~ "valle del lili",
    barrio %in% c("san bosco") ~ "san juan bosco",
    barrio %in% c("san fernando nuevo") ~ "san fernando",
    barrio %in% c("santa anita sur") ~ "santa anita",
    barrio %in% c("santafe") ~ "santa fe",
    barrio %in% c("sierras de normandia") ~ "normandia",
    barrio %in% c("villa de veracruz") ~ "villas de veracruz",
    barrio %in% c("zona norte los","norte") ~ "zona norte",
    TRUE ~ barrio  # Mantener valores que no necesitan agrupación
  ))
  • Longitud y latitud: Se encontró que los datos expresados para estas variables presentan variaciones en su escala, teniendo valores enteros en miles y valores decimales, por tanto, aquellos valores en miles fueron divididos por 1000 para dejar los datos en la escala adecuada para la elaboración de un mapa geográfico.
## Variable latitud
vivienda <- mutate(vivienda,latitud = ifelse(vivienda$latitud>1000,
                                             vivienda$latitud/1000,
                                             vivienda$latitud))

## Variable longitud
vivienda <- mutate(vivienda,longitud = ifelse(vivienda$longitud< -100,
                                              vivienda$longitud/1000,
                                              vivienda$longitud))

7.5 Imputación de datos

Para entender el comportamiento de las dos variables, se realiza un resumen estadístico de los datos. Encontrando que la variable tipo parqueadero tiene un valor mínimo de 1, máximo de 10, una mediana de 2 y una media de 2 aproximadamente . Así mismo, la variable piso tiene un valor mínimo de 1, máximo de 12, una mediana de 3 y una media de 4. aproximadamente.

print("Resumen estadistico variable parqueaderos")
## [1] "Resumen estadistico variable parqueaderos"
summary(vivienda$parquea)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   1.000   1.000   2.000   1.828   2.000  10.000    1580
print("Resumen estadistico variable piso")
## [1] "Resumen estadistico variable piso"
summary(vivienda$piso)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   1.000   2.000   3.000   3.765   5.000  12.000    2593

Para complementar el análisis se realizan los respectivos histogramas para identificar la simetría de los mismos:

# Visualización de simetría de datos
par(mfrow = c(1, 2))
par(mar = c(5, 4, 1, 4) + 0)
hist(vivienda$parquea,
     breaks = 10,
     las=1,
     main = "No. Parqueaderos por vivienda",
     xlab="Numero de parqueaderos",
     ylab = "frecuencia",
     col ="#ee964b",
     ylim = c(0,6000))
hist(vivienda$piso, 
     breaks = 12,
     las=1,
     main = "No. de piso por vivienda",
     xlab="Piso",
     ylab = "frecuencia",
     col ="#ee964b",
     ylim = c(0,2500))

Al analizar la distribución de las variables parqueaderos y piso, se observa una asimetría hacia la derecha en ambos casos. En el caso de la variable parqueaderos, esta asimetría se atribuye a la alta concentración de viviendas con hasta dos parqueaderos, lo que resulta en una media que se aproxima a la mediana. Por otro lado, en la variable piso, la dispersión es más amplia lo cual provoca que la media sea mayor que la mediana, especialmente influenciada por aquellas viviendas ubicadas en pisos altos.

Con lo anterior, se podría realizar una aproximación de los datos faltantes para las variables de parqueaderos y pisos utilizando la mediana debido a las asimetrias presentadas. Sin embargo, la imputación de datos no puede generalizarse debido a las complejas relaciones con otras variables como zona, estrato y tipo de apartamento. Por lo tanto, para llevar a cabo una imputación precisa, se ha creado una tabla de agrupación que relaciona estos datos.

#Analisis por agrupamiento
Analisis <- vivienda %>% group_by(zona,estrato,tipo) %>%  
  summarise(Parqueaderos = round(median(parquea,na.rm=TRUE),digit=0),
            Piso=round(median(piso,na.rm=TRUE),digit=0))
datatable(Analisis, list(pageLength=10))

A partir de la anterior, se realizó la respectiva imputación de datos usando la mediana, y se verifico su eficacia mediante la siguiente grafica.

# Imputación de variable parqueaderos
vivienda <- vivienda %>% 
  mutate(parquea = case_when(
    is.na(parquea) & zona == "Zona Centro" & estrato == "3" ~ 1,
    is.na(parquea) & zona == "Zona Centro" & estrato == "4" ~ 1,
    is.na(parquea) & zona == "Zona Centro" & estrato == "5" & tipo == "Apartamento" ~ 1,
    
    is.na(parquea) & zona == "Zona Norte" & estrato == "3" ~ 1,
    is.na(parquea) & zona == "Zona Norte" & estrato == "4" & tipo == "Apartamento" ~ 1,
    is.na(parquea) & zona == "Zona Norte" & estrato == "4" & tipo == "Casa" ~ 2,
    is.na(parquea) & zona == "Zona Norte" & estrato == "5" & tipo == "Apartamento" ~ 1,
    is.na(parquea) & zona == "Zona Norte" & estrato == "5" & tipo == "Casa" ~ 2,
    is.na(parquea) & zona == "Zona Norte" & estrato == "6" ~ 2,
    
    is.na(parquea) & zona == "Zona Oeste" & estrato == "3" ~ 1,
    is.na(parquea) & zona == "Zona Oeste" & estrato == "4" ~ 1,
    is.na(parquea) & zona == "Zona Oeste" & estrato == "5" ~ 2,
    is.na(parquea) & zona == "Zona Oeste" & estrato == "6" ~ 2,
    
    is.na(parquea) & zona == "Zona Oriente" & estrato == "3" ~ 1,
    is.na(parquea) & zona == "Zona Oriente" & estrato == "4" ~ 1,
    is.na(parquea) & zona == "Zona Oriente" & estrato == "5" & tipo == "Apartamento" ~ 1,
    is.na(parquea) & zona == "Zona Oriente" & estrato == "6" & tipo == "Apartamento" ~ 3,
    
    is.na(parquea) & zona == "Zona Sur" & estrato == "3" ~ 1,
    is.na(parquea) & zona == "Zona Sur" & estrato == "4" ~ 1,
    is.na(parquea) & zona == "Zona Sur" & estrato == "5" & tipo == "Apartamento" ~ 1,
    is.na(parquea) & zona == "Zona Sur" & estrato == "5" & tipo == "Casa" ~ 2,
    is.na(parquea) & zona == "Zona Sur" & estrato == "6" & tipo == "Apartamento" ~ 2,
    is.na(parquea) & zona == "Zona Sur" & estrato == "6" & tipo == "Casa" ~ 3,
    TRUE ~ parquea
  ))

vivienda <- vivienda %>% 
  mutate(piso = case_when(
    is.na(piso) & zona == "Zona Centro" & estrato == "3" & tipo == "Apartamento" ~ 4,
    is.na(piso) & zona == "Zona Centro" & estrato == "3" & tipo == "Casa" ~ 1,
    is.na(piso) & zona == "Zona Centro" & estrato == "4" & tipo == "Apartamento" ~ 8,
    is.na(piso) & zona == "Zona Centro" & estrato == "4" & tipo == "Casa" ~ 2,
  
    is.na(piso) & zona == "Zona Norte" & tipo == "Casa" ~ 2,
    is.na(piso) & zona == "Zona Norte" & estrato == "3" & tipo == "Apartamento" ~ 4,
    is.na(piso) & zona == "Zona Norte" & estrato == "4" & tipo == "Apartamento" ~ 4,
    is.na(piso) & zona == "Zona Norte" & estrato == "5" & tipo == "Apartamento" ~ 5,
    is.na(piso) & zona == "Zona Norte" & estrato == "6" & tipo == "Apartamento" ~ 4,

    is.na(piso) & zona == "Zona Oeste" & tipo == "Casa" ~ 2, 
    is.na(piso) & zona == "Zona Oeste" & estrato == "3" & tipo == "Apartamento" ~ 4,
    is.na(piso) & zona == "Zona Oeste" & estrato == "4" & tipo == "Apartamento" ~ 3,
    is.na(piso) & zona == "Zona Oeste" & estrato == "5" & tipo == "Apartamento" ~ 4,
    is.na(piso) & zona == "Zona Oeste" & estrato == "6" & tipo == "Apartamento" ~ 5,

    is.na(piso) & zona == "Zona Oriente" & estrato == "3" ~ 2,
    is.na(piso) & zona == "Zona Oriente" & estrato == "4" & tipo == "Apartamento" ~ 4,    
    is.na(piso) & zona == "Zona Oriente" & estrato == "4" & tipo == "Casa" ~ 2, 
    is.na(piso) & zona == "Zona Oriente" & estrato == "5" & tipo == "Apartamento" ~ 5,    
    is.na(piso) & zona == "Zona Oriente" & estrato == "5" & tipo == "Casa" ~ 1,
    
    is.na(piso) & zona == "Zona Sur" & tipo == "Apartamento" ~ 4,
    is.na(piso) & zona == "Zona Sur" & tipo == "Casa" ~ 2, 
    TRUE ~ piso
  ))
grafico <- md.pattern(vivienda, rotate.names = TRUE)

basedatos <- vivienda

Validando los datos se evidencia que para la variable piso quedaron 6 datos nulos y para parqueaderos 3 datos nulos, compartiendo 2 registros sin ninguna asignación para estas variables. Estos valores nulos corresponden a casos donde no había más información disponible en la misma categoría. Por lo tanto, se decidido mantenerlos en el análisis para evitar incurrir en errores de imputación.