knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE, collapse = FALSE, comment = "#>", render = TRUE)
Se inicia el análisis cargando las bibliotecas necesarias para trabajar con los datos y visualizaciones.
#install.packages("devtools")
#devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
#install.packages("psych")
#install.packages("naniar")
#install.packages("corrplot")
#install.packages("ggplot2")
#install.packages("factoextra")
library(psych)
library(naniar)
library(corrplot)
library(ggplot2)
library(factoextra)
library(tidyverse)
library(cluster)
library(FactoMineR)
library(gridExtra)
library(paqueteMODELOS)
data("vivenda")
Se definen funciones que serán utilizadas a lo largo del análisis para realizar tareas específicas, como:
# Calcula la moda de una columna de un dataframe
Mode <- function(columna) {
columna_sin_vacios <- columna[is.na(columna)]
frecuencias <- table(columna)
moda <- names(frecuencias)[which.max(frecuencias)]
return(moda)
}
# Calcula la moda de todas las columnas de un dataframe
ModeDf <- function(df) {
moda_dataframe <- data.frame(x=1)
for(name in colnames(df)) {
moda_dataframe[name] <- Mode(df[name])
}
return(moda_dataframe)
}
# Codifica una columna categorica para pasarla a numerica
LabelEncoder <- function(columna) {
name <- colnames(columna)
columna_codificada <- factor(columna[[name]])
columna_codificada <- as.numeric(columna_codificada)
return(columna_codificada)
}
#Codifica todas las columnas categoricas de un dataframe
LabelEncoderDF <- function(df) {
for(name in colnames(df)){
if(is.character(df[[name]])){
df[name] <- LabelEncoder(df[name])
}
}
return(df)
}
#Crea un histograma para una variable
Histograma <- function(columna) {
name <- colnames(columna)
ggplot(data = columna, aes(x = !!sym(name))) +
geom_histogram(fill = "black", color = "white") +
theme_minimal() +
ggtitle(paste("Distribución de:", name)) +
xlab("Valores") +
ylab("Frecuencia")
}
# Crea Histogramas para las variables numericas de un dataframe
HistogramasDf <- function(df) {
for(name in colnames(df)){
if(is.numeric(df[[name]])) {
print(Histograma(df[name]))
}
}
}
#Crea un grafico de barras para una columna de un dataframe
GraficoBarras <- function(columna) {
name <- colnames(columna)
ggplot(data = columna, aes(x = !!sym(name))) +
geom_bar(fill = "black", color = "white") +
labs(title = paste("Frecuencia de:", name), x = name, y = "Cantidad") +
theme_minimal()
}
#Crea graficos de barras para todas las columnas categoricas de un dataframe
GraficosBarrasDf <- function(df) {
for(name in colnames(df)) {
if(is.character(df[[name]])){
print(GraficoBarras(df[name]))
}
}
}
#Crea un grafico de barras bivariado
MultiGraficoBarras <- function(df, name, fill) {
ggplot(data = df, aes(x = !!sym(name), fill = !!sym(fill))) +
geom_bar() +
labs(title = paste("Frecuencia de:", name, "y", fill), x = name, y = "Frecuencia") +
theme_minimal()
}
#Crea graficos de barras bivariados para cada columna categorica del dataframe
MultiGraficoBarrasDf <- function(df) {
for(name in colnames(df)) {
for(fill in colnames(df)) {
if(!is.character(df[[name]]) | !is.character(df[[fill]])) { next }
if(name == fill) { next }
print(MultiGraficoBarras(df, name, fill))
}
}
}
#Crea un grafico de dispersion para un par de columnas de un dataframe
GraficoDispersion <- function(df, col_x, col_y) {
ggplot(data = df, aes(x = !!sym(col_x), y = !!sym(col_y))) +
geom_point() +
theme_minimal() +
labs(title = paste(col_x, "vs", col_y))
}
GraficosDispersionDf <- function(df) {
for(name_x in colnames(df)) {
for(name_y in colnames(df)){
if(!is.numeric(df[[name_x]]) | !is.numeric(df[[name_y]])) {next}
if(name_x == name_y) { next}
print(GraficoDispersion(df, name_x, name_y))
}
}
}
Se emplea la función describe de la biblioteca psych para calcular estadísticas descriptivas de las variables numéricas, como la media, desviación estándar, mediana, mínimo, máximo, etc. Estas medidas proporcionan información sobre la distribución y variabilidad de los datos.
#Imprimimos para una primera vista de la información.
print(vivienda)
#> # A tibble: 8,322 × 13
#> id zona piso estrato preciom areaconst parqueaderos banios habitaciones
#> <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1147 Zona … <NA> 3 250 70 1 3 6
#> 2 1169 Zona … <NA> 3 320 120 1 2 3
#> 3 1350 Zona … <NA> 3 350 220 2 2 4
#> 4 5992 Zona … 02 4 400 280 3 5 3
#> 5 1212 Zona … 01 5 260 90 1 2 3
#> 6 1724 Zona … 01 5 240 87 1 3 3
#> 7 2326 Zona … 01 4 220 52 2 2 3
#> 8 4386 Zona … 01 5 310 137 2 3 4
#> 9 1209 Zona … 02 5 320 150 2 4 6
#> 10 1592 Zona … 02 5 780 380 2 3 3
#> # ℹ 8,312 more rows
#> # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
#Verificamos la estructura del dataframe (filas y columnas)
cat("\nnumero de filas:", nrow(vivienda))
#>
#> numero de filas: 8322
cat("\nnumero de columnas:", ncol(vivienda))
#>
#> numero de columnas: 13
#Tipos de datos
str(vivienda)
#> spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
#> $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
#> $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
#> $ piso : chr [1:8322] NA NA NA "02" ...
#> $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
#> $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
#> $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
#> $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
#> $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
#> $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
#> $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
#> $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
#> $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
#> $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
#> - attr(*, "spec")=
#> .. cols(
#> .. id = col_double(),
#> .. zona = col_character(),
#> .. piso = col_character(),
#> .. estrato = col_double(),
#> .. preciom = col_double(),
#> .. areaconst = col_double(),
#> .. parqueaderos = col_double(),
#> .. banios = col_double(),
#> .. habitaciones = col_double(),
#> .. tipo = col_character(),
#> .. barrio = col_character(),
#> .. longitud = col_double(),
#> .. latitud = col_double()
#> .. )
#> - attr(*, "problems")=<externalptr>
variables_categoricas = c("zona", "piso", "tipo", "barrio")
variables_numericas = c("estrato", "preciom", "areaconst", "parqueaderos", "banios", "habitaciones", "longitud", "latitud")
#Medidas de tendencia central
describe(vivienda)
#> vars n mean sd median trimmed mad min max
#> id 1 8319 4160.00 2401.63 4160.00 4160.00 3083.81 1.00 8319.00
#> zona* 2 8319 3.92 1.33 5.00 4.04 0.00 1.00 5.00
#> piso* 3 5684 3.77 2.61 3.00 3.37 1.48 1.00 12.00
#> estrato 4 8319 4.63 1.03 5.00 4.67 1.48 3.00 6.00
#> preciom 5 8320 433.89 328.65 330.00 374.43 207.56 58.00 1999.00
#> areaconst 6 8319 174.93 142.96 123.00 149.15 84.51 30.00 1745.00
#> parqueaderos 7 6717 1.84 1.12 2.00 1.62 1.48 1.00 10.00
#> banios 8 8319 3.11 1.43 3.00 2.99 1.48 0.00 10.00
#> habitaciones 9 8319 3.61 1.46 3.00 3.41 1.48 0.00 10.00
#> tipo* 10 8319 1.39 0.49 1.00 1.36 0.00 1.00 2.00
#> barrio* 11 8319 241.48 128.83 251.00 245.34 171.98 1.00 436.00
#> longitud 12 8319 -76.53 0.02 -76.53 -76.53 0.02 -76.59 -76.46
#> latitud 13 8319 3.42 0.04 3.42 3.42 0.05 3.33 3.50
#> range skew kurtosis se
#> id 8318.00 0.00 -1.20 26.33
#> zona* 4.00 -0.59 -1.36 0.01
#> piso* 11.00 1.28 1.05 0.03
#> estrato 3.00 -0.18 -1.11 0.01
#> preciom 1941.00 1.85 3.67 3.60
#> areaconst 1715.00 2.69 12.91 1.57
#> parqueaderos 9.00 2.33 8.31 0.01
#> banios 10.00 0.93 1.13 0.02
#> habitaciones 10.00 1.63 3.98 0.02
#> tipo* 1.00 0.46 -1.78 0.01
#> barrio* 435.00 -0.09 -1.23 1.41
#> longitud 0.13 0.65 0.58 0.00
#> latitud 0.16 0.03 -1.15 0.00
#Revision de datos faltantes
faltantes <- is.na(vivienda)
columnas_na <- data.frame(colSums(faltantes))
cat("cantidad de datos faltantes:", sum(faltantes))
#> cantidad de datos faltantes: 4275
cat("\ncantidad de datos faltantes por columna:\n")
#>
#> cantidad de datos faltantes por columna:
columnas_na #Imprimimos
#> colSums.faltantes.
#> id 3
#> zona 3
#> piso 2638
#> estrato 3
#> preciom 2
#> areaconst 3
#> parqueaderos 1605
#> banios 3
#> habitaciones 3
#> tipo 3
#> barrio 3
#> longitud 3
#> latitud 3
cat("\n Mayor cantidad de faltantes en una fila:", max(rowSums(faltantes)))
#>
#> Mayor cantidad de faltantes en una fila: 13
#Grafico de faltantes por variable
gg_miss_var(vivienda)
#Dado que tenemos 13 columnas, eliminaremos los registros que posean más de 6 datos faltantes, esto con el objetivo de no emplear registros
#en nuestro modelo que tengan casi todos sus datos imputados.
filas_con_muchos_faltantes <- rowSums(faltantes) >= 6 #Vector Logico
cat("\n Numero de filas con mas de 6 datos faltantes:", sum(rowSums(faltantes) >= 6))
#>
#> Numero de filas con mas de 6 datos faltantes: 3
#Quitamos las filas con muchos faltantes
vivienda <- vivienda[!filas_con_muchos_faltantes, ]
Puede verse que existen gran cantidad de datos faltantes en las variables piso y parqueaderos, nos es imposible eliminar estos registros ya que estariamos eliminando gran parte de nuestro dataframe, por lo que emplearemos una imputación simple en etapas posteriores.
#Matriz de correlaciones
columnas_numericas <- sapply(vivienda, is.numeric)
corrplot(cor(vivienda[, columnas_numericas]), method = "color", type = "upper")
Se evidencia una amplia correlación entre la columna id y la variable longitud, esto no nos afecta ya que la variable id es una variable no estadistica y no se empleara en los analisis.
Se verifica nuevamente la presencia de datos faltantes con gg_miss_var(vivienda) para confirmar que se hayan imputado correctamente.
Se generan histogramas para las variables numéricas, lo que permite visualizar la forma de su distribución, identificar valores comunes y atípicos, y detectar asimetrías.
Se crean gráficos de barras para las variables categóricas. Estos gráficos muestran la frecuencia de cada categoría, lo que facilita la comparación de su popularidad.
#Imputación de datos faltantes.
#Para la variable parqueaderos emplearemos la moda
vivienda[is.na(vivienda["parqueaderos"]), "parqueaderos"] <- as.numeric(Mode(vivienda["parqueaderos"]))
#Se emplea la media para imputar las variables numericas.
#Se emplea la moda para las variables categoricas
for(colname in colnames(vivienda)) {
faltantes_columna <- is.na(vivienda[colname])
if(is.numeric(vivienda[[colname]])) {
vivienda[faltantes_columna, colname] <- mean(vivienda[[colname]], na.rm = TRUE)
}
if(is.character(vivienda[[colname]])){
vivienda[faltantes_columna, colname] <- Mode(vivienda[colname])
}
}
gg_miss_var(vivienda)
HistogramasDf(vivienda[, variables_numericas])
Cabe resaltar la distribución de las variables Areaconst y preciom, ya que están inclinados a la izquierda, indicando que ambas variables tienen muchos datos con precios muy bajos y areas muy bajas.
GraficosBarrasDf(vivienda[, variables_categoricas])
Puede verse que la mayor concentración de viviendas se encuentra en la zona sur y que la mayoria de viviendas son de tipo apartamento.
GraficosDispersionDf(vivienda[, c("preciom", "areaconst")])
De estas graficas de dispersión llama la atención la linealidad que existe entre las variables de area y precio, lo cual tiene sentido ya que el area puede ser un determinante para estimar el precio de una vivienda.
MultiGraficoBarrasDf(vivienda[,c("zona", "tipo", "piso")])
Las variables tipo y zona son muy importantes para un analisis bi variado, cabe resaltar que los apartamentos predominan en las zonas sur, norte y oeste, mientras que las viviendas de tipo casa predominan en las zonas oriente y centro.
Gráfico de Varianza Explicada: El gráfico de “screeplot” muestra la varianza explicada por cada componente principal. Los primeros componentes suelen explicar la mayor parte de la varianza, y se pueden utilizar para reducir la dimensionalidad del dataset.
Gráfico de Variables: El gráfico de variables en el PCA muestra la contribución de cada variable a los componentes principales. Las variables que más contribuyen a los primeros componentes son las más importantes para explicar la varianza del dataset.
Gráfico de Individuos: El gráfico de individuos en el PCA muestra la posición de cada vivienda en el espacio de los componentes principales. Los clusters de viviendas en este gráfico podrían indicar grupos con características similares.
#Variables candidatas para PCA
variables_pca <- c("preciom", "areaconst", "parqueaderos", "banios", "habitaciones", "longitud", "latitud")
#Estandarización de variables numericas
vivienda_Z <- scale(vivienda[, variables_pca])
pca <- prcomp(vivienda_Z)
fviz_eig(pca, addlabels = TRUE)
fviz_pca_var(pca,
col.var = "contrib", # Color by contributions to the PC
gradient.cols = c("#FF7F00", "#034D94"),
repel = TRUE # Avoid text overlapping
)
casos1 <- pca$x[c(1762, 3282), 1:2] # CP1
casos1 <- as.data.frame(casos1)
casos2 <- pca$x[c(2926, 8073), 1:2] # CP2
casos2 <- as.data.frame(casos2)
fviz_pca_ind(pca, col.ind = "#DEDEDE", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07")) +
geom_point(data = casos1, aes(x = PC1, y = PC2), color = "red", size = 3) +
geom_point(data = casos2, aes(x = PC1, y = PC2), color = "blue", size = 3)
vivienda[c(1762, 3282), ] #Mostramos las casas correspondiente al caso1
#> # A tibble: 2 × 13
#> id zona piso estrato preciom areaconst parqueaderos banios habitaciones
#> <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 5684 Zona S… 02 6 1800 1586 10 4 5
#> 2 69 Zona O… 02 3 165 80 1 0 0
#> # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
El analisis PCA nos indican que las 6 variables pueden explicarse con los 3 primeros componentes y se cubriria una gran parte de su varianza.
Tambien podemos visualizar que las variables precio, baños, area y habitaciones son las mas importantes para explicar la varianza de las 6 variables.
En esta sección se empleara el analisis de conglomerados.
Gráficos de Clusters: Los gráficos de dispersión con colores representando los clusters permiten visualizar la separación de los grupos. Se pueden analizar las características de cada cluster (por ejemplo, viviendas grandes y caras vs. viviendas pequeñas y económicas).
Coeficiente de Silhouette: El coeficiente de Silhouette mide la calidad de los clusters, con valores cercanos a 1 indicando clusters bien definidos.
#Convertimos nuestro matrix estandarizada a dataframe
vivienda_Z <- data.frame(vivienda_Z)
# distancia euclidiana
dist_emp <- dist(vivienda_Z, method = 'euclidean')
# Cluster jerarquico con el método complete
hc_emp <- hclust(dist_emp, method = 'complete')
# Determinamos a dónde pertenece cada observación
cluster_assigments <- cutree(hc_emp, k = 2)
# asignamos los clusters
assigned_cluster <- vivienda_Z %>% mutate(cluster = as.factor(cluster_assigments))
# gráfico de puntos
ggplot(assigned_cluster, aes(x = areaconst, y = preciom, color = cluster)) +
geom_point(size = 4) +
geom_text(aes(label = cluster), vjust = -.8) + # Agregar etiquetas del clúster
theme_classic()
ggplot(assigned_cluster, aes(x = habitaciones, y = preciom, color = cluster)) +
geom_point(size = 4) +
geom_text(aes(label = cluster), vjust = -.8) + # Agregar etiquetas del clúster
theme_classic()
ggplot(assigned_cluster, aes(x = banios, y = preciom, color = cluster)) +
geom_point(size = 4) +
geom_text(aes(label = cluster), vjust = -.8) + # Agregar etiquetas del clúster
theme_classic()
ggplot(assigned_cluster, aes(x = parqueaderos, y = preciom, color = cluster)) +
geom_point(size = 4) +
geom_text(aes(label = cluster), vjust = -.8) + # Agregar etiquetas del clúster
theme_classic()
dist_emp <- dist(vivienda_Z, method = "euclidean")
dendograma <- hclust(dist_emp, method = "average")
# plot(dendograma, cex = 0.6, hang = -1)
barplot(sort(dendograma$height, decreasing = TRUE), horiz = TRUE,
main = "Agregaciones (distancias euclidianas)",
col = "lightblue", ylab = "Nodo", xlab = "Peso", xlim = c(0, 2.5))
# distancia euclidiana
dist_emp <- dist(vivienda_Z, method = 'euclidean')
# Cluster jerarquico con el método complete
hc_emp <- hclust(dist_emp, method = 'complete')
# Determinamos a dónde pertenece cada observación
cluster_assigments <- cutree(hc_emp, k = 2)
# Calcular el coeficiente de Silhouette
sil <- silhouette(cluster_assigments, dist(vivienda_Z))
sil_avg <- mean(sil[,3])
# Imprimir el coeficiente de Silhouette promedio
cat("Coeficiente de Silhouette promedio k=4 : ", sil_avg)
#> Coeficiente de Silhouette promedio k=4 : 0.5381144
Gráfico de Varianza Explicada: Similar al PCA, el gráfico de “screeplot” en el análisis de correspondencia muestra la varianza explicada por cada eje.
Gráfico de Variables: El gráfico de variables muestra la asociación entre variables categóricas y los ejes. Las variables que más contribuyen a los primeros ejes son las más importantes para explicar la asociación entre las variables.
variables_categoricas <- sapply(vivienda, is.character)
tabla <- table(vivienda[, c("zona", "piso")])
tabla
#> piso
#> zona 01 02 03 04 05 06 07 08 09 10 11 12
#> Zona Centro 33 71 8 5 5 0 0 0 0 0 2 0
#> Zona Norte 177 1074 189 129 117 33 33 39 32 27 33 37
#> Zona Oeste 86 514 134 99 84 80 57 43 41 28 20 12
#> Zona Oriente 74 206 54 8 8 0 0 0 0 1 0 0
#> Zona Sur 490 2220 712 366 353 132 114 129 73 74 29 34
chisq.test(tabla)
#>
#> Pearson's Chi-squared test
#>
#> data: tabla
#> X-squared = 430.17, df = 44, p-value < 2.2e-16
resultados_ac <- CA(tabla)
valores_prop <-resultados_ac$eig ; valores_prop
#> eigenvalue percentage of variance cumulative percentage of variance
#> dim 1 0.0331063664 64.024467 64.02447
#> dim 2 0.0122885295 23.764812 87.78928
#> dim 3 0.0054182840 10.478430 98.26771
#> dim 4 0.0008957491 1.732291 100.00000
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
tabla <- table(vivienda[, c("zona", "estrato")])
tabla
#> estrato
#> zona 3 4 5 6
#> Zona Centro 105 14 4 1
#> Zona Norte 572 407 769 172
#> Zona Oeste 54 84 290 770
#> Zona Oriente 340 8 2 1
#> Zona Sur 382 1616 1685 1043
chisq.test(tabla)
#>
#> Pearson's Chi-squared test
#>
#> data: tabla
#> X-squared = 3830.4, df = 12, p-value < 2.2e-16
resultados_ac <- CA(tabla)
valores_prop <-resultados_ac$eig ; valores_prop
#> eigenvalue percentage of variance cumulative percentage of variance
#> dim 1 0.32215213 69.965515 69.96551
#> dim 2 0.12745096 27.680002 97.64552
#> dim 3 0.01084108 2.354483 100.00000
fviz_screeplot(resultados_ac, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+
ylab("Porcentaje de varianza explicado") + xlab("Ejes")
El mapa de factor CA nos permite identificar las relaciones entre las variables (zona y piso) ademas de (zona y estratos).
Donde puede visualizarse que los pisos mas altos (11 y 12) se encuentran relacionados a la zona norte, mientras que las zonas sur y oeste se llevan la mayor acumulación de diferentes valores de la variable piso.
Esto nos puede indicar que la mayor cantidad de datos se encuentran en estas dos zonas.
En cuanto a los estratos, podemos idenficar que las viviendas de estrato 6 estan estrechamente relacionadas con la zona oeste. Los estratos 4 y 5 estan fuertemente relacionados con la zona sur.
El análisis exploratorio de datos realizado sobre el mercado inmobiliario ha revelado información valiosa que puede ser aprovechada para la toma de decisiones estratégicas. A continuación, se detallan los hallazgos más relevantes:
Se observó una concentración de viviendas con precios y áreas construidas relativamente bajas, lo que sugiere una mayor oferta en este segmento del mercado.
El área construida se identificó como un factor determinante en el precio de las viviendas, mostrando una clara relación lineal.
La zona sur concentra la mayor cantidad de viviendas, y los apartamentos son el tipo de vivienda predominante.
La presencia de datos faltantes, especialmente en las variables ‘piso’ y ‘parqueaderos’, requirió la implementación de técnicas de imputación para asegurar la integridad del análisis.
La alta concentración de viviendas con precios y áreas reducidas indica una posible oportunidad para la empresa inmobiliaria en este nicho de mercado, ya sea para la construcción de nuevos proyectos o la adquisición de propiedades existentes para su posterior venta o alquiler.
La zona sur, dada su popularidad, podría ser un área estratégica para la inversión, aunque es crucial considerar también otros factores como la competencia y el potencial de crecimiento de otras zonas.
La preferencia por los apartamentos sugiere que este tipo de vivienda debería ser prioritario en la estrategia de la empresa, ya sea para la compra, venta o alquiler.
Considerar la posibilidad de desarrollar proyectos inmobiliarios dirigidos al segmento de precios bajos, donde existe una mayor demanda. Esto podría incluir la construcción de apartamentos de menor tamaño o la renovación de propiedades existentes para ofrecer opciones más asequibles.
Realizar un estudio más profundo de cada zona, incluyendo factores como la competencia, la presencia de servicios y el potencial de crecimiento. Esto permitirá identificar las zonas más atractivas para la inversión y desarrollar estrategias específicas para cada una de ellas.
Diseñar estrategias de marketing específicas para cada tipo de vivienda y zona, destacando los beneficios y características únicas de cada propiedad. Utilizar herramientas digitales y redes sociales para llegar a un público más amplio y generar mayor interés en los proyectos.
Al seguir las recomendaciones propuestas, la empresa podrá optimizar su inversión, maximizar sus beneficios y alcanzar una posición competitiva en un mercado en constante evolución.
La implementación de tecnologías de análisis de datos y la mejora continua de la calidad de la información serán clave para mantener una ventaja competitiva y adaptarse a las cambiantes demandas del mercado.