Modelos Estadísticos para la toma de decisiones
Una empresa inmobiliaria líder en una gran ciudad está buscando comprender en profundidad el mercado de viviendas urbanas para tomar decisiones estratégicas más informadas. La empresa posee una base de datos extensa que contiene información detallada sobre diversas propiedades residenciales disponibles en el mercado. Se requiere realizar un análisis holístico de estos datos para identificar patrones, relaciones y segmentaciones relevantes que permitan mejorar la toma de decisiones en cuanto a la compra, venta y valoración de propiedades.
El reto principal consiste en realizar un análisis integral y multidimensional de la base de datos para obtener una comprensión del mercado inmobiliario urbano. Se requiere aplicar diversas técnicas de análisis de datos, incluyendo:
Análisis de Componentes Principales: Reducir la dimensionalidad del conjunto de datos y visualizar la estructura de las variables en componentes principales para identificar características clave que influyen en la variación de precios y oferta del mercado.
Análisis de Conglomerados: Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas de las ofertas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.
Análisis de Correspondencia: Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio), para identificar patrones de comportamiento de la oferta en mercado inmobiliario.
Visualización de resultados: Presentar gráficos, mapas y otros recursos visuales para comunicar los hallazgos de manera clara y efectiva a la dirección de la empresa.
En este subcapítulo se instalan los paquetes necesarios para el análisis y se carga la base de datos de las propiedades residenciales disponibles en el mercado, “vivienda” desde el paquete “paqueteMODELOS”.
La base de datos tienen 8322 registros y 13 variables, a continuación se presenta un resumen de las cada una de las variables.
# Cargar base de datos del paquete
data("vivienda")
#glimpse(vivienda)
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>
summary(vivienda)
## id zona piso estrato
## Min. : 1 Length:8322 Length:8322 Min. :3.000
## 1st Qu.:2080 Class :character Class :character 1st Qu.:4.000
## Median :4160 Mode :character Mode :character Median :5.000
## Mean :4160 Mean :4.634
## 3rd Qu.:6240 3rd Qu.:5.000
## Max. :8319 Max. :6.000
## NA's :3 NA's :3
## preciom areaconst parqueaderos banios
## Min. : 58.0 Min. : 30.0 Min. : 1.000 Min. : 0.000
## 1st Qu.: 220.0 1st Qu.: 80.0 1st Qu.: 1.000 1st Qu.: 2.000
## Median : 330.0 Median : 123.0 Median : 2.000 Median : 3.000
## Mean : 433.9 Mean : 174.9 Mean : 1.835 Mean : 3.111
## 3rd Qu.: 540.0 3rd Qu.: 229.0 3rd Qu.: 2.000 3rd Qu.: 4.000
## Max. :1999.0 Max. :1745.0 Max. :10.000 Max. :10.000
## NA's :2 NA's :3 NA's :1605 NA's :3
## habitaciones tipo barrio longitud
## Min. : 0.000 Length:8322 Length:8322 Min. :-76.59
## 1st Qu.: 3.000 Class :character Class :character 1st Qu.:-76.54
## Median : 3.000 Mode :character Mode :character Median :-76.53
## Mean : 3.605 Mean :-76.53
## 3rd Qu.: 4.000 3rd Qu.:-76.52
## Max. :10.000 Max. :-76.46
## NA's :3 NA's :3
## latitud
## Min. :3.333
## 1st Qu.:3.381
## Median :3.416
## Mean :3.418
## 3rd Qu.:3.452
## Max. :3.498
## NA's :3
Debido a que se observan datos faltantes, se procede a realizar limpieza de la base de datos y a realizar la imputación de los datos faltantes.
vivienda1 <- vivienda
vivienda1 <- vivienda1 %>% filter(!is.na(areaconst), areaconst>0, !is.na(preciom))
vivienda1 <- vivienda1 %>% mutate(
piso = factor(piso),
zona = factor(zona),
tipo = factor(tipo),
barrio = factor(barrio))
# Resumen
summary(vivienda1)
## id zona piso estrato
## Min. : 1 Zona Centro : 124 02 :1450 Min. :3.000
## 1st Qu.:2080 Zona Norte :1920 03 :1097 1st Qu.:4.000
## Median :4160 Zona Oeste :1198 01 : 860 Median :5.000
## Mean :4160 Zona Oriente: 351 04 : 607 Mean :4.634
## 3rd Qu.:6240 Zona Sur :4726 05 : 567 3rd Qu.:5.000
## Max. :8319 (Other):1103 Max. :6.000
## NA's :2635
## preciom areaconst parqueaderos banios
## Min. : 58.0 Min. : 30.0 Min. : 1.000 Min. : 0.000
## 1st Qu.: 220.0 1st Qu.: 80.0 1st Qu.: 1.000 1st Qu.: 2.000
## Median : 330.0 Median : 123.0 Median : 2.000 Median : 3.000
## Mean : 433.9 Mean : 174.9 Mean : 1.835 Mean : 3.111
## 3rd Qu.: 540.0 3rd Qu.: 229.0 3rd Qu.: 2.000 3rd Qu.: 4.000
## Max. :1999.0 Max. :1745.0 Max. :10.000 Max. :10.000
## NA's :1602
## habitaciones tipo barrio longitud
## Min. : 0.000 Apartamento:5100 valle del lili:1008 Min. :-76.59
## 1st Qu.: 3.000 Casa :3219 ciudad jardín : 516 1st Qu.:-76.54
## Median : 3.000 pance : 409 Median :-76.53
## Mean : 3.605 la flora : 366 Mean :-76.53
## 3rd Qu.: 4.000 santa teresita: 262 3rd Qu.:-76.52
## Max. :10.000 el caney : 208 Max. :-76.46
## (Other) :5550
## latitud
## Min. :3.333
## 1st Qu.:3.381
## Median :3.416
## Mean :3.418
## 3rd Qu.:3.452
## Max. :3.498
##
A continuación, se presenta el porcentaje (%) de datos faltantes en las variables “piso”, “parqueaderos”:
# Estimación del porcentaje de datos faltantes
na_summary <- sapply(vivienda1[, c("piso", "parqueaderos")], function(x) {
sum(is.na(x)) / length(x) * 100
})
print(na_summary)
## piso parqueaderos
## 31.67448 19.25712
Se procede a realizar la imputación de los datos por la moda de la variable piso y parqueaderos agrupada por zona y tipo de vivienda:
# Función para calcular moda
moda <- function(v) {
uniqv <- na.omit(unique(v))
uniqv[which.max(tabulate(match(v, uniqv)))]}
# Resultados de la moda de la variable piso y parqueaderos -
# agrupada por zona y tipo de vivienda
moda_zona_tipo <- vivienda1 %>%
group_by(zona, tipo) %>%
summarise(
moda_piso = moda(piso),
moda_parqueaderos = moda(parqueaderos),
.groups = 'drop'
)
print(moda_zona_tipo)
## # A tibble: 10 × 4
## zona tipo moda_piso moda_parqueaderos
## <fct> <fct> <fct> <dbl>
## 1 Zona Centro Apartamento 05 1
## 2 Zona Centro Casa 01 1
## 3 Zona Norte Apartamento 03 1
## 4 Zona Norte Casa 02 1
## 5 Zona Oeste Apartamento 03 2
## 6 Zona Oeste Casa 02 2
## 7 Zona Oriente Apartamento 01 1
## 8 Zona Oriente Casa 01 1
## 9 Zona Sur Apartamento 05 1
## 10 Zona Sur Casa 02 2
# Imputación por zona y tipo
vivienda1 <- vivienda1 %>%
group_by(zona, tipo) %>% # Agrupar por zona y tipo
mutate(
piso = ifelse(is.na(piso), moda(piso), piso),
parqueaderos = ifelse(is.na(parqueaderos), moda(parqueaderos), parqueaderos)
) %>%
ungroup()
summary(vivienda1 %>% select(piso,parqueaderos))
## piso parqueaderos
## Min. : 1.000 Min. : 1.000
## 1st Qu.: 2.000 1st Qu.: 1.000
## Median : 3.000 Median : 1.000
## Mean : 3.503 Mean : 1.712
## 3rd Qu.: 5.000 3rd Qu.: 2.000
## Max. :12.000 Max. :10.000
# Identificación de valores atipicos
variables_cuantitativas<-vivienda1 %>% select(piso,
estrato,
preciom,
areaconst,
parqueaderos,
banios,
habitaciones,
longitud,
latitud)
variables_cuantitativas_largo <- variables_cuantitativas %>%
pivot_longer(cols = everything(),
names_to = "variable",
values_to = "valor")
# Gráfico múltiple
p_multiple <- ggplot(variables_cuantitativas_largo, aes(x = variable, y = valor)) +
geom_boxplot(outlier.colour = "red",
outlier.size = 1.5,
fill = "lightblue",
alpha = 0.7) +
facet_wrap(~ variable, scales = "free", ncol = 3) +
labs(title = "Detección de Datos Atípicos por Variable",
x = "Variables",
y = "Valor") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5))
print(p_multiple)
# --- Identificación y eliminación de outliers usando IQR ---
# Función para filtrar valores atípicos según IQR
eliminar_outliers <- function(df, variable) {
Q1 <- quantile(df[[variable]], 0.25, na.rm = TRUE)
Q3 <- quantile(df[[variable]], 0.75, na.rm = TRUE)
IQR_value <- Q3 - Q1
df %>%
filter(df[[variable]] >= (Q1 - 1.5 * IQR_value) &
df[[variable]] <= (Q3 + 1.5 * IQR_value))
}
# Variables donde eliminaremos outliers
variables_a_filtrar <- c("areaconst", "preciom", "parqueaderos", "banios", "habitaciones")
# Copia del dataset original limpio
vivienda_sin_outliers <- vivienda1
# Filtrado progresivo por cada variable
for (var in variables_a_filtrar) {
vivienda_sin_outliers <- eliminar_outliers(vivienda_sin_outliers, var)
}
# Gráfico después de eliminar outliers
variables_cuantitativas_largo_sin <- vivienda_sin_outliers %>%
select(all_of(variables_a_filtrar)) %>%
pivot_longer(cols = everything(),
names_to = "variable",
values_to = "valor")
p_multiple_sin <- ggplot(variables_cuantitativas_largo_sin, aes(x = variable, y = valor)) +
geom_boxplot(outlier.colour = "red", outlier.size = 1.5,
fill = "lightgreen", alpha = 0.7) +
facet_wrap(~ variable, scales = "free", ncol = 3) +
labs(title = "Datos sin Outliers",
x = "Variables", y = "Valor") +
theme_minimal()
print(p_multiple_sin)
# Comparamos tamaño de la base
cat("Registros originales:", nrow(vivienda1), "\n")
## Registros originales: 8319
cat("Registros después de imputar outliers:", nrow(vivienda_sin_outliers), "\n")
## Registros después de imputar outliers: 6554
Solo se realiza la eliminación de outliers de las variables “areaconst”, “preciom”, “parqueaderos”, “banios”, “habitaciones”, para no sesgar las variables por casos extremos que representan propiedades muy atípicas. Se mantiene los outliers de las variables de longitud, estrato y piso.
# 3 - PCA sobre variables numéricas
# seleccionar variables numéricas de interés
num_vars <- vivienda_sin_outliers %>% select(piso,
estrato,
preciom,
areaconst,
parqueaderos,
banios,
habitaciones)
# estandarización
num_scaled <- scale(num_vars)
# PCA
res.pca <- prcomp(num_scaled, center = TRUE, scale. = FALSE)
summary(res.pca)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 1.8852 1.1728 0.8590 0.71246 0.61101 0.54492 0.39366
## Proportion of Variance 0.5077 0.1965 0.1054 0.07251 0.05333 0.04242 0.02214
## Cumulative Proportion 0.5077 0.7042 0.8096 0.88211 0.93544 0.97786 1.00000
# Scree plot
fviz_eig(res.pca, addlabels = TRUE)
De la grafica anterior puede inferir que la dimensión 1 explica 50,8% de la variabilidad de la base de datos y que entre la dimensión 1 y 2 se explica el 70,05% de la variabilidad.
# Biplot de variables
fviz_pca_var(res.pca, col.var = 'contrib', gradient.cols = c('#00AFBB','#E7B800','#FC4E07'), repel = TRUE)
El primer componente esta asociado principalmente a las variables “habitaciones”, “areaconst”, “banios”, “preciom”, “parqueaderos” y “estrato”, indicando que entre mejor sean las caracteristicas de la vivienda, en cuanto a tamaño (habitaciones, área construida, número de baños y número de parqueaderos) mayor será su precio y su clasificación en el estrato socioeconómico.
Por otro lado, la variable “piso” esta asociado al segundo componente, indicando que independiente de las caracteristicas de la vivienda.
# Individuos coloreados por estrato
# debemos asegurar un vector habillage con misma longitud
ind_hab <- vivienda_sin_outliers$estrato[complete.cases(num_vars)]
fviz_pca_ind(res.pca, geom.ind = 'point', pointsize = 1, habillage = ind_hab, addEllipses = FALSE, repel = TRUE)
Respecto a la gráfica de componentes principales por estratos se interpreta que las viviendas de estratos socioeconómicos más altos estan ubicadas más hacia la izquierda del primer componente y los estratos más bajos estan ubicados hacia la derecha, confirmando la asocaición de las variables que describen las características de la vivienda en el primer componente.
# Selección variables numéricas
num_vars <- vivienda_sin_outliers %>%
select(preciom, areaconst, estrato, banios, habitaciones, parqueaderos) %>%
drop_na()
# Escalar variables
num_scaled <- scale(num_vars)
#Elección DE k con Silhouette
fviz_nbclust(num_scaled, kmeans, method = "silhouette") +
labs(title = "Índice de Silhouette para K-means")
Para elegir el número de conglomerados, el indice de Silhouette que la mejor agrupación corresponde a K=2 conglomerados. Sin embargo, a continuación, se visualiza el Dendograma y se eligen en su lugar 4 grupos.
# Dendograma
dist_eucl <- dist(num_scaled, method = "euclidean")
hc <- hclust(dist_eucl, method = "complete")
plot(hc,
main = "Dendrograma - Distancia Euclidiana",
xlab = "Observaciones",
sub = "",
cex = 0.6)
# Rectángulos para k clusters (puedes ajustar k)
rect.hclust(hc, k = 4, border = 2:5)
Posteriormente se utiliza el algoritmo K-MEANS para agrupar en los 4 cluster y se utiliza componentes principales.
# K-MEANS (ejemplo con k = 4)
set.seed(123)
km <- kmeans(num_scaled, centers = 4, nstart = 50)
# Visualización de clusters en PCA
fviz_cluster(list(data = num_scaled, cluster = km$cluster),
geom = "point",
ellipse.type = "convex",
main = "Clusters K-means (k = 4)")
# Perfil de cada cluster
cluster_profile <- num_vars %>%
mutate(cluster_km = factor(km$cluster)) %>%
group_by(cluster_km) %>%
summarise(across(everything(), median, na.rm = TRUE), .groups = "drop")
rows_used <- which(complete.cases(num_vars))
vivienda_sin_outliers$cluster_km <- NA
vivienda_sin_outliers$cluster_km[rows_used] <- factor(km$cluster)
print(cluster_profile)
## # A tibble: 4 × 7
## cluster_km preciom areaconst estrato banios habitaciones parqueaderos
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 600 172 6 4 3 2
## 2 2 160 66.4 4 2 3 1
## 3 3 300 98 5 2 3 1
## 4 4 371 220 4 4 4 2
El grupo 1, corresponde las viviendas de con altas caracteristicas con mayor costo.
El grupo 2, agrupa las viviendas más pequeñas y de menor costo.
El grupo 3, representa las viviendas de un estrato alto, precio intermedio y poca área construida.
El grupo 4, esta conformado por viviendas con caracteristicas y precio intermedio.
Se podría inferir que la mayoria de viviendas se encuentran en el grupo 1 y 4.
NOTA: No se utiliza la variable barrio, tiene demasiadas categorias.
# Preparar variables categóricas
cat_vars <- vivienda_sin_outliers %>%
mutate(
# Categorizar estrato en grupos más manejables
Estrato = case_when(
estrato %in% c(1,2) ~ "E_Bajo",
estrato %in% c(3,4) ~ "E_Medio",
estrato %in% c(5,6) ~ "E_Alto"
),
# Categorizar precio en rangos
Precio = case_when(
preciom <= 300 ~ "P_Bajo",
preciom <= 600 ~ "P_Medio",
preciom <= 1000 ~ "P_Alto",
TRUE ~ "P_Muy Alto"
),
# Categorizar área construida
Area = case_when(
areaconst <= 80 ~ "V_Pequeña",
areaconst <= 120 ~ "V_Mediana",
areaconst <= 180 ~ "V_Grande",
TRUE ~ "V_Muy_Grande"
)
) %>%
select(tipo, zona, Estrato, Precio, Area) %>%
mutate_all(as.factor) %>%
drop_na()
# Realizar MCA
res.mca <- FactoMineR::MCA(cat_vars, graph = FALSE)
# Información del MCA
print("Varianza explicada por dimensión:")
## [1] "Varianza explicada por dimensión:"
print(res.mca$eig)
## eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.47025366 21.375167 21.37517
## dim 2 0.31148470 14.158395 35.53356
## dim 3 0.24686253 11.221024 46.75459
## dim 4 0.21552789 9.796722 56.55131
## dim 5 0.20146662 9.157573 65.70888
## dim 6 0.19964782 9.074901 74.78378
## dim 7 0.18527078 8.421399 83.20518
## dim 8 0.14766382 6.711992 89.91717
## dim 9 0.10938797 4.972180 94.88935
## dim 10 0.07042389 3.201086 98.09044
## dim 11 0.04201032 1.909560 100.00000
fviz_screeplot(res.mca, addlabels = TRUE, ylim = c(0, 80))+ggtitle("")+ ylab( "Porcentaje de varianza explicado") + xlab("Ejes")
De la grafica anterior se infiere que el primer componente solo representa el 21,4% de la varianza de los datos, se considera que representa muy poco la variabilidad de los datos.
# Individuos por zona
p_ind_zona <- fviz_mca_ind(res.mca,
habillage = cat_vars$zona,
addEllipses = TRUE,
ellipse.level = 0.68,
geom = "point",
pointsize = 0.8,
repel = FALSE) +
labs(title = "Distribución de Viviendas por Zona",
subtitle = "Análisis de Correspondencia Múltiple") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 12))
print(p_ind_zona)
Se interpreta que la mayoria de las viviendas se encuentra ubicada en la zona norte y en la zona sur de la ciudad.
# Individuos por tipo de vivienda
p_ind_tipo <- fviz_mca_ind(res.mca,
habillage = cat_vars$tipo,
addEllipses = TRUE,
ellipse.level = 0.68,
geom = "point",
pointsize = 0.8,
palette = "Set2") +
labs(title = "Distribución por Tipo de Vivienda",
subtitle = "Casas vs Apartamentos en el espacio MCA") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 12))
print(p_ind_tipo)
De la grafica se podria interpretar que el numero de casas es mayor que el numero de apartamentos.
# Individuos por PRECIO de vivienda
p_ind_precio <- fviz_mca_ind(res.mca,
habillage = cat_vars$Precio,
addEllipses = TRUE,
ellipse.level = 0.68,
geom = "point",
pointsize = 0.8,
palette = "Set2") +
labs(title = "Distribución por Precio de las Vivienda",
subtitle = "Precio en el espacio MCA") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 12))
print(p_ind_precio)
A partir de una superposición de las 3 imagenes se podria interpretar que hacia la derecha se encuentran las viviendas de mayor precio, que en su mayoria corresponde a las casas y se encuentran ubicadas en la zona oeste en mayor proporción, y en menor proporción en la zona norte y sur.
A continuación, en el siguiente mapa se pueden ubicar las diferentes viviendas con sus caracteristicas principales (Tipo, Zona, Área Construida, Precio)
geo <- vivienda_sin_outliers %>%
filter(!is.na(longitud), !is.na(latitud), !is.na(cluster_km))
if (nrow(geo) > 0) {
# Crear objeto sf
sf_pts <- st_as_sf(geo, coords = c('longitud','latitud'), crs = 4326)
# Paleta de colores para clusters K-means
pal <- colorFactor(palette = 'Set1', domain = sf_pts$cluster_km)
# Mapa
leaflet(sf_pts) %>%
addTiles() %>%
addCircleMarkers(
radius = 4,
color = ~pal(cluster_km),
stroke = FALSE,
fillOpacity = 0.8,
popup = ~paste0(
'<b>', tipo, '</b><br/>Zona: ', zona,
'<br/>Estrato: ', estrato,
'<br/>Área: ', round(areaconst), ' m²',
'<br/>Precio: ', scales::comma(preciom), 'M'
)
) %>%
addLegend(
"bottomright",
pal = pal,
values = ~cluster_km,
title = "Clusters K-means",
opacity = 1
)
} else {
cat('No hay coordenadas válidas para mapas.\n')
}
print(cluster_profile)
## # A tibble: 4 × 7
## cluster_km preciom areaconst estrato banios habitaciones parqueaderos
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 600 172 6 4 3 2
## 2 2 160 66.4 4 2 3 1
## 3 3 300 98 5 2 3 1
## 4 4 371 220 4 4 4 2
El precio y el estrato socioeconómico de la vivienda está determinado en mayor medida por las características de la vivienda representadas en el área construida, la cantidad de habitaciones, cantidad de baños y cantidad de parqueaderos.
La mayoría de las viviendas se encuentran en el grupo 1 y 4, que corresponden a viviendas de excelentes características con un costo representativo y por otro lado a viviendas de características intermedias. Por lo tanto, podría inferirse que una oportunidad de mercado es dirigir la oferta inmobiliaria hacia los estratos altos y medios de la ciudad.
La oferta inmobiliaria puede plantearse con casas hacia un grupo selecto de clientes clase alta y con apartamentos hacia clientes clase media.
La base de datos caracteriza las viviendas de la ciudad en su mayoría hacia la zona norte, sur y oeste, lo que representa la zona este como potencial para explorar nuevas opciones de mercado.
Aunque se realizó la eliminación de outliers, el ejercicio puede realizarse sin eliminarlos para evaluar un sector exclusivo del mercado, donde posiblemente se encuentren viviendas de alto costo con características especiales.