Introducción

El mercado inmobiliario en Cali (Colombia), ha experimentado un notable crecimiento en los últimos años, impulsado por diversos factores como el aumento de la población, la inversión extranjera y el desarrollo de nuevos proyectos sociales y urbanísticos. Con el propósito de comprender las tendencias y dinámicas de la vivienda en la ciudad, se llevará a cabo un análisis estadístico descriptivo utilizando la información recopilada por la empresa B&C (Bienes y Casas) sobre las propiedades en el territorio. Este análisis proporcionará a la empresa una base sólida para la toma de decisiones estratégicas, incluyendo la definición del nicho de mercado, estrategias de marketing, fijación de precios de venta y la prestación de un servicio personalizado al cliente.

Objetivo

El objetivo de este documento es elaborar un informe estadístico que identifique los principales patrones de comportamiento del sector inmobiliario en la ciudad de Cali, centrándose en la detección de datos atípicos y la exploración de las relaciones entre variables numéricas y categóricas. Con este fin, se establecerán tres (3) objetivos específicos que respaldarán este análisis:

• Analizar los precios de las viviendas en diferentes zonas de Cali.

• Identificar los tipos de viviendas más ofertadas en el mercado.

• Destacar las características más relevantes de la oferta de vivienda en Cali.

Métodos

Se utilizará un enfoque de análisis descriptivo (análisis exploratorio de datos) para cumplir con los objetivos establecidos. Esto implicará el uso de técnicas y herramientas estadísticas para organizar, resumir y presentar los datos recopilados por la empresa B&C.

El proceso metodológico constará de las siguientes etapas:

  1. Carga de datos fuente y visualización previa.

  2. Preparación de los datos: orden, transformación y limpieza.

  3. Análisis estadístico: definición de variables de interés y aplicación de descriptivos.

  4. Visualización e interpretación de resultados.

  5. Anexos, conclusiones, recomendaciones y discusión.

1. Carga de datos y visualización previa.

En este apartado, se realizará la carga de la base de datos original, se realizará una primera visualización de los datos obtenidos y se presentarán los paquetes a utilizar para el desarrollo del mismo.

1.1 Paquetes de librerías.

Consolidado de paquetes de librerias a utilizar en el proyecto:

library(paqueteMETODOS)
library(devtools)
library(dplyr)
library(ggplot2)
library(naniar)
library(knitr)
library(rmarkdown)
library(bookdown)
library(xaringan)
library(blogdown)
library(formattable)
library(leaflet)
library(kableExtra)

1.2 Importación de datos y distribución de variables.

Al realizar el proceso de importación, se observa que el conjunto inicial de datos cuenta con un total de 8330 registros (filas - observaciones) y 13 variables (columnas) con diferentes tipos de datos como el id, zona, piso, estrato, parqueaderos, área, baños, precio, zona, barrio, entre otros.

De igual forma, se encuentra que existen algunos datos faltantes (NA), principalmente para las variables de “piso” (2641) y “parqueadero” (1606), tal como se observa en la siguiente tabla. Estos datos servirán como enfoque para el proceso de depuración y limpieza.

#Se descarga la base de datos original
#devtools::install_github("dgonxalex80/paqueteMETODOS")
data(vivienda_faltantes)

# Se crea una copia seguridad, con la que se trabajará en el proyecto.
viviwork = vivienda_faltantes

# Se visualiza la existencia de datos faltantes por medio de un data frame
faltantes = colSums(is.na(vivienda_faltantes)) %>%
  as.data.frame()
colnames(faltantes) = "Faltantes"

# Mostrar el dataframe con kable() y formato adicional
kable(faltantes, caption = "Datos faltantes por variable") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Datos faltantes por variable
Faltantes
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

2. Orden, transformación y limpieza de datos.

Tal como se mencionó anteriormente, hay una muestra representativa de datos perdidos (NA) para las variables de piso y parqueadero, equivalente al 32% y 19%, respectivamente. [Anexo 1]

Con el fin de descubrir algún patron referente a los datos nulos y poder establecer una posible imputación de datos basados en la relación del tipo de vivienda, se plantea la siguiente hipótesis con las variables en mención:

  • En el tipo de vivida “casa”, las personas que llenaron la encuesta pueden asumir no marcar piso y parqueadero porque en la ciudad de Cali, la mayoría de este tipo de viviendas no cuentan con más de un piso o, la vivienda no tiene acceso a parqueadero privado.

Para comprobar lo anterior, se realizaran dos tipos análisis:

  1. Analizar las variables “piso” y “tipo” de vivienda, para saber su correlación y,
  2. Analizar las variables “parquea” (parqueadero) y “tipo” de vivienda, para igualmente conocer el tipo de relación.

2.1 Propuesta 1. Análisis de la variable “piso”.

Se propone hacer un análisis bivariado entre la variable “piso” y “tipo” de vivienda (apartamento - casa) para saber si existe alguna relación de los valores faltantes de acuerdo con la vivienda.

La siguiente tabla, muestra que en la variable “piso” hay un total de 2641 NA (realmente se analizan 2638 datos, puesto que hay 3 filas en las que todos sus datos son NA) y su distribución de datos perdidos es equitativa porcentualmente, entre el 48% y 52%. Es decir, no hay predominancia en afectación de la variable “tipo” para la primera propuesta.

# Para analizar "tipo" de vivienda, primero se hace la limpieza
tipo = table(viviwork$tipo) %>% data.frame()
viviwork$tipo = tolower(viviwork$tipo) # Poner en minúsculas

# Unificar los "aptos" a "apartamento"
viviwork$tipo = ifelse(viviwork$tipo == "apto", "apartamento", viviwork$tipo) 

# Filtrar las filas con datos faltantes en la columna "piso"
datos_faltantes_piso = viviwork[is.na(viviwork$piso), ] 

# Conocer cuántos datos faltantes (NA) corresponden a cada tipo de vivienda
tabla_tipo_piso_faltante = table(datos_faltantes_piso$tipo)

# Calcular el porcentaje de datos faltantes para cada tipo de vivienda
porcentaje_tipo_piso_faltante = prop.table(tabla_tipo_piso_faltante) * 100 

# Crear una tabla con los resultados
tabla_resultados = data.frame(Tipo = names(porcentaje_tipo_piso_faltante),
                               Faltantes = as.numeric(tabla_tipo_piso_faltante),
                               Porcentaje = as.numeric(porcentaje_tipo_piso_faltante))

# Agregar un totalizado al final de la tabla
total_faltantes = sum(tabla_resultados$Faltantes)
total_porcentaje = sum(tabla_resultados$Porcentaje)

# Agregar los totales a la tabla de resultados
tabla_resultados = rbind(tabla_resultados, c("Total", total_faltantes, total_porcentaje))

# Mostrar la tabla de resultados con kable()
kable(tabla_resultados, caption = "Tabla de datos faltantes en la columna 'piso' por tipo de vivienda") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Tabla de datos faltantes en la columna ‘piso’ por tipo de vivienda
Tipo Faltantes Porcentaje
apartamento 1383 52.426080363912
casa 1255 47.573919636088
Total 2638 100

2.2 Propuesta 2. Análisis de la variable “parquea” (parqueadero).

Se propone hacer un analisis bivariado entre la variable “parquea” (correspondiente a parqueadero) y el “tipo” de vivienda (apartamento - casa) para saber si existe alguna relación de los valores faltantes de acuerdo con la vivienda.

La siguiente tabla muestra que, en la variable parqueadero hay un total de 1606 NA (igualmente se analizan 3 filas menos), y su distribución de datos perdidos tambien resulta equitativa porcentualmente, entre el 45% y 54%. Lo que indica que no hay predominancia en afectación de la variable “tipo” de vivienda para el segundo análisis.

# Filtrar las filas con datos faltantes en la columna "parquea"
datos_faltantes_parquea = viviwork[is.na(viviwork$parquea), ]

# Conocer cuántos datos faltantes (NA) corresponden a cada tipo de vivienda
tabla_tipo_parquea_faltante = table(datos_faltantes_parquea$tipo)

# Calcular el porcentaje de datos faltantes para cada tipo de vivienda
porcentaje_tipo_parquea_faltante = prop.table(tabla_tipo_parquea_faltante) * 100

# Crear una tabla con los resultados
tabla_resultados_parquea = data.frame(Tipo = names(porcentaje_tipo_parquea_faltante),
                                       Faltantes = as.numeric(tabla_tipo_parquea_faltante),
                                       Porcentaje = as.numeric(porcentaje_tipo_parquea_faltante))

# Agregar un totalizado al final de la tabla
total_faltantes = sum(tabla_resultados_parquea$Faltantes)
total_porcentaje = sum(tabla_resultados_parquea$Porcentaje)

# Agregar los totales a la tabla de resultados
tabla_resultados_parquea = rbind(tabla_resultados_parquea, c("Total", total_faltantes, total_porcentaje))

# Mostrar la tabla de resultados con kable() y formato adicional
kable(tabla_resultados_parquea, caption = "Tabla de datos faltantes en la columna 'parquea' por tipo de vivienda") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Tabla de datos faltantes en la columna ‘parquea’ por tipo de vivienda
Tipo Faltantes Porcentaje
apartamento 869 54.2108546475359
casa 734 45.7891453524641
Total 1603 100

Teniendo en cuenta lo anterior, se puede decir que tanto en las variables piso como en parqueadero, no hay una diferencia representativa para concluir que alguno incurrió en omisión del dato faltante por incurrir en obviedad del valor cero (0) o simplemente no llenar el campo en la encuesta; habría que analizar con mayor profundidad cuales fueron los métodos para el levantamientos de la información.

2.3 Rellenando los faltantes

En este punto, se plantea realizar dos propuestas para rellenar los datos faltantes:

  1. La primera, es utilizar la media aritmética general de las variables piso y parqueadero; donde el promedio para pisos es de 3,7 y para parqueadero es de 1,8.
#Realizamos una primera evaluación de los promedios
# Calcular el promedio de la variable "piso"
promedio_piso = mean(viviwork$piso, na.rm = TRUE)
promedio_piso
## [1] 3.772368
# Calcular el promedio de la variable "parquea"
promedio_parquea = mean(viviwork$parquea, na.rm = TRUE)
promedio_parquea
## [1] 1.835961
  1. La segunda propuesta, y que vamos a utilizar para el desarrollo de este proyecto, es profundizar las variables piso y parqueadero teniendo en cuenta su relación con los apartamentos y las casas.

La idea es poder completar los datos perdidos (NA) de la variable piso en apartamento con el valor cinco (5) y para casa con valor de (3). Por su parte, para la variable parqueadero, tanto para apartamento como para casa, se utilizará el promedio general por defecto correspondiente al valor de uno (1). Esto, teniendo en cuenta lo mencionado respecto a que actualmente las casas y apartamentos en la ciudad no poseen parqueadero o son de tipo comunitario, teniendo en cuenta los análisis de medidas de tendencia central.

# Averiguamos el promedio de pisos, por tipo de vivienda, utilizando aggregate()
promedios_pisoxtipo = aggregate(piso ~ tipo, data = viviwork, FUN = function(x) ceiling(mean(x)))

# Mostrar la tabla con estilo utilizando kableExtra
kable(promedios_pisoxtipo, caption = "Promedio de pisos por tipo de vivienda") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Promedio de pisos por tipo de vivienda
tipo piso
apartamento 5
casa 3
# Averiguamos el promedio de parqueaderos, por tipo de vivienda, utilizando aggregate()
promedios_parqueaxtipo = aggregate(parquea ~ tipo, data = viviwork, FUN = function(x) ceiling(mean(x)))

# Mostrar la tabla con estilo utilizando kableExtra
kable(promedios_parqueaxtipo, caption = "Promedio de parqueaderos por tipo de vivienda") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Promedio de parqueaderos por tipo de vivienda
tipo parquea
apartamento 2
casa 3

Se combinan los resultados en una tabla para una mejor visualización. Se eligen los valores para piso más no para el parqueadero por tipo de vivienda porque con el analisis propuesto, aparentemente resultan muy altos.

# Combinar los resultados de los promedios de pisos por tipo de vivienda
promedios = merge(promedios_pisoxtipo, promedios_parqueaxtipo, by = "tipo")
colnames(promedios) = c("Tipo", "Promedio_pisos", "Promedio_parqueaderos")

# Crear una tabla con los resultados
tabla_resultados = data.frame(Tipo = promedios$Tipo,
                               `Promedio de Pisos` = promedios$Promedio_pisos,
                               `Promedio de Parqueaderos` = promedios$Promedio_parqueaderos)

# Mostrar la tabla con kableExtra y formato adicional
kable(tabla_resultados, 
      caption = "Promedio de pisos y parqueaderos por tipo de vivienda",
      align = "c",
      col.names = c("Tipo de vivienda", "Promedio de Pisos", "Promedio de Parqueaderos"),
      digits = 2,
      format = "html",
      table.attr = "class='table table-striped table-hover'",
      row.names = FALSE) %>%
  kable_styling(full_width = FALSE) %>%
  scroll_box(width = "100%", height = "400px")
Promedio de pisos y parqueaderos por tipo de vivienda
Tipo de vivienda Promedio de Pisos Promedio de Parqueaderos
apartamento 5 2
casa 3 3

2.4 Eliminación de registros con datos totalmente vacios

Tal como se mencionó anteriormente, se observa que hay tres (3) filas que representan datos totalmente vacíos, y se procede con su eliminación, quedando en 8327 observaciones totales.

# Rellenar los datos faltantes en la columna "piso"
viviwork$piso = ifelse(is.na(viviwork$piso), 
                        promedios$Promedio_pisos[match(viviwork$tipo, promedios$Tipo)], 
                        viviwork$piso)

# Rellenar los datos faltantes en la columna "parquea"
viviwork$parquea = ifelse(is.na(viviwork$parquea) & (viviwork$tipo == "apartamento" | viviwork$tipo == "casa"), 
                           1, 
                           viviwork$parquea)

#Corroboramos nuevamente faltantes
faltantesNew = colSums(is.na(viviwork)) %>%
  as.data.frame()

Se corroborá por medio de la tabla, que los datos faltantes hayan sido rellenados, para poder avanzar con el siguiente punto del proyecto.

# Eliminar las filas con valores NA en viviwork
viviwork = viviwork[complete.cases(viviwork), ]
faltantesNew = colSums(is.na(viviwork)) %>% as.data.frame() 

# Crear y mostrar la tabla con kableExtra
kable(faltantesNew, 
      caption = "Nueva tabla de datos faltantes",
      col.names = c("Variable", "Faltantes"),
      align = "c",
      digits = 0,
      format = "html",
      table.attr = "class='table table-striped table-hover'",
      row.names = TRUE) %>%
  kable_styling(full_width = FALSE) %>%
  scroll_box(width = "100%", height = "400px")
Nueva tabla de datos faltantes
Variable Faltantes
id 0
zona 0
piso 0
estrato 0
preciom 0
areaconst 0
parquea 0
banios 0
habitac 0
tipo 0
barrio 0
longitud 0
latitud 0

2.5 Limpieza de la variable “barrio”.

Luego, se procede con la limpieza de algunos barrios mal registrados desde la base de datos original. En principio se cuenta con 436 registros de barrios y se llega obtener 369 con nombres de barrios unificados.

#crear la variable, 1ra visualización
barrio = table(viviwork$barrio) %>% data.frame() 
viviwork$barrio = tolower(viviwork$barrio) #pone en minusculas
viviwork$barrio = iconv(viviwork$barrio, to = "ASCII//TRANSLIT") #Eliminar las tildes de los barrios

#Unificar los nombres de los barrios
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "agua blanca", "aguablanca", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "alf?crez real", "alferez real", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "alfonso lopez i", "alfonso lopez", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "arboleda", "arboledas", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "barrio 7de agosto", "7 de agosto", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "barrio el recuerdo", "el recuerdo", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "barrio eucaristico", "eucaristico", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "barrio obrero", "obrero", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "troncal", "el troncal", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "base a?crea", "base aerea", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "brisas de los", "alamos", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "cali canto", "calicanto", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "canaverales los samanes", "canaverales", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "caney especial", "caney", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "ciudad jardin pance", "ciudad jardin", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "ciudad mel?cndez", "ciudad melendez", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "ciudadela paso ancho", "ciudadela pasoancho", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "colon", "cristobal colon", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "el ingenio 3", "el ingenio iii", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "juanamb??", "juanambu", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "las vegas de", "las vegas", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "los cristales club", "los cristales", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "cambulos", "los cambulos", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "san fernando nuevo", "san fernando", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "san fernando viejo", "san fernando", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "valle de lili", "valle del lili", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "tequendema", "tequendama", barrio))
viviwork = viviwork %>%
  mutate(barrio = ifelse(barrio == "rep??blica de israel", "republica de israel", barrio))

3. Análisis de la información y resultados.

Una vez se realiza toda la limpieza, depuración y relleno de los datos faltantes (NA) en la base de datos, se da paso a la revisión de la información mediante el análisis estadístico descriptivo:

3.1 Analisis de precios en la vivienda en Cali

El primer análisis propuesto está relacionado con los descriptivos de la variable precio. En ella encontramos que de todo el conjunto de datos, el precio promedio de una vivienda en Cali está en los $434 millones de pesos; con viviendas desde los $58 hasta los $1999 millones de pesos. El analisis de indicadores cómo la desviación estandar (329), el rango intercuartilico (320) y el coeficiente de variación (0,79) indican una alta variabilidad en los precios y dispersión de datos. En otras palabras, se evidencia la presencia de valores atipicos, una concentración de precios más bajos y una cola larga de precios más altos. [Anexo 2].

#### 3.1.1 Analisis de precio general####
summarytools::descr(viviwork$preciom)
## Descriptive Statistics  
## viviwork$preciom  
## N: 8327  
## 
##                     preciom
## ----------------- ---------
##              Mean    434.25
##           Std.Dev    329.03
##               Min     58.00
##                Q1    220.00
##            Median    330.00
##                Q3    540.00
##               Max   1999.00
##               MAD    209.05
##               IQR    320.00
##                CV      0.76
##          Skewness      1.85
##       SE.Skewness      0.03
##          Kurtosis      3.66
##           N.Valid   8327.00
##         Pct.Valid    100.00

Luego, se realiza un análisis del precio por zona y la variable tipo (apartamento y casa) utilizando el indicador de la media aritmética. Donde los datos indican que la zona menos costosa es Oriente ($228 millones), mientras que en el Oeste, siendo la zona mas costosa, casi que triplican su valor promedio ($678 millones).

La siguiente tabla cruzada y gráfico de barras, dan cuenta de la información mencionada:

#3.1.2 Analisis de precio por zona####
precio_promedio_por_zona = aggregate(preciom ~ zona, data = viviwork, FUN = mean)
kable(precio_promedio_por_zona, 
      caption = "Precio promedio por zona",
      col.names = c("Zona", "Precio Promedio"),
      align = "c",
      digits = 2,
      format = "html",
      table.attr = "class='table table-striped table-hover'",
      row.names = FALSE) %>%
  kable_styling(full_width = FALSE) %>%
  scroll_box(width = "100%", height = "400px")
Precio promedio por zona
Zona Precio Promedio
Zona Centro 309.69
Zona Norte 345.76
Zona Oeste 678.68
Zona Oriente 228.53
Zona Sur 426.52
azul_paleta = colorRampPalette(c("#001865", "#4752ac"))
colores_azulados = azul_paleta(length(precio_promedio_por_zona$precio))

# Gráfico de barras del precio promedio por zona con tamaño de fuente ajustado para las etiquetas de zona
par(mar = c(5, 5, 4, 2) + 0.1) # Establecer los márgenes de la figura
barplot(precio_promedio_por_zona$precio, 
        names.arg = precio_promedio_por_zona$zona,
        xlab = "Zona", 
        ylab = "Precio promedio en millones", 
        col = colores_azulados,
        border = "black",
        ylim = c(0, max(precio_promedio_por_zona$precio) * 1.1),
        main = "Precio promedio de viviendas por zona",
        font.axis = 2, 
        cex.axis = 0.8,
        font.lab = 2, 
        cex.lab = 0.9,
        font.main = 4,
        cex.main = 1.2,
        cex.names = 0.8)

Para profundizar un poco más, se propone ahora el análisis del comportamiento que tienen los precios tanto en apartamentos como en casas.

En la tabla, se observa que las casas son mayormente más costosas que los apartamentos en cualquier zona de Cali; en el oriente (zona con los precios mas bajos) el precio promedio de los apartamentos ronda los 152 millones de pesos y el valor de una casa promedio estaría por los 244 millones, mas costosa inclusive que un apartamento en la zona centro y casi igual que en la zona norte y sur.

Las casas, son el tipo de vivienda más costosa para comprar en Cali de acuerdo a la zona. Por ejemplo, el promedio de la vivienda en el Oeste, estaría en los $736 millones; siendo la ubicación de los barrios más prestigiosos de la ciudad.

# 3.1.3 Precios promedio por zona y tipo de vivienda ####
precios_promedio = aggregate(preciom ~ zona + tipo, data = viviwork, FUN = mean)

# Crear una tabla cruzada de precios promedio por zona y tipo de vivienda
tabla_cruzada = reshape2::dcast(precios_promedio, zona ~ tipo, value.var = "preciom")

# Convertir la tabla cruzada a un data frame
df_tabla = as.data.frame(tabla_cruzada)

kable(df_tabla, 
      caption = "Precios promedio por zona y tipo de vivienda",
      align = "c",
      format = "html",
      col.names = c("Zona", "Precio Apartamento", "Precio Casa"),  # Corregir el orden de las columnas
      row.names = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Precios promedio por zona y tipo de vivienda
Zona Precio Apartamento Precio Casa
Zona Centro 186.5833 339.2400
Zona Norte 285.2577 446.0913
Zona Oeste 669.2676 736.3550
Zona Oriente 152.5968 244.8201
Zona Sur 297.3550 612.0077

Lo anterior, se puede corroborar esta vez haciendo uso del indicador de centro de la mediana, en donde la hipótesis sigue siendo constante para lo mencionado al valor de las casas.

# 3.1.4 Mediana de precios por zona y tipo de vivienda ####

# Calcular las medianas
precios_medianos = aggregate(preciom ~ zona + tipo, data = viviwork, FUN = median)

# Crear una tabla cruzada de precios medianos por zona y tipo de vivienda
tabla_cruzada_medianos = reshape2::dcast(precios_medianos, zona ~ tipo, value.var = "preciom")

# Convertir la tabla cruzada a un data frame
df_tabla_medianos = as.data.frame(tabla_cruzada_medianos)

# Presentar la tabla utilizando kable
kable(df_tabla_medianos, 
      caption = "Medianas de precios por zona y tipo de vivienda",
      align = "c",
      format = "html",
      col.names = c("Zona", "Precio Apartamento", "Precio Casa"),
      row.names = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Medianas de precios por zona y tipo de vivienda
Zona Precio Apartamento Precio Casa
Zona Centro 152.5 310
Zona Norte 250.0 390
Zona Oeste 570.0 680
Zona Oriente 115.0 235
Zona Sur 245.0 480

Ahora, se realizará un análisis de los precios promedio de la vivienda en Cali teniendo en cuenta el estrato socioeconómico al cual pertenen. En la siguiente tabla se puede observar como entre mayor sea el estrato, mayor es la construcción por metro cuadrado de las viviendas con un rango comprendido entre los 210 y 800 mts.

Sucede algo muy parecido con el precio promedio de las viviendas, respecto al estrato socioeconómico; los rangos están comprendidos entre los 131 y 248 millones de pesos.

# Calcular el precio promedio por estrato
precio_promedio_por_estrato = aggregate(preciom ~ estrato, data = viviwork, FUN = mean)

# Calcular el promedio del área construida por cada estrato
areaconstr_promedio_por_estrato = aggregate(areaconst ~ estrato, data = viviwork, FUN = mean)

# Combinar los resultados en una tabla
tabla_precios_areaconstr_por_estrato = merge(precio_promedio_por_estrato, areaconstr_promedio_por_estrato, by = "estrato")

# Renombrar las columnas
colnames(tabla_precios_areaconstr_por_estrato) <- c("Estrato", "Areaconstr_promedio", "Precio_promedio_Cali")

# Mostrar la tabla con kable y kableExtra
kable(tabla_precios_areaconstr_por_estrato, 
      caption = "Tabla de precios promedio de la vivienda en Cali por estrato y área construida",
      align = "c",
      format = "html",
      col.names = c("Estrato", "Área Construida Promedio", "Precio Promedio en Cali"),
      row.names = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Tabla de precios promedio de la vivienda en Cali por estrato y área construida
Estrato Área Construida Promedio Precio Promedio en Cali
3 210.3235 141.6812
4 275.1840 131.2354
5 410.2472 173.2978
6 800.9132 248.4207

Sin embargo, al analizar esta información con un diagrama de cajas, se puede notar que existen datos atípicos para tener en cuenta respecto a la distribución de area de acuerdo al estrato.

# Crear el diagrama de caja para la variable areaconst
boxplot_areaconstr = ggplot(viviwork, aes(x = as.factor(estrato), y = areaconst)) +
  geom_boxplot(fill = "#9abaf9", color = "#001865") +
  labs(title = "Diagrama de caja del área construida por estrato",
       x = "Estrato",
       y = "Área Construida") +
  theme_minimal()

# Mostrar el diagrama de caja
print(boxplot_areaconstr)

Por ello se puede realizar el análisis del area construida con el indicador de la mediana. Arrojando unos datos menores, pero con igual constante, entre mayor sea el estrato socioeconómico, mayor es el area construida.

# Calcular la mediana del área construida por cada estrato
areaconstr_mediana_por_estrato = aggregate(areaconst ~ estrato, data = viviwork, FUN = median)

# Renombrar la columna
colnames(areaconstr_mediana_por_estrato) = c("Estrato", "Areaconstr_mediana")

# Mostrar la tabla con kable y kableExtra
kable(areaconstr_mediana_por_estrato, 
      caption = "Mediana del área construida de la vivienda en Cali por estrato",
      align = "c",
      format = "html",
      col.names = c("Estrato", "Mediana del Área Construida"),
      row.names = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Mediana del área construida de la vivienda en Cali por estrato
Estrato Mediana del Área Construida
3 91
4 83
5 115
6 198

3.2 Análisis del tipo de vivienda más ofertada

Para iniciar, se propone iniciar con un análisis de la participación porcentual de las viviendas por zonas, realizando una discriminación de las zonas donde hay mayor influencia de viviendas. La zona sur representa un 57% de las viviendas, seguida del norte y el oeste con un 23% y 13%, respectivamente. Estas tres zonas conforman un 94% de los datos analizados.

3.2.1 Participación de viviendas por zona.

# Calcular la frecuencia de viviendas por zona
frecuencia_zona = table(viviwork$zona)

# Calcular el porcentaje de viviendas por zona
porcentaje_zona = prop.table(frecuencia_zona) * 100

# Crear un data frame con los resultados
df_porcentaje_zona = data.frame(Zona = names(porcentaje_zona), Porcentaje = as.numeric(porcentaje_zona))

# Mostrar la tabla con kable y kableExtra
kable(df_porcentaje_zona, 
      caption = "Porcentaje de viviendas por zona",
      align = "c",
      format = "html",
      col.names = c("Zona", "Porcentaje"),
      digits = 2,
      row.names = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Porcentaje de viviendas por zona
Zona Porcentaje
Zona Centro 1.49
Zona Norte 23.08
Zona Oeste 14.46
Zona Oriente 4.22
Zona Sur 56.76
# Crear un gráfico de barras para mostrar el porcentaje de viviendas por zona
barplot(porcentaje_zona, 
        main = "Porcentaje de viviendas por zona",
        xlab = "Zona",
        ylab = "Porcentaje",
        col = "#101d78",
        ylim = c(0, 100),
        las = 1)

3.2.2 Vivienda mas ofertada en Cali

De acuerdo con el siguiente gráfico, se puede observar como la participación del tipo de viviendas “apartamentos” es mayor que la de “casas”, 61% y 38% respectivamente.

Dado este resultado, se realizará un análisis mas profundo sobre este tipo de vivienda.

frecuencia_tipo = table(viviwork$tipo) #calcular la frecuencia de tipo
porcentajes = prop.table(frecuencia_tipo) * 100 # Calcular los porcentajes
colores = c("#122777", "#ffb350") # Colores diferenciadores

pie(frecuencia_tipo, 
    labels = paste(names(frecuencia_tipo), " (", round(porcentajes, 2), "%)"),  
    col = colores, 
    border = "black", 
    main = "Distribución de la oferta de vivienda por tipo",
    cex = 0.9)

3.2.3 Analisis del tipo apartamento en relación con las demás variables (estrato, parqueadero, baños, area construida, no de habitaciones).

Al revisar detenidamente el tipo de vivienda apartamento, podemos observar las siguientes caracteristicas: El estrato mayormente participativo es el cinco (5), cuentan con al menos un (1) parqueadero, dos (2) baños y tres (3) habitaciones; el area construida representa una mediana de 90 metros cuadrados.

# Filtrar solo las filas donde el tipo de vivienda sea "apartamento"
apartamentos = viviwork %>%
  filter(tipo == "apartamento")

Mode <- function(x) {
  x <- na.omit(x)  # Eliminar valores NA internamente
  uniqx <- unique(x)
  uniqx[which.max(tabulate(match(x, uniqx)))]
}

# Calcular los promedios por cada variable
promedios_apto = apartamentos %>%
  summarise(Moda_Estrato = Mode(estrato),
            Moda_Parquea = Mode(parquea),
            Moda_Banios = Mode(banios),
            Mediana_Areaconstr = median(areaconst, na.rm = TRUE),
            Moda_Habitac = Mode(habitac))

# Convertir la tabla de promedios a un formato adecuado para kable
tabla_apto = as.data.frame(t(promedios_apto))
colnames(tabla_apto) = c("Vivienda tipo Apartamento")

# Cambiar los nombres de las filas
rownames(tabla_apto) = c("Moda Estrato", "Moda Parqueaderos", "Moda Baños", "Mediana Área Construida", "Moda Habitaciones")

# Mostrar la tabla con kable y kableExtra
kable(tabla_apto, 
      caption = "Datos de variables para apartamentos",
      align = "l",
      col.names = c("Vivienda tipo Apartamento"),
      format = "html",
      digits = 2,
      row.names = TRUE) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                full_width = FALSE)
Datos de variables para apartamentos
Vivienda tipo Apartamento
Moda Estrato 5
Moda Parqueaderos 1
Moda Baños 2
Mediana Área Construida 90
Moda Habitaciones 3

4. Caracteristicas mas relevantes de la oferta de vivienda en Cali

Para observar las caracteristicas mas relevantes de la oferta de vivienda en Cali, se realizará principalmente un analisis de la distribucipon de las variables utilizando diferentes tipos de graficos para tener una idea de la forma y dispersión de cada una de ellas.

4.1 Distribución de variables

Variable Estrato.

El rango de valores de estrato va desde 3 hasta 6. Los cuartiles muestran que la mayoría de los datos se encuentran entre el cuartil 1 (Estrato 4) y el cuartil 3 (Estrato 5), lo que sugiere que la mayoría de las viviendas tienen un estrato de 4 o 5.

descr(viviwork$estrato)
## Descriptive Statistics  
## viviwork$estrato  
## N: 8327  
## 
##                     estrato
## ----------------- ---------
##              Mean      4.63
##           Std.Dev      1.03
##               Min      3.00
##                Q1      4.00
##            Median      5.00
##                Q3      5.00
##               Max      6.00
##               MAD      1.48
##               IQR      1.00
##                CV      0.22
##          Skewness     -0.18
##       SE.Skewness      0.03
##          Kurtosis     -1.11
##           N.Valid   8327.00
##         Pct.Valid    100.00
# Histograma para la variable estrato
hist_estrato = ggplot(viviwork, aes(x = estrato)) +
  geom_histogram(binwidth = 1, fill = "#0f34a3", color = "black") +
  labs(title = "Histograma de la variable 'estrato'", x = "Estrato", y = "Frecuencia") +
  theme_minimal()

# Mostrar el histograma para estrato
print(hist_estrato)

Variable Baño

La distribución del número de baños está sesgada hacia la derecha, lo que indica que la mayoría de las viviendas tienen un número relativamente bajo de baños, pero hay algunas propiedades con un número considerablemente mayor de baños, lo que hace que la media sea más alta que la mediana. La desviación estándar es relativamente alta en comparación con la media, lo que sugiere una dispersión significativa en el número de baños entre las viviendas. La mediana de 3 baños sugiere que la mayoría de las viviendas tienen al menos 3 baños. Existen propiedades con 0 baños, lo que podría indicar que son locales comerciales u otro tipo de construcción que no requiere instalaciones de baño; se deja para posterior análisis y revisión.

descr(viviwork$banios)
## Descriptive Statistics  
## viviwork$banios  
## N: 8327  
## 
##                      banios
## ----------------- ---------
##              Mean      3.11
##           Std.Dev      1.43
##               Min      0.00
##                Q1      2.00
##            Median      3.00
##                Q3      4.00
##               Max     10.00
##               MAD      1.48
##               IQR      2.00
##                CV      0.46
##          Skewness      0.92
##       SE.Skewness      0.03
##          Kurtosis      1.12
##           N.Valid   8327.00
##         Pct.Valid    100.00
# Histograma para la variable banios
hist_banios = ggplot(viviwork, aes(x = banios)) +
  geom_histogram(binwidth = 1, fill = "#0f34a3", color = "black") +
  labs(title = "Histograma de la variable 'baños'", x = "Baños", y = "Frecuencia") +
  theme_minimal()

# Mostrar el histograma para banios
print(hist_banios)

Variable Habitaciones

La distribución del número de habitaciones está sesgada hacia la derecha, lo que significa que la mayoría de las viviendas tienen un número relativamente bajo de habitaciones. Existe una amplia variedad en el número de habitaciones entre las viviendas, como se indica por el rango que va desde 0 hasta 10 habitaciones. La mediana de 3 habitaciones sugiere que la mayoría de las viviendas tienen al menos 3 habitaciones, lo que podría considerarse como una configuración típica para muchas familias.

descr(viviwork$habitac)
## Descriptive Statistics  
## viviwork$habitac  
## N: 8327  
## 
##                     habitac
## ----------------- ---------
##              Mean      3.61
##           Std.Dev      1.46
##               Min      0.00
##                Q1      3.00
##            Median      3.00
##                Q3      4.00
##               Max     10.00
##               MAD      1.48
##               IQR      1.00
##                CV      0.40
##          Skewness      1.64
##       SE.Skewness      0.03
##          Kurtosis      3.99
##           N.Valid   8327.00
##         Pct.Valid    100.00
# Histograma para la variable habitac
hist_habitac = ggplot(viviwork, aes(x = habitac)) +
  geom_histogram(binwidth = 1, fill = "#0f34a3", color = "black") +
  labs(title = "Histograma de la variable 'habitac'", x = "Habitaciones", y = "Frecuencia") +
  theme_minimal()

# Mostrar el histograma para habitac
print(hist_habitac)

# Gráfico de dispersión entre área construida y número de habitaciones
scatter_area_habitac = ggplot(viviwork, aes(x = areaconst, y = habitac)) +
  geom_point(color = "#0f34a3") +  
  labs(title = "Diagrama de dispersión de 'areaconst' vs 'habitac'", x = "Área Construida", y = "Número de Habitaciones") +
  theme_minimal()

# Mostrar el gráfico de dispersión
print(scatter_area_habitac)

Diagramas de dispersión entre las variables variables area construida y precio.

El siguiente gráfico nos muestra una de las hipotesis que se ha venido desarrollando a lo largo del proyecto en el que se argumenta la relación entre el valor y el area construida.

Un coeficiente de correlación de Pearson de aproximadamente 0.687 sugiere una correlación positiva moderadamente fuerte entre el área construida y el precio de venta. Esto significa que, en general, a medida que aumenta el área construida de una vivienda, tiende a aumentar también su precio de venta. Sin embargo, es importante recordar que la correlación no implica causalidad, por lo que otros factores pueden influir en esta relación.

# Dispersion para la variable areaconst
scatter_areaconst = ggplot(viviwork, aes(x = areaconst, y = preciom)) +
  geom_point(color = "#0f34a3") +  # Utilizamos geom_point para crear un diagrama de dispersión
  labs(title = "Diagrama de dispersión de 'areaconst' vs 'preciom'", x = "Área Construida", y = "Precio de Venta") +
  theme_minimal()

# Mostrar el diagrama de dispersión
print(scatter_areaconst)

# Calcular la correlación de Pearson entre areaconst y preciom
correlationpr_ar = cor(viviwork$areaconst, viviwork$preciom)
# Imprimir el valor de correlación
print(correlationpr_ar)
## [1] 0.6872452

4.2 Gráfico de los barrios más importantes, No. viviendas por barrio y precio promedio.

El barrio Valle del Lili representa una participación del 12% sobre los datos recogidos del sector inmobiliario, seguido de ciudad jardin (6,4%) y pance (4%). Estos tres barrios puntean el top 3 de la representación de más viviendas, y coincide con el analisis del sector sur con mayor representatividad.

Si se incluyen otros barrios del sector sur, como el caney, el ingenio y la hacienda, estaríamos hablando de una participación de un 30,43% en el cuadro del top 10 sobre el total de los barrios.

# Contar la frecuencia de cada barrio y ordenar en orden descendente
tabla_barrios = viviwork %>%
  count(barrio) %>%
  arrange(desc(n)) %>%
  rename(Frecuencia_Absoluta = n)

# Seleccionar los primeros diez barrios
top_10_barrios = head(tabla_barrios, 10)

# Crear el gráfico de barras
ggplot(top_10_barrios, aes(x = reorder(barrio, -Frecuencia_Absoluta), y = Frecuencia_Absoluta)) +
  geom_bar(stat = "identity", fill = "#000f66") +
  labs(title = "Top 10 Barrios más representativos de Cali",
       x = "Barrio",
       y = "Frecuencia Absoluta") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

La siguiente tabla, muestra la composición de frecuencias relativas de la variable barrio en relación a su participación y la cantidad de viviendas que lo componen.

# Contar la frecuencia de cada barrio y ordenar en orden descendente
tabla_barrios = viviwork %>%
  count(barrio) %>%
  arrange(desc(n)) %>%
  rename(`Frecuencia Absoluta` = n)

# Calcular la frecuencia relativa
total_observaciones = nrow(viviwork)
tabla_barrios = tabla_barrios %>%
  mutate(`Frecuencia Relativa` = `Frecuencia Absoluta` / total_observaciones)

# Seleccionar los primeros diez barrios
top_10_barrios = head(tabla_barrios, 10)

# Mostrar la tabla formateada con formattable
tabla_formateada_barrios = formattable(top_10_barrios, align = "l",
                                        list(
                                          `Frecuencia Absoluta` = color_tile("lightblue", "blue"),
                                          `Frecuencia Relativa` = color_tile("lightblue", "blue")
                                        ))

# Mostrar la tabla formateada
tabla_formateada_barrios
barrio Frecuencia Absoluta Frecuencia Relativa
valle del lili 1010 0.12129218
ciudad jardin 541 0.06496938
pance 412 0.04947760
la flora 369 0.04431368
santa teresita 263 0.03158400
el caney 209 0.02509908
el ingenio 203 0.02437853
la hacienda 166 0.01993515
normandia 163 0.01957488
acopi 158 0.01897442

Por ultimo, se realiza un analisis geografico de la distribución que tienen los diferentes tipos de vivienda en la ciudad. A una escala satelital, se logra ver la influencia que presenta el sector sur, oeste y norte.

# Coordenadas del centro de Cali, Colombia
centro_cali_lat = 3.4516
centro_cali_lon = -76.5320

# Definir un rango más amplio para las coordenadas (en grados)
rango_lat = 1.0
rango_lon = 1.0

# Función para limpiar los datos de latitud y longitud
limpiar_coordenadas = function(data, centro_lat, centro_lon, rango_lat, rango_lon) {
  lat_min <- centro_lat - rango_lat
  lat_max <- centro_lat + rango_lat
  lon_min <- centro_lon - rango_lon
  lon_max <- centro_lon + rango_lon
  
  # Filtrar datos dentro del rango
  data = data[data$latitud >= lat_min & data$latitud <= lat_max & 
                 data$longitud >= lon_min & data$longitud <= lon_max, ]
  
  return(data)
}

# Elaboración de mapa
df_viviwork = data.frame(
  longitud = viviwork$longitud,
  latitud = viviwork$latitud,
  preciom = viviwork$preciom,
  zona = viviwork$zona
)

# Limpiar coordenadas
df_viviwork = limpiar_coordenadas(df_viviwork, centro_cali_lat, centro_cali_lon, rango_lat, rango_lon)

# Crear el mapa
mapa = leaflet(df_viviwork) %>%
  addTiles() %>%
  addCircleMarkers(
    ~longitud, ~latitud,
    radius = 1,
    color = "red",
    fill = TRUE,
    fillOpacity = 0.7
  )

mapa

Anexos

Anexo 1. Análisis de datos perdidos en la base de datos

vis_miss(vivienda_faltantes)

Anexo 2. Diagrama de cajas para analizar el precio en el total de datos

boxplot(viviwork$preciom,
        main = "Diagrama de Cajas del Precio de la Vivienda",
        ylab = "Precio (en millones)",
        col = "#9abaf9",
        border = "#001865",
        horizontal = TRUE)  # Para un diagrama horizontal

Anexo 3. Análisis de estrato por tipo de vivienda

# Filtrar los apartamentos con estrato 4 y 5
apartamentos_estrato_4_5 = apartamentos %>%
  filter(estrato %in% c(4, 5))

# Calcular el número total de apartamentos
total_apartamentos = nrow(apartamentos)

# Calcular el número de apartamentos con estrato 4 y 5
total_estrato_4_5 = nrow(apartamentos_estrato_4_5)

# Calcular el porcentaje
porcentaje_estrato_4_5 = (total_estrato_4_5 / total_apartamentos) * 100

# Mostrar el resultado
porcentaje_estrato_4_5
## [1] 62.10341

Conclusiones, recomendaciones y discusión.

Conclusiones.

A continuación, se organizan las conclusiones por áreas de interés, lo que proporciona una estructurada de los hallazgos y facilita la comprensión para la empresa en la toma de decisiones estratégicas.

  • Predominancia de apartamentos: Más del 60% de las viviendas en Cali son de tipo apartamento, lo que indica una inclinación hacia propiedades de tipo horizontal. Este fenómeno puede estar influenciado por el alto costo de las casas en la región.

  • Precios inferiores de apartamentos: Los apartamentos tienden a tener precios inferiores en comparación con las casas. Esta diferencia de precios puede influir en las decisiones de compra y en la percepción del valor de la propiedad.

  • Crecimiento en zonas periféricas: Se observa un crecimiento significativo en las zonas sur y norte de Cali, que colindan con los municipios de Jamundí y Yumbo. Estas áreas muestran un gran potencial en el sector inmobiliario, lo que sugiere oportunidades de inversión y desarrollo.

  • Zonas de mayor Valor: Las zonas sur, norte y oeste son las más caras del mercado inmobiliario en Cali. Estas áreas también son las más demandadas y ofrecen una amplia variedad de opciones de vivienda, lo que contribuye a la rápida valorización de las propiedades.

  • Configuración de viviendas: Es importante considerar el número de baños y habitaciones en las viviendas, ya que esto puede influir en la preferencia de los compradores y en el diseño de estrategias de mercado. La presencia de viviendas con un solo ambiente puede indicar un nicho de mercado específico que debe ser atendido.

  • Viviendas de interés social: Es importante considerar la oferta de viviendas de interés social en el análisis, ya que estas propiedades juegan un papel crucial en la satisfacción de la demanda de vivienda asequible y en el desarrollo social y económico de la región.

  • Nichos de mercado: Se identifica un fuerte nicho de mercado en los estratos 4 y 5, donde el 62% de los apartamentos se ubican. Esto sugiere oportunidades para dirigir estrategias de marketing y desarrollo de productos hacia este segmento específico de la población.

Recomendaciones:
  • Considerar otros estratos y zonas: Ampliar el alcance del análisis para incluir estratos inferiores y zonas como el oriente de la ciudad, donde predominan las viviendas unifamiliares y se pueden encontrar propiedades de estratos 3 o inferiores. Esto permitirá tener una visión más completa y representativa del mercado inmobiliario en Cali.

  • Mejorar métodos de recopilación de datos: Implementar métodos más efectivos para el levantamiento de información a fin de reducir la presencia de datos faltantes (NA). Esto podría incluir la mejora de los procesos de recolección y registro de datos, así como la implementación de controles de calidad para garantizar la integridad de la información recopilada.

Discusión:
  • El proceso de imputación de datos se utilizó para las variables de parqueadero y piso debido a la presencia de valores perdidos en el conjunto de datos, sin embargo, se observa que el porcentaje de datos perdidos supera el umbral sugerido del 20%, lo que plantea preocupaciones sobre la fiabilidad de los resultados. Aunque se recomienda no considerar estas variables como objetos de estudio prioritarios para la toma de decisiones debido a estas limitaciones, eliminarlas por completo podría generar una pérdida aún mayor de información valiosa. La teoría sugiere trabajar con conjuntos de datos cuya pérdida no supere el 20%, lo que destaca la necesidad de abordar estas limitaciones en futuros análisis para garantizar la validez y confiabilidad de los resultados obtenidos.