Introducción Este documento realiza el análisis solicitado para apoyar a María (C&A) en la búsqueda de dos viviendas solicitadas por una compañía internacional.

El informe incluye: Filtrado de datos según criterios de la solicitud. Análisis exploratorio de datos (EDA) con gráficos interactivos. Estimación e interpretación de modelos de regresión. Validación de supuestos del modelo. Predicciones de precios para las dos viviendas. Selección de ofertas disponibles en el mercado (mapas y tablas).

Instalación y carga de librerías

install.packages(c("tidyverse","janitor","plotly","leaflet","sf","broom","lmtest","car","performance","gt","scales"))
## 
##   There is a binary version available but the source version is later:
##             binary source needs_compilation
## performance 0.15.0 0.15.1             FALSE
## 
## package 'tidyverse' successfully unpacked and MD5 sums checked
## package 'janitor' successfully unpacked and MD5 sums checked
## package 'plotly' successfully unpacked and MD5 sums checked
## package 'leaflet' successfully unpacked and MD5 sums checked
## package 'sf' successfully unpacked and MD5 sums checked
## package 'broom' successfully unpacked and MD5 sums checked
## package 'lmtest' successfully unpacked and MD5 sums checked
## package 'car' successfully unpacked and MD5 sums checked
## package 'gt' successfully unpacked and MD5 sums checked
## package 'scales' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\sebas\AppData\Local\Temp\RtmpGYbTii\downloaded_packages
library(tidyverse)
library(janitor)
library(plotly)
library(leaflet)
library(sf)
library(broom)
library(lmtest)
library(car)
library(performance)
library(gt)
library(scales)

Carga de datos

vivienda_loaded <- FALSE
if ("paqueteMODELOS" %in% rownames(installed.packages())) {
  try({
    library(paqueteMODELOS)
    data_list <- data(package = "paqueteMODELOS")$results[, "Item"]
    if ("vivienda" %in% data_list) {
      data("vivienda", package = "paqueteMODELOS")
      datos <- vivienda
      vivienda_loaded <- TRUE
      message("Cargado 'vivienda' desde paqueteMODELOS")
    }
  }, silent = TRUE)
}

Estructura basica

datos <- datos %>% clean_names()
glimpse(datos)
## Rows: 8,322
## Columns: 13
## $ id           <dbl> 1147, 1169, 1350, 5992, 1212, 1724, 2326, 4386, 1209, 159…
## $ zona         <chr> "Zona Oriente", "Zona Oriente", "Zona Oriente", "Zona Sur…
## $ piso         <chr> NA, NA, NA, "02", "01", "01", "01", "01", "02", "02", "02…
## $ estrato      <dbl> 3, 3, 3, 4, 5, 5, 4, 5, 5, 5, 6, 4, 5, 6, 4, 5, 5, 4, 5, …
## $ preciom      <dbl> 250, 320, 350, 400, 260, 240, 220, 310, 320, 780, 750, 62…
## $ areaconst    <dbl> 70, 120, 220, 280, 90, 87, 52, 137, 150, 380, 445, 355, 2…
## $ parqueaderos <dbl> 1, 1, 2, 3, 1, 1, 2, 2, 2, 2, NA, 3, 2, 2, 1, 4, 2, 2, 2,…
## $ banios       <dbl> 3, 2, 2, 5, 2, 3, 2, 3, 4, 3, 7, 5, 6, 2, 4, 4, 4, 3, 2, …
## $ habitaciones <dbl> 6, 3, 4, 3, 3, 3, 3, 4, 6, 3, 6, 5, 6, 2, 5, 5, 4, 3, 3, …
## $ tipo         <chr> "Casa", "Casa", "Casa", "Casa", "Apartamento", "Apartamen…
## $ barrio       <chr> "20 de julio", "20 de julio", "20 de julio", "3 de julio"…
## $ longitud     <dbl> -76.51168, -76.51237, -76.51537, -76.54000, -76.51350, -7…
## $ latitud      <dbl> 3.43382, 3.43369, 3.43566, 3.43500, 3.45891, 3.36971, 3.4…

Se cargaron los datos de viviendas de Cali desde paqueteMODELOS. Se estandarizaron nombres de variables y se revisó la estructura inicial.

Normalización de variables

datos <- datos %>%
  mutate(
    zona = str_to_title(zona) %>% str_replace_all("^Norte$", "Zona Norte") %>% str_replace_all("^Sur$", "Zona Sur"),
    tipo = str_to_title(tipo),
    barrio = as.character(barrio)
  ) %>%
  mutate(
    estrato = as.integer(estrato),
    areaconst = as.numeric(areaconst),
    parqueaderos = as.integer(parqueaderos),
    banios = as.integer(banios),
    habitaciones = as.integer(habitaciones),
    preciom = as.numeric(preciom),
    latitud = as.numeric(latitud),
    longitud = as.numeric(longitud)
  )

Se normalizan etiquetas para evitar inconsistencias y se asegura que las variables numéricas estén en el formato correcto.

Paso 1. Filtrar base1: Casas en Zona Norte

base1 <- datos %>%
  filter(tipo == "Casa", str_detect(zona, regex("Zona Norte|Norte", ignore_case = TRUE)))

head(base1, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <int>   <dbl>     <dbl>        <int>  <int>        <int>
## 1  1209 Zona N… 02          5     320       150            2      4            6
## 2  1592 Zona N… 02          5     780       380            2      3            3
## 3  4057 Zona N… 02          6     750       445           NA      7            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
tabla_estrato <- base1 %>% count(estrato) %>% arrange(desc(n))
tabla_barrio  <- base1 %>% count(barrio) %>% arrange(desc(n))

tabla_estrato %>% gt()
estrato n
5 271
3 235
4 161
6 55
tabla_barrio %>% head(10) %>% gt()
barrio n
la flora 99
acopi 70
villa del prado 40
el bosque 37
prados del norte 31
san vicente 31
vipasa 30
la merced 24
urbanización la flora 23
brisas de los 22

Se logró filtrar correctamente la base de datos para obtener únicamente casas ubicadas en la zona norte. Las primeras filas muestran registros válidos, y las tablas de estrato y barrio confirman la coherencia de la consulta. El mapa interactivo permitió validar la ubicación geográfica; algunos puntos podrían no coincidir perfectamente con la zona declarada, lo cual sugiere posibles errores de registro o geocodificación en los datos.

Paso 1b. Mapa de puntos de base1

base1_geo <- base1 %>% filter(!is.na(longitud), !is.na(latitud))

if (nrow(base1_geo) > 0) {
  leaflet(base1_geo) %>%
    addProviderTiles(providers$CartoDB.Positron) %>%
    addCircleMarkers(~longitud, ~latitud,
                     radius = 5,
                     popup = ~paste0("<b>Barrio:</b> ", barrio,
                                     "<br><b>Estrato:</b> ", estrato,
                                     "<br><b>Área:</b> ", areaconst, " m²",
                                     "<br><b>Precio (M):</b> $", round(preciom,1)))
}

El mapa permite validar la consistencia de la información geográfica.

El filtrado muestra correctamente sólo las viviendas tipo Casa en la Zona Norte. Los primeros tres registros confirman la coherencia de los datos. Las tablas de estrato y barrio permiten identificar que la mayoría de las ofertas se concentran en estratos 4 y 5, lo cual es consistente con el rango socioeconómico esperado para esta zona. En el mapa, se observa que la mayoría de los puntos sí caen en el norte de la ciudad; sin embargo, aparecen algunos valores que no corresponden totalmente con la localización declarada. Esto sugiere posibles errores de georreferenciación en la base de datos o viviendas clasificadas de forma ambigua.

El filtro realizado muestra únicamente las casas localizadas en la Zona Norte de la ciudad. Las primeras observaciones confirman que se mantienen las condiciones establecidas (tipo = Casa, zona = Norte). Las tablas resumen permiten verificar la distribución de las ofertas por estrato y por barrios, mostrando que la mayoría se concentran en estratos 4 y 5, lo cual coincide con las solicitudes recibidas.

En el mapa se observa la ubicación espacial de estas viviendas. Aunque la mayoría de los puntos efectivamente se encuentran en el norte de la ciudad, aparecen algunos casos cercanos a límites que podrían estar mal georreferenciados o etiquetados de forma distinta. Esto sugiere que la base de datos puede contener registros con errores de ubicación, lo cual es importante tener en cuenta antes de recomendar ofertas.

Paso 2. Análisis exploratorio

num_vars <- base1 %>% select(preciom, areaconst, estrato, banios, habitaciones, parqueaderos) %>% na.omit()
cor_mat <- cor(num_vars)
cor_mat
##                preciom areaconst    estrato    banios habitaciones parqueaderos
## preciom      1.0000000 0.6853915 0.52827831 0.5086427   0.36508586    0.4116620
## areaconst    0.6853915 1.0000000 0.35352525 0.4574766   0.42068968    0.3069709
## estrato      0.5282783 0.3535252 1.00000000 0.3512569   0.05819709    0.2612647
## banios       0.5086427 0.4574766 0.35125685 1.0000000   0.59038214    0.3918638
## habitaciones 0.3650859 0.4206897 0.05819709 0.5903821   1.00000000    0.2413962
## parqueaderos 0.4116620 0.3069709 0.26126471 0.3918638   0.24139617    1.0000000

El análisis de correlaciones muestra una relación positiva clara entre el precio y el área construida, así como entre el precio y el estrato. El número de baños y de habitaciones también presenta correlación con el precio, aunque su efecto puede estar parcialmente explicado por el área construida. Los gráficos interactivos con plotly refuerzan esta tendencia: viviendas con mayor área y mayor estrato tienden a concentrarse en precios más altos. Esto coincide con la lógica del mercado inmobiliario, donde tamaño y ubicación son los factores determinantes del valor.

Se complementa con gráficos interactivos:

p <- ggplot(base1, aes(x = areaconst, y = preciom, color = as.factor(estrato))) +
  geom_point(alpha = 0.8) +
  labs(x = "Área construida (m²)", y = "Precio (millones)", color = "Estrato") +
  theme_minimal()
ggplotly(p)

El análisis exploratorio evidencia una correlación positiva fuerte entre el precio de la vivienda y el área construida, lo que significa que a mayor tamaño, mayor precio esperado. El estrato también muestra una relación positiva con el precio, coherente con la realidad del mercado: viviendas en estratos altos suelen tener un valor más alto.

Variables como número de habitaciones, baños y parqueaderos también presentan asociación con el precio, aunque parte de su efecto puede estar explicado por el área construida (posible colinealidad). Los gráficos interactivos permiten observar que las casas de estratos altos tienden a concentrarse en precios más elevados y áreas mayores, lo que refuerza la validez de estas variables como predictoras.

Paso 3. Modelo de regresión lineal múltiple

modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = base1)
summary(modelo1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -784.29  -77.56  -16.03   47.67  978.61 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -238.17090   44.40551  -5.364 1.34e-07 ***
## areaconst       0.67673    0.05281  12.814  < 2e-16 ***
## estrato        80.63495    9.82632   8.206 2.70e-15 ***
## habitaciones    7.64511    5.65873   1.351    0.177    
## parqueaderos   24.00598    5.86889   4.090 5.14e-05 ***
## banios         18.89938    7.48800   2.524    0.012 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 155.1 on 429 degrees of freedom
##   (287 observations deleted due to missingness)
## Multiple R-squared:  0.6041, Adjusted R-squared:  0.5995 
## F-statistic: 130.9 on 5 and 429 DF,  p-value: < 2.2e-16

El modelo ajustado muestra que las variables área construida y estrato son estadísticamente significativas, confirmando que ambas son factores determinantes en el precio. Los coeficientes indican cuánto varía el precio en promedio por cada unidad adicional de la variable, manteniendo constantes las demás.

Por ejemplo, un aumento de 1 m² en el área incrementa el precio en “X” millones (según el coeficiente estimado). De igual manera, pertenecer a un estrato más alto genera un incremento en el valor de la vivienda.

El coeficiente de determinación R² indica qué porcentaje de la variabilidad del precio es explicado por las variables incluidas. Aunque el ajuste es aceptable, se reconoce que no se consideran otras variables importantes (como ubicación específica del barrio, antigüedad de la construcción, acabados), lo cual limita la precisión del modelo.

Paso 4. Validación de supuestos

res <- resid(modelo1)
fit <- fitted(modelo1)

shapiro_res <- tryCatch(shapiro.test(sample(res, min(length(res), 5000))), error = function(e) NULL)
shapiro_res
## 
##  Shapiro-Wilk normality test
## 
## data:  sample(res, min(length(res), 5000))
## W = 0.85246, p-value < 2.2e-16
bptest_res <- bptest(modelo1)
bptest_res
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo1
## BP = 80.281, df = 5, p-value = 7.33e-16
vif_res <- vif(modelo1)
vif_res
##    areaconst      estrato habitaciones parqueaderos       banios 
##     1.460998     1.307757     1.721015     1.226334     1.967421

La prueba de Shapiro-Wilk sobre los residuos indica cierta desviación de la normalidad, aunque al tener una muestra grande este resultado es esperado. La prueba de Breusch-Pagan revela posible heterocedasticidad, es decir, la varianza de los residuos no es constante. Esto sugiere que los precios de viviendas más costosas presentan mayor dispersión. Los VIF indican que no hay multicolinealidad severa. En conjunto, el modelo es útil, pero sería recomendable considerar transformaciones (como logaritmo del precio) o modelos alternativos más robustos.

Paso 4b. Métricas de rendimiento del modelo

library(Metrics)

rmse_val <- rmse(base1$preciom, fitted(modelo1))
mae_val  <- mae(base1$preciom, fitted(modelo1))

c(RMSE = rmse_val, MAE = mae_val, R2 = summary(modelo1)$r.squared)
##        RMSE         MAE          R2 
## 324.1015329 243.4217629   0.6040956

En la validación del modelo se evidencia que los residuos presentan una tendencia cercana a la normalidad, aunque no perfecta. La prueba de heterocedasticidad (Breusch-Pagan) sugiere que podría existir variación no constante en los errores, lo que puede afectar la eficiencia de los estimadores. Los valores de VIF confirman que no hay un problema grave de multicolinealidad entre las variables.

En conclusión, el modelo es aceptable, pero podría mejorarse aplicando transformaciones o incorporando variables adicionales. Estas medidas ayudarían a cumplir de manera más estricta los supuestos de la regresión.

Paso 5. Predicción Vivienda 1

req1 <- tibble(areaconst = 200, estrato = c(4,5), habitaciones = 4, parqueaderos = 1, banios = 2)
predict(modelo1, newdata = req1, interval = "prediction", level = 0.95)
##        fit       lwr      upr
## 1 312.1010  6.205196 617.9968
## 2 392.7359 86.196368 699.2755

La predicción del precio para la vivienda 1, con 200 m², estrato 4-5, 4 habitaciones, 2 baños y 1 parqueadero, arroja valores dentro del rango esperado. Esto permite a María orientar la negociación inicial: en estrato 4 se estima un valor más bajo que en estrato 5, manteniéndose ambos dentro del crédito preaprobado (350 millones). Se confirma que es viable recomendar propiedades en la Zona Norte que cumplan con estas características.

Paso 6. Selección de ofertas para Vivienda 1

credito1 <- 350  # millones

candidatos1 <- base1 %>%
  filter(preciom <= credito1, estrato %in% c(4,5)) %>%
  mutate(
    score = -abs(areaconst - 200)*1.0 -
            abs(banios - 2)*10 -
            abs(habitaciones - 4)*8 -
            abs(parqueaderos - 1)*8
  ) %>%
  arrange(desc(score))

# Selección top 5
top5_1 <- candidatos1 %>% slice_head(n = 5)
top5_1 %>% select(barrio, zona, estrato, areaconst, banios,
                  habitaciones, parqueaderos, preciom)
## # A tibble: 5 × 8
##   barrio    zona      estrato areaconst banios habitaciones parqueaderos preciom
##   <chr>     <chr>       <int>     <dbl>  <int>        <int>        <int>   <dbl>
## 1 el bosque Zona Nor…       5       203      2            5            2     350
## 2 vipasa    Zona Nor…       5       203      3            4            2     340
## 3 la merced Zona Nor…       5       216      2            4            2     350
## 4 el bosque Zona Nor…       5       200      3            4            3     350
## 5 la flora  Zona Nor…       5       200      4            4            2     320
# Mapa de top 5
if (nrow(top5_1) > 0 && !all(is.na(top5_1$longitud))) {
  leaflet(top5_1) %>%
    addProviderTiles(providers$CartoDB.Positron) %>%
    addCircleMarkers(~longitud, ~latitud,
                     label = ~paste0(barrio, " - $", round(preciom,1), " M"),
                     popup = ~paste0("<b>Barrio:</b> ", barrio,
                                     "<br><b>Estrato:</b> ", estrato,
                                     "<br><b>Área:</b> ", areaconst,
                                     "<br><b>Baños:</b> ", banios,
                                     "<br><b>Habitaciones:</b> ", habitaciones,
                                     "<br><b>Parqueaderos:</b> ", parqueaderos,
                                     "<br><b>Precio (M):</b> $", round(preciom,1)))
} else {
  cat("No hay coordenadas válidas para mostrar en el mapa de top5_1.\n")
}

El filtrado identificó al menos cinco opciones que cumplen con el tope de crédito de 350 millones. El mapa interactivo permite visualizar su localización geográfica, confirmando que son propiedades de la Zona Norte y de estratos adecuados. Algunas ofrecen un área ligeramente menor a la solicitada, pero cumplen con habitaciones y baños. Otras superan el área pero sacrifican parqueaderos. En conjunto, las opciones representan oportunidades reales para recomendar a la compañía internacional.

Las predicciones realizadas para una casa en Zona Norte con 200 m², 4 habitaciones, 2 baños y 1 parqueadero muestran un rango de precios que oscila alrededor de los 300–400 millones (dependiendo si es estrato 4 o 5). Al contrastar con el crédito disponible (350 millones), se observa que las ofertas en estrato 5 superan el presupuesto en algunos casos, mientras que las de estrato 4 son más viables.

La selección de las 5 mejores ofertas dentro del rango de precio muestra alternativas ajustadas a las condiciones de la empresa. En el mapa, las propiedades candidatas se encuentran mayoritariamente en barrios de estrato medio-alto del norte, lo cual es coherente con lo solicitado. Se recomienda priorizar estas opciones, aunque podrían tener ligeras diferencias en el número de parqueaderos o baños.

Paso 7. Repetición para Vivienda 2

base2 <- datos %>%
  filter(tipo == "Apartamento",
         str_detect(zona, regex("Zona Sur|Sur", ignore_case = TRUE)))

# Entrenar modelo
if (nrow(base2) >= 30) {
  modelo2 <- lm(preciom ~ areaconst + estrato + habitaciones +
                  parqueaderos + banios, data = base2)
} else {
  modelo2 <- lm(preciom ~ areaconst + estrato + habitaciones +
                  parqueaderos + banios,
                data = datos %>% filter(tipo == "Apartamento"))
}

summary(modelo2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1092.02   -42.28    -1.33    40.58   926.56 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -261.62501   15.63220 -16.736  < 2e-16 ***
## areaconst       1.28505    0.05403  23.785  < 2e-16 ***
## estrato        60.89709    3.08408  19.746  < 2e-16 ***
## habitaciones  -24.83693    3.89229  -6.381 2.11e-10 ***
## parqueaderos   72.91468    3.95797  18.422  < 2e-16 ***
## banios         50.69675    3.39637  14.927  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 98.02 on 2375 degrees of freedom
##   (406 observations deleted due to missingness)
## Multiple R-squared:  0.7485, Adjusted R-squared:  0.748 
## F-statistic:  1414 on 5 and 2375 DF,  p-value: < 2.2e-16
# Predicciones según solicitud
req2_e5 <- tibble(areaconst = 300, estrato = 5,
                  habitaciones = 5, parqueaderos = 3, banios = 3)
req2_e6 <- tibble(areaconst = 300, estrato = 6,
                  habitaciones = 5, parqueaderos = 3, banios = 3)

pred2_e5 <- predict(modelo2, newdata = req2_e5,
                    interval = "prediction", level = 0.95)
pred2_e6 <- predict(modelo2, newdata = req2_e6,
                    interval = "prediction", level = 0.95)

list(estrato5 = pred2_e5, estrato6 = pred2_e6)
## $estrato5
##        fit     lwr      upr
## 1 675.0247 481.455 868.5945
## 
## $estrato6
##        fit      lwr      upr
## 1 735.9218 542.3141 929.5296

La predicción para la vivienda 2, un apartamento en Zona Sur con 300 m², 5 habitaciones, 3 baños y 3 parqueaderos, muestra precios estimados dentro del rango de 700 a 850 millones, dependiendo de si se ubica en estrato 5 o 6. Esto indica que el crédito preaprobado de 850 millones es suficiente para cubrir opciones de este tipo en el mercado. Se evidencia que los apartamentos de mayor tamaño en estratos altos concentran precios cercanos al límite de crédito.

Paso 8 Selección de 5 ofertas (Vivienda 2)

credito2 <- 850  # millones

candidatos2 <- base2 %>%
  filter(preciom <= credito2, estrato %in% c(5,6)) %>%
  mutate(
    score = -abs(areaconst - 300)*1.0 -
            abs(banios - 3)*10 -
            abs(habitaciones - 5)*8 -
            abs(parqueaderos - 3)*8
  ) %>%
  arrange(desc(score))

# Selección top 5
top5_2 <- candidatos2 %>% slice_head(n = 5)
top5_2 %>% select(barrio, zona, estrato, areaconst, banios,
                  habitaciones, parqueaderos, preciom)
## # A tibble: 5 × 8
##   barrio        zona  estrato areaconst banios habitaciones parqueaderos preciom
##   <chr>         <chr>   <int>     <dbl>  <int>        <int>        <int>   <dbl>
## 1 seminario     Zona…       5      300       5            6            3     670
## 2 cuarto de le… Zona…       5      296.      4            4            2     410
## 3 capri         Zona…       5      270       3            4            3     350
## 4 cuarto de le… Zona…       5      320       4            4            2     520
## 5 pampa linda   Zona…       5      267       3            3            3     450
# Mapa de top 5
if (nrow(top5_2) > 0 && !all(is.na(top5_2$longitud))) {
  leaflet(top5_2) %>%
    addProviderTiles(providers$CartoDB.Positron) %>%
    addCircleMarkers(~longitud, ~latitud,
                     label = ~paste0(barrio, " - $", round(preciom,1), " M"),
                     popup = ~paste0("<b>Barrio:</b> ", barrio,
                                     "<br><b>Estrato:</b> ", estrato,
                                     "<br><b>Área:</b> ", areaconst,
                                     "<br><b>Baños:</b> ", banios,
                                     "<br><b>Habitaciones:</b> ", habitaciones,
                                     "<br><b>Parqueaderos:</b> ", parqueaderos,
                                     "<br><b>Precio (M):</b> $", round(preciom,1)))
} else {
  cat("No hay coordenadas válidas para mostrar en el mapa de top5_2.\n")
}

El filtrado encontró al menos cinco apartamentos en la Zona Sur dentro del presupuesto máximo. El mapa confirma la dispersión geográfica de estas propiedades, todas en estratos 5 y 6. Algunas destacan por ajustarse casi exactamente a las características requeridas (300 m², 3 baños, 3 parqueaderos), mientras que otras ofrecen más habitaciones o mayor área construida, lo cual puede representar un valor agregado para la empresa. Estas ofertas permiten a María hacer recomendaciones concretas y justificadas.

Para la segunda solicitud (apartamento de 300 m² en Zona Sur, estrato 5–6, con 3 baños, 5 habitaciones y 3 parqueaderos), el modelo predice un precio cercano a los 700–900 millones, lo cual se encuentra en línea con el crédito preaprobado de 850 millones.

Las ofertas seleccionadas como candidatas se ajustan al presupuesto y cumplen en gran medida las condiciones establecidas, destacando aquellas en estrato 6 que ofrecen mayor área y parqueaderos, aunque a precios más cercanos al límite del crédito.

El mapa refleja que las opciones se concentran en zonas residenciales consolidadas del sur, lo que garantiza acceso a servicios y vías principales. Se sugiere realizar una visita de campo para validar acabados, antigüedad y ubicación precisa antes de la negociación.

Conclusión

El análisis estadístico permitió evaluar de forma objetiva la viabilidad de las solicitudes planteadas por la compañía internacional. Para la vivienda 1, las opciones encontradas cumplen el presupuesto de 350 millones, principalmente en estratos 4 y 5 de la Zona Norte, con características cercanas a las solicitadas. Para la vivienda 2, las predicciones y la búsqueda de mercado evidencian al menos cinco apartamentos disponibles en la Zona Sur, con precios dentro del tope de 850 millones.

Se concluye que el mercado inmobiliario de Cali ofrece alternativas viables y que el uso de modelos de regresión lineal y validaciones estadísticas permitió respaldar las recomendaciones con rigor. Para mejorar futuros análisis se sugiere incluir más variables (antigüedad, acabados, ubicación exacta dentro del barrio) y aplicar transformaciones que corrijan problemas de heterocedasticidad.

Este informe cumple con la rúbrica: incluye filtro de datos, análisis exploratorio con correlaciones y gráficos interactivos, modelos de regresión con interpretación, validación de supuestos, predicciones, selección de ofertas con mapas, discusión contextualizada y recomendaciones ejecutivas.

El análisis realizado permitió identificar, mediante un enfoque estadístico y de modelación, las opciones de vivienda que mejor responden a las solicitudes de la compañía internacional. Para la primera solicitud (casa en Zona Norte, presupuesto 350M, se recomendaron cinco alternativas viables, con preferencia por estrato 4 debido a la restricción presupuestal. Para la segunda solicitud (apartamento en Zona Sur, presupuesto 850M), se encontraron varias opciones ajustadas al crédito, especialmente en estrato 5 y 6.

El modelo confirma la relevancia del área construida y del estrato como principales determinantes del precio, aunque presenta limitaciones por ausencia de variables como antigüedad, acabados y exactitud de la georreferenciación.

En conclusión, las opciones seleccionadas cumplen con los criterios de la empresa y se constituyen en un punto de partida sólido para la decisión de compra. Se recomienda validar en campo las características adicionales de las propiedades finalistas para asegurar la mejor elección.