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.
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.
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:
Carga de datos fuente y visualización previa.
Preparación de los datos: orden, transformación y limpieza.
Análisis estadístico: definición de variables de interés y aplicación de descriptivos.
Visualización e interpretación de resultados.
Anexos, conclusiones, recomendaciones y discusión.
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.
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)
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)
| 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 |
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:
Para comprobar lo anterior, se realizaran dos tipos análisis:
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)
| Tipo | Faltantes | Porcentaje |
|---|---|---|
| apartamento | 1383 | 52.426080363912 |
| casa | 1255 | 47.573919636088 |
| Total | 2638 | 100 |
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)
| 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.
En este punto, se plantea realizar dos propuestas para rellenar los datos faltantes:
#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
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)
| 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)
| 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")
| Tipo de vivienda | Promedio de Pisos | Promedio de Parqueaderos |
|---|---|---|
| apartamento | 5 | 2 |
| casa | 3 | 3 |
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")
| 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 |
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))
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:
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")
| 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)
| 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)
| 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)
| 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)
| Estrato | Mediana del Área Construida |
|---|---|
| 3 | 91 |
| 4 | 83 |
| 5 | 115 |
| 6 | 198 |
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.
# 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)
| 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)
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)
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)
| Vivienda tipo Apartamento | |
|---|---|
| Moda Estrato | 5 |
| Moda Parqueaderos | 1 |
| Moda Baños | 2 |
| Mediana Área Construida | 90 |
| Moda Habitaciones | 3 |
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.
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)
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)
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)
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
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
vis_miss(vivienda_faltantes)
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
# 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
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.
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.