El mercado inmobiliario es un sector clave para el desarrollo económico y social de las ciudades, pues refleja las dinámicas de oferta y demanda de vivienda, oficinas, comercio y otros usos del suelo. En este trabajo se realiza un análisis del mercado de viviendas en Cali, una de las principales ciudades de Colombia, que se caracteriza por su diversidad, cultura y potencial de crecimiento
El objetivo de este trabajo es identificar las características más relevantes del mercado inmobiliario de viviendas en Cali, así como los factores que lo determinan y las tendencias que se observan. Para ello, se utiliza una base de datos suministrada por la empresa B&C. Esta base de datos contiene información de variables con las características y venta de viviendas en Cali.
El trabajo se divide en tres partes. En la primera parte se describe la metodología empleada para limpiar, imputar y explorar la base de datos, utilizando herramientas estadísticas y computacionales. En la segunda parte se presentan los resultados del análisis descriptivo del mercado de vivienda, agrupadas por tipo y zona, y se destacan las características más importantes de cada segmento. En la tercera parte se discuten las principales conclusiones y recomendaciones del trabajo, dirigidas a los directivos de la agencia inmobiliaria B&C.
Realizar un análisis del mercado de viviendas en Cali, aplicando métodos estadísticos para limpiar, imputar y presentar los datos, con el fin de brindar información útil y relevante a los directivos de la empresa B&C.
Preparar la base de datos suministrada por la empresa B&C para generar información de calidad.
Elaborar análisis de la información para producir estadísticas relevantes para la toma de decisiones en materia del mercado de vivienda de Cali.
Presentar las conclusiones del análisis.
En esta sección se abordan las principales actividades desarrolladas para garantizar la calidad e integridad de la información suministrada. Se identifican los duplicados por la variable “id”, se corrigen los errores de entrada generados por errores de digitación como ortográficos, uso no adecuado de mayúsculas o minúsculas, entre otros y por último, la imputación de valores faltantes (na)
En este primer paso cargamos la base de datos que contiene 8330 registros y 13 variables.
A continuación, se obtienen los indicadores básicos de las variables:
Se observan valores atípicos en las variables latitud y longitud y valores faltantes en todas las variables (aparecen 8327 cuando en la tabla inicial se informan 8330), además en piso y parquea los faltantes superan los 2300 registros.
El proceso de limpieza consistirá en la eliminación de duplicados, recodificación de las variables categóricas barrio y tipo y, de las variables numéricas latitud y longitud. Posteriormente se imputarán los valores faltantes para que la base tenga la calidad requerida para el análisis de la información.
Teniendo en cuenta que la variable id es la que se utiliza para identificar las viviendas, se requiere eliminar los valores faltantes (na) y posteriormente los duplicados
# Eliminación de los valores NA del id
vivienda <- vivienda_faltantes[!is.na(vivienda_faltantes$id), ]
rm(vivienda_faltantes) # eliminar la base inicial
duplicados <- duplicated(vivienda$id) # genera una vista con las columnas duplicadas
vivienda_con_duplicados <- vivienda[duplicados, ] # genera una tabla con los duplicados
head(vivienda_con_duplicados) # Revisar el subconjunto de datosPara los análisis de precios, no se recomienda usar la variable del precio de la vivienda porque varía en función del área, por lo tanto, se calcula una variable muy usada en el mercado inmobiliario: el precio por metro. Para este análisis se multiplica por mil para que los análisis sean más faciles de leer.
Se ajustan las categorías de las variables tipo, latitud, longitud y barrio
La tabulación de la variable se presenta a continuación:
tabla_tipo <- count(vivienda, tipo)
tabla_tipo <- rbind(tabla_tipo, data.frame(tipo = "NA", n = sum(is.na(vivienda$tipo))))
# Ordenar la tabla por frecuencia
tabla_tipo <- arrange(tabla_tipo, desc(n))
tabla_tipoComo se puede apreciar, la variable en principio tiene 6 categorías, no obstante solo son dos: Casa y Apartamento, por lo tanto se hacen los reemplazos del caso.
vivienda <- vivienda %>%
mutate(tipo = recode(tipo, "apto" = "Apartamento", "APARTAMENTO" = "Apartamento", "casa" = "Casa", "CASA" = "Casa"))Una vez aplicada la limpieza, la variable tipo presenta el siguiente comportamiento:
Las variables latitud y longitud contienen errores por mostrar coordenadas que no corresponden a Cali.
En el tabulado inicial se mostraban valores mínimos y máximos para longitud de -76.66 y -76499 respectivamente, se sabe que la longitud promedio para Cali está alrededor de los -76
El procedimiento consiste en detectar valores infreriores a -60000 y hace una división por mil, los demás valores que no cumplan esta condición quedan igual.
vivienda$longitud <- ifelse(vivienda$longitud > -60000, vivienda$longitud, vivienda$longitud/1000)
ggplot(vivienda, aes(x = longitud)) +
stat_density(geom = "line") +
labs(title = "Gráfica 1. Densidad de probabilidad de longitud", x = "Longitud")La gráfica anterior muestra la curva de densidad de probabilidad de que un valor de la variable se encuentre en un rango específico, nos interesa que sus valores estén alrededor de -76
Al igual que con la longitud, la latitud tiene valores máximos (9437) y mínimos (3.33) que no corresponden con la ubicación espacial de Cali, se aplica una división por mil si los datos superan el valor de 4.
vivienda$latitud <- ifelse(vivienda$latitud < 4, vivienda$latitud, vivienda$latitud/1000)
ggplot(vivienda, aes(x = latitud)) +
stat_density(geom = "line") +
labs(title = "Gráfica 2. Densidad de probabilidad de latitud", x = "Latitud")En el gráfico anterior se aprecia la variable ya ajustada.
Esta variable es la más compleja de ajustar, por la cantidad de datos únicos que tiene. Una inspección visual muestra posibles errores de digitación y de denominación del barrio, además del uso de tildes en unos casos y en otros no.
# Contar los valores distintos de la variable "barrio"
barrio_frec=table(vivienda$barrio) %>% data.frame() # ver tabulado de la variable
kable(head(barrio_frec, 10), format = "markdown")| Var1 | Freq |
|---|---|
| 20 de julio | 3 |
| 3 de julio | 1 |
| acopi | 158 |
| agua blanca | 1 |
| aguablanca | 2 |
| aguacatal | 109 |
| alameda | 16 |
| alameda del rio | 1 |
| alameda del río | 2 |
| alamos | 14 |
numero_barrios <- n_distinct(vivienda$barrio)
# Imprimir un mensaje con el número de barrios sin ajustar
mensaje <- paste("Hay", numero_barrios, "categorías de barrios")
mensaje## [1] "Hay 436 categorías de barrios"
Así las cosas, se organizan los ajustes con un flujo, donde primero, se transforman todas categorías de la variable en minúsculas (función tolower), después se reeemplazan las tildes y caracteres especiales con la función sapply y por último se buscan las categorías parecidas que hacen pensar que se trata de la misma pero con escritura distinta, por ejemplo “agua blanca” y aguablanca.
######2.5 ajustar barrio ######
barrio_frec=table(vivienda$barrio) %>% data.frame() # ver tabulado de la variable
vivienda$barrio <- tolower(vivienda$barrio) # Convertir en minúsculas
# Crear una tabla de búsqueda para las tildes y caracteres especiales
ajustar <- c("á", "é", "í", "ó", "ú", "√©", "√∫")
ajustada <- c("a", "e", "i", "o", "u", "e", "u")
# Sustituir las letras con tilde por las letras sin tilde en la columna "barrio"
vivienda$barrio <- sapply(vivienda$barrio, function(x) {
for (i in 1:length(ajustar)) {
x <- gsub(ajustar[i], ajustada[i], x)
}
return(x)
})
# Reemplazar las categorías en la columna "barrio"
# Categorías a reemplazar
categorias <- c("agua blanca", "bloques del limonar", "ciudadela paso ancho", "el gran limonar",
"el caney", "el ingenio 3", "la primavera", "las vegas de", "libertadores", "pampalinda",
"portada de comfandi", "rincon de salomia", "san judas tadeo", "santa helena de", "tequendema",
"urbanizacion rio lili", "valle de lili", "zona norte los", "arboleda")
n_categorias <- c("aguablanca", "bosques del limonar", "ciudadela pasoancho", "gran limonar",
"caney", "el ingenio iii", "primavera", "las vegas", "los libertadores", "pampa linda",
"portales de comfandi", "salomia", "san judas", "santa elena", "tequendama",
"urbanizacion lili", "valle del lili", "zona norte", "arboledas")
for (i in 1:length(categorias)) {
vivienda[vivienda$barrio == categorias[i], "barrio"] <- n_categorias[i]
}
barrio_frec=table(vivienda$barrio) %>% data.frame() # ver tabulado de la variable
# Mostrar las 10 primeras filas de la tabla
kable(head(barrio_frec, 10), format = "markdown")| Var1 | Freq |
|---|---|
| 20 de julio | 3 |
| 3 de julio | 1 |
| acopi | 158 |
| aguablanca | 3 |
| aguacatal | 109 |
| alameda | 16 |
| alameda del rio | 3 |
| alamos | 14 |
| alborada | 1 |
| alcazares | 2 |
Como se observa, los barrios como aguablanca y alameda del rio quedaron con nombres unificados.
Identificamos las variables con valores faltantes
La variable piso y parquea presentan valores en blanco (na), trataremos las imputaciones por separado.
Existen distintas técnicas para imputar valores faltantes, por ejemplo, la media, la moda, la mediana, sin embargo, como la variable de interes es una variable discreta y contamos con otras variables que ayudan a identificar el valor más probable de la variable, se utilizó la librería mice y el método MCC. Este método predice los valores faltantes utilizando la media condicional y luego ajusta los valores predichos para que coincidan con la distribución de los valores observados. Esta técnica se aplicó para sustituir los valores faltantes de la variable piso.
Para utilizar este método, se convierten las variables categóricas en continuas (zona, barrio y tipo) con la función factor, se ajusta con 50 iteraciones.
ggplot(vivienda, aes(x = .data[["piso"]])) +
geom_histogram() +
labs(title = "Gráfica 3. Distribución de 'piso' antes de la imputación")na_piso <- sum(is.na(vivienda$piso)) # Revisar la cantidad de NA en "piso"
mensaje <- paste("Hay", na_piso, "valores en blanco")
mensaje## [1] "Hay 2635 valores en blanco"
######3.1 convertir variables categóricas a numéricas ######
# Convertir la variable "tipo" a numérica
vivienda$tipo_num <- as.numeric(factor(vivienda$tipo))
vivienda$barrio_num <- as.numeric(factor(vivienda$barrio))
vivienda$zona_num <- as.numeric(factor(vivienda$zona))
######3.2 Imputar la variable piso con el paquete mice ######
# Crear un conjunto de datos con las variables relevantes para la imputación
data_impute <- vivienda[, c("estrato", "preciom", "areaconst", "banios", "habitac", "tipo_num", "barrio_num", "zona_num", "piso")]
# Realizar la imputación utilizando el método MICE (Multiple Imputation by Chained Equations)
imputed_data <- mice(data_impute, method = "pmm", m = 5, maxit = 50, printFlag = FALSE)
# Combinar los conjuntos de datos imputados en un único conjunto de datos
imputed_data_complete <- complete(imputed_data)
# Agregar la columna imputada "piso_imp" a la tabla vivienda
# vivienda$piso_imp <- imputed_data_complete$piso
vivienda$piso <- imputed_data_complete$pisoA continuación se presenta el gréfico con la variable ajustada con la imputación, no se aprecian cambios abruptos en la distribución de frecuencias.
ggplot(vivienda, aes_string(x = "piso")) +
geom_histogram() +
labs(title = "Gráfica 4. Distribución de 'piso' después de la imputación")En el caso de la variable de número de parqueaderos (parquea), al tabular la información por estratos, se observa que no hay valores de cero, es decir que en la base no tendrían viviendas sin parqueadero, para hacer la imputación se podría asumir que si el campo está en blanco es porque no hay parqueadero. Se observa que los NA se concentran especialmente en estrato 3 y 4, así las cosas, se sustituyen los NA por ceros.
ggplot(data = vivienda, aes_string(x = "parquea")) +
geom_bar(stat = "count", position = "identity") +
labs(x = "Parquea", y = "Frecuencia", title = "Gráfica 5. Distribución de parqueaderos") +
theme_minimal()tabla_na <- table(factor(vivienda$estrato, levels = unique(vivienda$estrato)), ifelse(is.na(vivienda$parquea), "Con NA", "Sin NA")) %>% data.frame()
# Convertir la tabla a formato Markdown
tabla_markdown <- knitr::kable(tabla_na, format = "markdown")
# Mostrar la tabla en Markdown
tabla_markdown| Var1 | Var2 | Freq |
|---|---|---|
| 6 | Con NA | 117 |
| 5 | Con NA | 228 |
| 3 | Con NA | 769 |
| 4 | Con NA | 488 |
| 6 | Sin NA | 1870 |
| 5 | Sin NA | 2522 |
| 3 | Sin NA | 684 |
| 4 | Sin NA | 1641 |
na_parquea <- sum(is.na(vivienda$parquea))
mensaje <- paste("Hay", na_parquea, "valores en blanco")
mensaje## [1] "Hay 1602 valores en blanco"
En este paso se reemplazan los NA por ceros.
######Imputar los valores NA de la variable parquea con ceros
vivienda$parquea <- replace(vivienda$parquea, is.na(vivienda$parquea), 0)
na_parquea <- sum(is.na(vivienda$parquea))
mensaje <- paste("Hay", na_parquea, "valores en blanco")
mensaje## [1] "Hay 0 valores en blanco"
En resumen, en esta sección de preparación de las bases de datos, se eliminaron valores NA y duplicados de la variable id, se imputaron valores faltantes en parquea y piso, se recategorizaron los nombres de barrios y de tipo de vivienda y por último, se ajustaron los valores de latitud y longitud, así las cosas se procederá a hacer un análisis descriptivo.
En esta sección se procede a hacer un análisis estadístico-descriptivo que permita caracterizar el mercado inmobiliario de viviendas.
En primer lugar, se hará un análisis de la oferta de vivienda.
conteo <- table(vivienda$zona) # se obtiene la variable tabulada
# Crear un vector con los nombres de las categorías
nombres <- c("Zona Centro", "Zona Norte", "Zona Oeste", "Zona Oriente", "Zona Sur")
colores <- c("#f95738","#ee964b", "#f4d35e", "#faf0ca", "#0d3b66") # paleta de colores
porcentajes <- round(conteo / sum(conteo) * 100, 1) # Crear un vector con los porcentajes de cada categoría
# Crear un vector con las etiquetas que combinan los nombres, los valores absolutos y los porcentajes
etiquetas <- paste0(nombres, " (", conteo, ", ", porcentajes, "%)")
pie(conteo, labels = etiquetas, main = "Gráfica 6. Distribución de viviendas por zona", col = colores) # Crear el gráficoLa mayor oferta de vivienda se encuentra en la zona sur con mas del 56% de las unidades y la zona norte con 23%, en contraste las zonas centro y oriente concentran apenas el 5,7%.
conteo <- table(vivienda$tipo)
nombres <- c("Apartamento", "Casa")
colores <- c("#ee964b", "#0d3b66") # paleta de colores
porcentajes <- round(conteo / sum(conteo) * 100, 1)
etiquetas <- paste0(nombres, " (", conteo, ", ", porcentajes, "%)")
pie(conteo, labels = etiquetas, main = "Gráfica 7. Distribución de viviendas por tipo", col = colores) # Crear el gráficoDe otra parte, se observa que el tipo de vivienda predominante son los apartamentos con 61% de las unidades y las casas participan con el 39% restante.
En la siguiente gráfica se cruzan las variables tipo y zona para ver cómo se comporta la oferta.
# graficar las unidades por zona y tipo
ggplot(vivienda, aes(fill = tipo, y = after_stat(count), x = zona)) +
geom_bar(position = "dodge") +
labs(title = "Gráfica 8. Distribución de Tipos de Vivienda por Zona",
x = "Zona",
y = "Número de viviendas") +
theme_test()En la zona centro y oriental, los apartamentos participan con el 19% y 18% respectivamente, mientras que en las demás zonas, los apartamentos están alrededor del 60% para las zonas norte y sur y el 86% para la zona oeste.
Continuando con el análisis, ahora se presenta la distribución de las viviendas por estrato:
conteo <- table(vivienda$estrato) # se obtiene la variable tabulada
# Crear un vector con los nombres de las categorías
nombres <- c("Estrato 3", "Estrato 4", "Estrato 5", "Estrato 6")
colores <- c("#ee964b", "#f4d35e", "#faf0ca", "#0d3b66") # paleta de colores
porcentajes <- round(conteo / sum(conteo) * 100, 1) # Crear un vector con los porcentajes de cada categoría
# Crear un vector con las etiquetas que combinan los nombres, los valores absolutos y los porcentajes
etiquetas <- paste0(nombres, " (", conteo, ", ", porcentajes, "%)")
pie(conteo, labels = etiquetas, main = "Gráfica 9. Distribución de viviendas por estrato", col = colores) # Crear el gráficoEl gráfico muestra que el 50% está equilibrado entre los estratos 4 y 6, el estrato 5 es el que tiene la mayor participación (33%) y el 3 la menor (17,5%).
# Crear un dataframe con el conteo por zona y estrato
conteo_zona_estrato <- vivienda %>%
group_by(zona) %>%
count(estrato)
# Crear el gráfico de barras
ggplot(conteo_zona_estrato, aes(x = fct_reorder(zona, n), y = n, fill = estrato)) +
geom_bar(stat = "identity") +
labs(title = "Gráfica 10. Distribución de viviendas por estrato",x = "Zona", y = "Unidades", fill = "Estrato") +
theme_test()Cuando se hace el cruce de las unidades de vivienda por estrato, se observa que en las zonas con menor oferta (oriente y centro), casi el total es estrato 3, en la zona oeste predomina el 6 y los estratos 3 y 4 son escasos, en las zonas norte y sur predomina el estrato 5. También se aprecia que las zona oeste y sur concentran las viviendas estrato 6.
Ahora, se presentan las viviendas por zona, tipo y promedio de las características como número de baños, parqueaderos, habitaciones y pisos.
# Gráfico anidado de viviendas por tipo, zona y promedios
promedio_banios <- aggregate(banios ~ zona + tipo, data = vivienda, FUN = mean)
promedio_parquea <- aggregate(parquea ~ zona + tipo, data = vivienda, FUN = mean)
promedio_habitac <- aggregate(habitac ~ zona + tipo, data = vivienda, FUN = mean)
promedio_piso <- aggregate(piso ~ zona + tipo, data = vivienda, FUN = mean)
grafico1 <- ggplot(promedio_banios, aes(x = zona, y = banios, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Baños", y = "Promedio de baños") +
theme(plot.title = element_text(size = 10, hjust = 0.5)) +
guides(fill = FALSE)
grafico2 <- ggplot(promedio_parquea, aes(x = zona, y = parquea, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Parqueaderos", y = "Promedio de parqueaderos") +
theme(plot.title = element_text(size = 10, hjust = 0.5))
grafico3 <- ggplot(promedio_habitac, aes(x = zona, y = habitac, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Habitaciones", y = "Promedio de habitaciones") +
theme(plot.title = element_text(size = 10, hjust = 0.5)) +
guides(fill = FALSE)
grafico4 <- ggplot(promedio_piso, aes(x = zona, y = piso, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Pisos", y = "Promedio de pisos") +
theme(plot.title = element_text(size = 10, hjust = 0.5))
# Combinar los gráficos en un solo gráfico de 2x2
grid.arrange(grafico1, grafico2, grafico3, grafico4, nrow = 2, ncol = 2, top = "Gráfica 11. Viviendas por zona, tipo y promedio de baños, parqueaderos, habitaciones y pisos.")De la gráfica 11 se observa que las viviendas para las zonas oeste y sur tienen un promedio de cerca de 5 baños en las casas, en los apartamentos la zona oeste se caracteriza por un promedio de 4, le sigue la zona sur con 3, tambien, en dotación de parqueaderos, la zona sur tiene más que la zona 3 en las casas, en los apartamentos la situación se invierte. Lss zonas centro y oriente tienen menos baños y parqueadero que las demás zonas. En cuanto a las habitaciones, los apartamentos tienen el mismo promedio (3) en todas las zonas, llama la atención que aunque en las zonas centro y oriente hay menos baños y parqueaderos, en materia de habitaciones, en las casas llevan la delantera.
Siguendo con las características de las viviendas, el gráfico 12 muestra el número promedio de las características que las componen, esta vez cruzado por tipo y estrato.
# Gráfico anidado de viviendas por tipo, estrato y promedios
prom_ban_est <- aggregate(banios ~ estrato + tipo, data = vivienda, FUN = mean)
prom_parquea_est <- aggregate(parquea ~ estrato + tipo, data = vivienda, FUN = mean)
prom_habitac_est <- aggregate(habitac ~ estrato + tipo, data = vivienda, FUN = mean)
prom_piso_est <- aggregate(piso ~ estrato + tipo, data = vivienda, FUN = mean)
grafico1 <- ggplot(prom_ban_est, aes(x = estrato, y = banios, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Baños", y = "Promedio de baños") +
theme(plot.title = element_text(size = 10, hjust = 0.5)) +
guides(fill = FALSE)
grafico2 <- ggplot(prom_parquea_est, aes(x = estrato, y = parquea, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Parqueaderos", y = "Promedio de parqueaderos") +
theme(plot.title = element_text(size = 10, hjust = 0.5))
grafico3 <- ggplot(prom_habitac_est, aes(x = estrato, y = habitac, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Habitaciones", y = "Promedio de habitaciones") +
theme(plot.title = element_text(size = 10, hjust = 0.5)) +
guides(fill = FALSE)
grafico4 <- ggplot(prom_piso_est, aes(x = estrato, y = piso, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Pisos", y = "Promedio de pisos") +
theme(plot.title = element_text(size = 10, hjust = 0.5))
# Combinar los gráficos en un solo gráfico de 2x2
grid.arrange(grafico1, grafico2, grafico3, grafico4, nrow = 2, ncol = 2, top = "Gráfica 12. Viviendas por estrato, tipo y promedio de baños, parqueaderos, habitaciones y pisos.")El análisis por estrato muestra que a mayor estrato, en los apartamentos hay más baños y parqueaderos, para el primero la diferencia es de 2 unidades entre el estrato más bajo y el más alto, para el segundo, hay una diferencia de 1 a 4 en casas y de 1 a 5 en apartamentos. En habitaciones ocurre los contrario en las casas, a mayor estrato menos habitaciones y en los apartamentos no hay diferencias significativas. Por último, en pisos, las casa están cerca a los dos, en los apartamentos es mayor el número de pisos en los estratos más altos.
Para terminar con las características de la vivienda en Cali, se presenta el área promedio de las viviendas por tipo, zona y estrato.
# Gráfico anidado de viviendas por tipo, estrato y promedio de área
prom_tama_zona <- aggregate(areaconst ~ zona + tipo, data = vivienda, FUN = mean)
prom_tama_est <- aggregate(areaconst ~ estrato + tipo, data = vivienda, FUN = mean)
grafico1 <- ggplot(prom_tama_zona, aes(x = zona, y = areaconst, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Zona", y = "Promedio metros cuadrados") +
theme(plot.title = element_text(size = 10, hjust = 0.5)) +
guides(fill = FALSE)
grafico2 <- ggplot(prom_tama_est, aes(x = estrato, y = areaconst, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Estrato", y = "Promedio metros cuadrados") +
theme(plot.title = element_text(size = 10, hjust = 0.5),
axis.title.y = element_blank())
# Combinar los gráficos en un solo gráfico de1x2
grid.arrange(grafico1, grafico2, nrow = 1, ncol = 2, top = "Gráfica 13. Área promedio de viviendas por tipo, zona y estrato.")La gráfica anterior evidencia que en los apartamentos, el área es uniforme en las zonas, excepto a la Oeste, donde el metraje es casi el doble que las demás. En las casas el área de la zona Oeste es de 343 metros, la zona sur 282, miestras que las zonas oriente y centro tienen un área promedio a los 217 metros cuadrados.
En síntesis, la zona sur tiene la mayor oferta de vivienda, las zonas centro y oriente participan con menos del 5,7%, la zona occidente se caracteriza por la prevalencia de apartamentos (hay 6 apartamentos con cada casa) y la zona occidente tiene más parqueaderos y baños por vivienda. El 57 de las viviendas están en los estratos 5 y 6 y hay una relación directa entre la cantidad promedio de parqueaderos y baños: a mayor estrato, mayor cantidad de estos componentes y en contraste, a mayor estrato, menos promedio de habitaciones en las casas. El área de los apartamentos es similar en las zonas excepto la oeste que es cerca del doble, asimismo, el área de las viviendas es mayor conforme aumenta el estrato.
En esta sección se hará el análisis de los precios de las viviendas, en principio, se graficarán los dos indicadores asociados al precio, el precio total (preciom) y el precio por metro cuadrado (p_m2) para identificar cuál es más conveniente para los análisis.
# Crear un gráfico de boxplot de precio total por tipo de vivienda
grafico_p1 <- ggplot(vivienda, aes(x = tipo, y = preciom, fill = tipo)) +
geom_boxplot() +
labs(title = "Precio total",
x = "Tipo de Vivienda",
y = "Precio total - millones") +
theme(plot.title = element_text(size = 10, hjust = 0.5)) +
guides(fill = FALSE)
# Crear un gráfico de boxplot de p_m2 por tipo de vivienda
grafico_p2 <- ggplot(vivienda, aes(x = tipo, y = p_m2, fill = tipo)) +
geom_boxplot() +
labs(title = "Precio por metro cuadrado",
x = "Tipo de Vivienda",
y = "Precio por metro cuadrado - miles") +
theme(plot.title = element_text(size = 10, hjust = 0.5)) +
guides(fill = FALSE)
# Combinar los gráficos en un solo gráfico de1x2
grid.arrange(grafico_p1, grafico_p2, nrow = 1, ncol = 2, top = "Gráfica 14. Comparativa precio total de las viviendas y precio de metro cuadrado.")Como muestran las gráficas tipo boxplot, al utilizar el precio total el rango de los datos es superior y presenta más valores atípicos que al usar el precio por metro cuadrado, la primera variable está fuertemente influenciada por el área de la vivienda. Así las cosas, en adelante los precios se analizarán con la variable precio por metro cuadrado.
# Gráfico anidado de viviendas por tipo, estrato y promedio de área
prom_precio_zona <- aggregate(p_m2 ~ zona + tipo, data = vivienda, FUN = mean)
prom_precio_est <- aggregate(p_m2 ~ estrato + tipo, data = vivienda, FUN = mean)
grafico1 <- ggplot(prom_precio_zona, aes(x = zona, y = p_m2, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Zona", y = "Precio metro cuadrado") +
theme(plot.title = element_text(size = 10, hjust = 0.5)) +
guides(fill = FALSE)
grafico2 <- ggplot(prom_precio_est, aes(x = estrato, y = p_m2, fill = tipo)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Estrato", y = "Precio metro cuadrado") +
theme(plot.title = element_text(size = 10, hjust = 0.5),
axis.title.y = element_blank())
# Combinar los gráficos en un solo gráfico de1x2
grid.arrange(grafico1, grafico2, nrow = 1, ncol = 2, top = "Gráfica 15. Precio promedio de metro cuadrado por tipo, zona y estrato.")El precio promedio del metro cuadrado es más alto en la zona oeste tanto en casas como en apartamentos, para las casas es ligeramente superior y para los apartamentos es 30% más costoso que en la zona sur y más del 200% más costoso que la zona más barata. Teniendo en cuenta que el precio del metro cuadrado es más barato en las zonas centro y oriente, y como se mencionaba antes, estas zonas tienen una participación muy baja en el total, por lo que se podría minimizar los esfuerzos en esas zonas y aumentar la gestión en las zonas sur y occidente, especialmente en los apartamentos.
De otra parte, el valor del metro cuadrado por estrato muestra un comportamiento típico, es decir, que a mayor estrato, es más costoso y se evidencia tanto en casas como en apartamentos. Llama la atención que en el estrato 6 el precio del metro cuadrado es el doble del estrato 3 para los apartamentos y poco menos del doble para las casas.
vivienda_casa4 <- subset(vivienda, tipo == "Casa" & estrato == "4")
vivienda_casa4 <- aggregate(p_m2 ~ parquea, data = vivienda_casa4, FUN = mean)
vivienda_apto4 <- subset(vivienda, tipo == "Apartamento" & estrato == "4")
vivienda_apto4 <- aggregate(p_m2 ~ parquea, data = vivienda_apto4, FUN = mean)
vivienda_casa5 <- subset(vivienda, tipo == "Casa" & estrato == "5")
vivienda_casa5 <- aggregate(p_m2 ~ parquea, data = vivienda_casa5, FUN = mean)
vivienda_apto5 <- subset(vivienda, tipo == "Apartamento" & estrato == "5")
vivienda_apto5 <- aggregate(p_m2 ~ parquea, data = vivienda_apto5, FUN = mean)
vivienda_casa6 <- subset(vivienda, tipo == "Casa" & estrato == "6")
vivienda_casa6 <- aggregate(p_m2 ~ parquea, data = vivienda_casa6, FUN = mean)
vivienda_apto6 <- subset(vivienda, tipo == "Apartamento" & estrato == "6")
vivienda_apto6 <- aggregate(p_m2 ~ parquea, data = vivienda_apto6, FUN = mean)
# Crear los gráficos
graf1 <- ggplot(vivienda_casa4, aes(x = parquea, y = p_m2, fill = parquea)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de parqueaderos", y = "Estrato 4") +
ggtitle("Casas") +
ylim(0, 5000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5))
graf2 <- ggplot(vivienda_apto4, aes(x = parquea, y = p_m2, fill = parquea)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de parqueaderos", y = "Precio metro cuadrado") +
ggtitle("Apartamentos") +
ylim(0, 5000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5),
axis.title.y = element_blank())
graf3 <- ggplot(vivienda_casa5, aes(x = parquea, y = p_m2, fill = parquea)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de parqueaderos", y = "Estrato 5") +
ggtitle("Casas") +
ylim(0, 5000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5))
graf4 <- ggplot(vivienda_apto5, aes(x = parquea, y = p_m2, fill = parquea)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de parqueaderos", y = "Precio metro cuadrado") +
ggtitle("Apartamentos") +
ylim(0, 5000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5),
axis.title.y = element_blank())
graf5 <- ggplot(vivienda_casa6, aes(x = parquea, y = p_m2, fill = parquea)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de parqueaderos", y = "Estrato 6") +
ggtitle("Casas") +
ylim(0, 5000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5))
graf6 <- ggplot(vivienda_apto6, aes(x = parquea, y = p_m2, fill = parquea)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de parqueaderos", y = "Precio metro cuadrado") +
ggtitle("Apartamentos") +
ylim(0, 5000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5),
axis.title.y = element_blank())
grid.arrange(graf1, graf2, graf3, graf4, graf5, graf6, nrow = 3, ncol = 2, top = "Gráfica 16. Precio promedio de metro cuadrado por estrato, tipo y número de parqueaderos.")El precio del metro cuadrado, en los apartamentos el valor más alto del metro cuadrado es para los que tienen 3 parqueaderos en los estratos 4 al 6, en el estrato 6 el metro cuadrado de los apartamentos es más barato si tiene solamente un parqueadero.
En las casas, el estrato 4 tiene un mejor precio si tiene un parqueadero mientras que en los estratos del 5 y 6 se valora más el metro cuadrado con dos parqueaderos. No se hace mención de las casa con más de 6 parqueaderos, pues son datos atípicos.
vivienda_casa4 <- subset(vivienda, tipo == "Casa" & estrato == "4")
vivienda_casa4 <- aggregate(p_m2 ~ habitac, data = vivienda_casa4, FUN = mean)
vivienda_apto4 <- subset(vivienda, tipo == "Apartamento" & estrato == "4")
vivienda_apto4 <- aggregate(p_m2 ~ habitac, data = vivienda_apto4, FUN = mean)
vivienda_casa5 <- subset(vivienda, tipo == "Casa" & estrato == "5")
vivienda_casa5 <- aggregate(p_m2 ~ habitac, data = vivienda_casa5, FUN = mean)
vivienda_apto5 <- subset(vivienda, tipo == "Apartamento" & estrato == "5")
vivienda_apto5 <- aggregate(p_m2 ~ habitac, data = vivienda_apto5, FUN = mean)
vivienda_casa6 <- subset(vivienda, tipo == "Casa" & estrato == "6")
vivienda_casa6 <- aggregate(p_m2 ~ habitac, data = vivienda_casa6, FUN = mean)
vivienda_apto6 <- subset(vivienda, tipo == "Apartamento" & estrato == "6")
vivienda_apto6 <- aggregate(p_m2 ~ habitac, data = vivienda_apto6, FUN = mean)
# Crear los gráficos
graf1 <- ggplot(vivienda_casa4, aes(x = habitac, y = p_m2, fill = habitac)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de habitaciones", y = "Estrato 4") +
ggtitle("Casas") +
xlim(0,7) +
ylim(0, 6000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5))
graf2 <- ggplot(vivienda_apto4, aes(x = habitac, y = p_m2, fill = habitac)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de habitaciones", y = "Precio metro cuadrado") +
ggtitle("Apartamentos") +
xlim(0,7) +
ylim(0, 6000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5),
axis.title.y = element_blank())
graf3 <- ggplot(vivienda_casa5, aes(x = habitac, y = p_m2, fill = habitac)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de habitaciones", y = "Estrato 5") +
ggtitle("Casas") +
xlim(0,7) +
ylim(0, 6000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5))
graf4 <- ggplot(vivienda_apto5, aes(x = habitac, y = p_m2, fill = habitac)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de habitaciones", y = "Precio metro cuadrado") +
ggtitle("Apartamentos") +
xlim(0,7) +
ylim(0, 6000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5),
axis.title.y = element_blank())
graf5 <- ggplot(vivienda_casa6, aes(x = habitac, y = p_m2, fill = habitac)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de habitaciones", y = "Estrato 6") +
ggtitle("Casas") +
xlim(0,7) +
ylim(0, 6000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5))
graf6 <- ggplot(vivienda_apto6, aes(x = habitac, y = p_m2, fill = habitac)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Número de habitaciones", y = "Precio metro cuadrado") +
ggtitle("Apartamentos") +
xlim(0,7) +
ylim(0, 6000) +
guides(fill = FALSE) +
theme(plot.title = element_text(size = 10, hjust = 0.5),
axis.title.y = element_blank())
grid.arrange(graf1, graf2, graf3, graf4, graf5, graf6, nrow = 3, ncol = 2, top = "Gráfica 17. Precio promedio de metro cuadrado por estrato, tipo y número de habitaciones")Al cruzar el valor promedio del metro cuadrado de las casas en los estratos por número de habitaciones, se observa que en el estrato 4, el precio es mejor con 2 habitaciones (no se tiene en cuenta el precio con una habitación, pues tiene valores atípicos). Los estratos 5 y 6 se valoran mejor si la casa tiene 3 habitaciones. Se observa que en estrato 6 el número mínimo de habitaciones es 3.
En cuanto a los apartamentos, el precio más alto es para los que tienen una habitación, sin embargo, esta afirmación se debe validar con la empresa, puesto que los apartamentos con una sola habitación son muy pocos. Omitiendo lo anterior, se aprecia que los apartamentos con 2 habitaciones se valoran mejor que los que tienen tres aunque las diferencias de precio no son significativas.
Si bien este análisis de la oferta y el precio de la vivienda presenta las características más relevantes, no permite realizar un análisis explicativo ni determinar tendencias temporales. Además, la falta de variables como el margen de comisión por venta, o las fechas de comercialización limita la capacidad de ofrecer alternativas para la maximización de ingresos u otros análisis más avanzados. Por lo tanto, las recomendaciones se basan en la oferta y el precio de los inmuebles.
A continuación se presentarán las conclusiones a partir de la información suministrada:
Las zonas centro y oriente tienen una participación marginal dentro del mercado, además, los precios del metro cuadrado son menores que en las otras zonas, por ello, para obtener más ganancias, se recomienta dirigir los esfuerzos en las zonas donde la dinámica de la oferta y los precios son mayores.
Los precios por metro cuadrado son mayores en los apartamentos que en las casas, si se tiene en cuenta el estrato, la relación es directa independientemente del tipo de vivienda. En cuanto a la zona, los mayores precios los tiene la zona Oeste, el metro cuadrado de un apartamento en este sector cuesta el doble que uno ubicado en el oriente. En cuanto a cantidad y precio, la zona sur tiene las mejores condiciones, aunque el precio promedio no es el más alto, el volumen de viviendas que hay allí hace que sea un lugar muy atractivo en el mercado.
Los precios por metro cuadrado de los apartamentos son mejores cuando tienen tres parqueaderos, mientras que para las casas, en estrato 4 el metro cuadrado es más costoso con un parqueadero y en los estratos 5 y 6 los precios aumentan con dos parqueaderos.
Se recomienda poner foco en las zonas oeste y sur pues concentran el 71% de las viviendas y cuentan con los precios promedio del metro cuadrado más elevados de la ciudad, sin embargo, la zona norte aunque tiene menores precios de casas, cuenta con el 23% de participación, una cifra nada despreciable y un precio del metro cuadrado de apartamentos de menos del 20% de la zona sur.
Se recomienda incorporar variables como la fecha de venta de las viviendas, el valor de la comisión por venta, el tiempo de demora de la venta, para hacer análisis más avanzados que permitan establecer en qué epocas del año el mercado es más dinámico y cuales son aquellas zonas donde se pueden maximizar los ingresos con la misma capacidad operativa o simular cuánto se aumentan los ingresos con el aumento de más personas en el equipo de ventas.
En el mismo sentido, se recomienda hacer análisis de tipo inferencial para determinar cuáles son los factores que determinan el precio del metro cuadrado, la facilidad de las ventas, el tiempo promedio de ventas, entre otros análisis.