Brayan Hernandez Cardona

knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE, collapse = FALSE, comment = "#>", render = TRUE)

Carga de Datos:

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")

Funciones Auxiliares:

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))

    }
  }
}

Reconocimiento del dataset

Estructura y Tipos de Datos:

  • Se utiliza la función print(vivienda) para obtener una vista previa de los datos y la función str(vivienda) para examinar la estructura del dataframe, incluyendo el número de filas y columnas, así como los tipos de datos de cada variable.
  • Se identifican las variables categóricas y numéricas presentes en el conjunto de datos.

Medidas de Tendencia Central y Dispersión:

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.

Datos Faltantes:

  • Se utiliza la función is.na para identificar los valores faltantes en el dataframe y se calcula la cantidad total de faltantes.
  • Se resume la cantidad de faltantes por columna.
  • Se calcula la mayor cantidad de faltantes en una fila.
  • Se genera un gráfico de barras para visualizar la cantidad de faltantes por variable.
  • Se decide eliminar las filas con 6 o más datos faltantes para evitar trabajar con registros incompletos.

Correlaciones:

  • Se seleccionan las columnas numéricas del dataframe y se calcula la matriz de correlación para verificar el relacionamiento entre cada par de variable.
  • Se visualiza la matriz de correlación con corrplot, donde los colores representan la fuerza y dirección de las correlaciones entre las variables.
#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.

Preparación de los datos

Imputación de Datos Faltantes:

  • Se imputan los valores faltantes en la variable parqueaderos utilizando la moda.
  • Se imputan los valores faltantes en las demás variables numéricas utilizando la media.
  • Se imputan los valores faltantes en las variables categóricas utilizando la moda.

Se verifica nuevamente la presencia de datos faltantes con gg_miss_var(vivienda) para confirmar que se hayan imputado correctamente.

Visualización de la Distribución de Datos:

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.

Visualización de Frecuencias de Variables Categóricas:

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.

Analisis de Componentes PCA

#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.

Analisis de Conglomerados

En esta sección se empleara el analisis de conglomerados.

#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

Analisis de Correspondencia

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.

Analisis Final

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:

Distribución de precios y áreas:

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.

Variables predictoras del precio:

El área construida se identificó como un factor determinante en el precio de las viviendas, mostrando una clara relación lineal.

Ubicación y tipo de vivienda:

La zona sur concentra la mayor cantidad de viviendas, y los apartamentos son el tipo de vivienda predominante.

Datos faltantes:

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.

Conclusiones Clave

Oportunidades en el segmento de precios bajos:

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.

Importancia de la ubicación:

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.

Demanda de apartamentos:

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.

Recomendaciones Específicas

Conclusion