Contexto

María, una agente de bienes raíces con amplia experiencia en Cali y Bogotá, fundó su propia empresa inmobiliaria C&A (Casas y Apartamentos), donde actualmente trabajan ocho agentes. En el contexto actual, las ventas de vivienda en Cali han disminuido debido a factores económicos, aunque se espera una pronta recuperación del sector.

Una compañía internacional ha solicitado a María asesoría para la adquisición de dos viviendas destinadas a ubicar a empleados que llegarán a la ciudad. Cada vivienda tiene condiciones específicas relacionadas con el tipo, área construida, número de parqueaderos, baños, habitaciones, estrato, zona y un crédito preaprobado disponible.

Las características principales de ambas opciones se resumen en la Tabla I.

Tabla I. Caracteristicas de los tipos de Viviendas
Característica Vivienda1 Vivienda2
Tipo Casa Apartamento
área construida 200 300
parqueaderos 1 3
baños 2 3
habitaciones 4 5
estrato 4 o 5 5 o 6
zona Norte Sur
credito pre-aprobado 350 millones 850 millones

Con base en esta información, María requiere la elaboración de un informe ejecutivo sustentado en técnicas de modelación estadística, particularmente en el uso de modelos de regresión múltiple, que permita analizar las características de cada caso y formular recomendaciones informadas para la toma de decisión.

Datos

Los datos son tomados de OLX mediante procedimiento webscraping y contenidos en paqueteMOD. La información corresponde a viviendas urbanas ofertadas en Colombia (en los últimos 3 meses), específicamente en la ciudad de Cali, lo cual delimita el alcance geográfico del análisis y contextualiza los resultados dentro del mercado inmobiliario local.

El conjunto de datos está compuesto por 8.322 observaciones y 13 variables. En la Tabla II se presenta la descripción detallada de cada una de las variables incluidas en el estudio:

df$barrio <- tolower(df$barrio)  #minusculas
df$barrio <- trimws(df$barrio)  #espacios vacios
df$barrio <- stri_trans_general(df$barrio, "Latin-ASCII") #acentos

df$barrio[df$barrio %in% c("agua blanca", "aguablanca")] <- "agua blanca"
df$barrio[df$barrio %in% c("alf√(C)rez real", "alferez real")] <- "alferez real"
df$barrio[df$barrio %in% c("arboleda", "arboledas")] <- "arboleda"
df$barrio[df$barrio %in% c("base a√(C)rea")] <- "basea aerea"
df$barrio[df$barrio %in% c("cali bella", "calibella")] <- "cali bella"
df$barrio[df$barrio %in% c("cali canto", "calicanto")] <- "cali canto"
df$barrio[df$barrio %in% c("ciudad mel√(C)ndez")] <- "ciudad melendez"
df$barrio[df$barrio %in% c("ciudadela paso ancho")] <- "ciudadela pasoancho"
df$barrio[df$barrio %in% c("el caney")] <- "caney"
df$barrio[df$barrio %in% c("el ingenio 3")] <- "el ingenio iii"
df$barrio[df$barrio %in% c("el tr√(C)bol")] <- "el trebol"
df$barrio[df$barrio %in% c("ingenio")] <- "el ingenio"
df$barrio[df$barrio %in% c("ingenio i")] <- "el ingenio i"
df$barrio[df$barrio %in% c("ingenio ii")] <- "el ingenio ii"
df$barrio[df$barrio %in% c("juanamb√∫")] <- "juanambu"
df$barrio[df$barrio %in% c("la alborada")] <- "alborada"
df$barrio[df$barrio %in% c("la ceibas")] <- "ceibas"
df$barrio[df$barrio %in% c("laflora","norte la flora","urbanizacion la flora")] <- "la flora"
df$barrio[df$barrio %in% c("las am√(C)ricas")] <- "las americas"
df$barrio[df$barrio %in% c("las ceibas")] <- "ceibas"
df$barrio[df$barrio %in% c("los cambulos")] <- "cambulos"
df$barrio[df$barrio %in% c("los alcazares")] <- "alcazares"
df$barrio[df$barrio %in% c("mel√(C)ndez")] <- "melendez"
df$barrio[df$barrio %in% c("pampa linda")] <- "pampalinda"
df$barrio[df$barrio %in% c("ponce")] <- "pance"
df$barrio[df$barrio %in% c("rep√∫blica de israel")] <- "republica de israel"
df$barrio[df$barrio %in% c("sector aguacatal")] <- "aguacatal"
df$barrio[df$barrio %in% c("siete de agosto")] <- "barrio 7de agosto"
df$barrio[df$barrio %in% c("tequendema","urbanizacion tequendama")] <- "tequendama"
df$barrio[df$barrio %in% c("urbanizacion barranquilla")] <- "barranquilla"
df$barrio[df$barrio %in% c("urbanizacion boyaca")] <- "boyaca"
df$barrio[df$barrio %in% c("urbanizacion la merced")] <- "la merced"
df$barrio[df$barrio %in% c("urbanizacion pacara")] <- "pacara"
df$barrio[df$barrio %in% c("urbanizacion lili","valle de lili")] <- "valle del lili"
Tabla II. Variables y descripción de las variables
Variable Descripcion Clasificacion
Id Identificador de la vivienda Cualitativa nominal
zona Zona donde se encuentra la vivienda Cualitativa nominal (categórica)
piso Cantidad de pisos de la vivienda Cuantitativa discreta
estrato Estrato donde se encuentra ubicada la vivienda Cualitativa ordinal (categórica)
preciom Precio de la vivienda Cuantitativa continua
areaconst Área construida de la vivienda Cuantitativa continua
parqueaderos Número de parqueaderos de la vivienda Cuantitativa discreta
banios Número de baños de la vivienda Cuantitativa discreta
habitaciones Número de habitaciones de la vivienda Cuantitativa discreta
tipo Tipo de vivienda: Casa, Apto, etc. Cualitativa nominal (categórica)
barrio Barrio donde se ubica la vivienda Cualitativa nominal (categórica)
longitud Longitud de la vivienda: Este (+) / Oeste (-) Cuantitativa continua
latitud Latitud de la vivienda: Norte (+) /Sur (-) Cuantitativa continua

Con base en este conjunto de datos, se cuenta con una base empírica que permite analizar el comportamiento del mercado inmobiliario en la ciudad de Cali y evaluar cómo diferentes características estructurales y de localización influyen en el precio de las viviendas ofertadas. A partir de esta información, se procede a analizar el primer caso planteado en el estudio, correspondiente a la Vivienda Tipo 1, contrastando sus características con los patrones observados en la base de datos.

Analisis de Vivienda Tipo 1

Seleccion de la base

Avanzaremos filrando la base considerando tipo de vivienda “casa”, que se encuentren en la zona norte:

df1 <- subset(df, zona == "Zona Norte" & tipo == "Casa")
# Ver primeros 3 registros

head(df1, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 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>

Realizamos validacion de la cantidad de registros al realizar el filtro:

table(df1$tipo, df1$zona)
##       
##        Zona Norte
##   Casa        722

Obtenemos un total de 722 registros que cumplen con las condiciones establecidas: viviendas de tipo “casa” ubicadas en la Zona Norte de la ciudad. A partir de este subconjunto, procedemos a construir un mapa georreferenciado que permita validar la localización espacial de estas propiedades dentro de Cali y verificar la coherencia entre la zona reportada y sus coordenadas reales.

map <- leaflet(df1) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = 5,
    color = "blue",
    fillOpacity = 0.7,
    popup = ~paste(
      "Precio: ", preciom, "<br>",
      "Habitaciones: ", habitaciones, "<br>",
      "Barrio: ", barrio, "<br>",
      "Baños: ", banios
    )
  )

map

A partir del mapa, se evidencia que algunos inmuebles se encuentran ubicados hacia el sur de la ciudad, pese a estar clasificados como parte de la Zona Norte. Esta inconsistencia sugiere errores de reclasificación en la base original de OLX. Para garantizar la coherencia espacial del análisis, se aplicara un nuevo filtrado utilizando la variable de latitud, considerando únicamente las propiedades con valores superiores a 3.43. Este criterio permite acotar el conjunto de datos a las viviendas realmente situadas en el sector norte de Cali.

df_norte <- subset(df, 
              zona == "Zona Norte" & 
                tipo == "Casa" & 
                latitud >= 3.43)

table(df_norte$tipo, df_norte$zona)
##       
##        Zona Norte
##   Casa        615
map1 <- leaflet(df_norte) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = 5,
    color = "#B254A5",
    fillOpacity = 0.7,
    popup = ~paste(
      "Precio: ", preciom, "<br>",
      "Habitaciones: ", habitaciones, "<br>",
      "Barrio: ", barrio, "<br>",
      "Baños: ", banios
    )
  )

map1

Con la aplicación del nuevo filtrado geográfico, el conjunto de datos queda conformado por 615 viviendas que cumplen simultáneamente con las condiciones de tipo (casa), zona reportada (Norte) y ubicación real según su latitud.

Análisis Exploratorio-Correlación

Con la base de datos previamente filtrada, se procede a realizar un análisis exploratorio, el cual incluye la depuración y tratamiento de los datos, así como la evaluación de las relaciones entre variables mediante análisis de correlación.

Tratamiento y Depuración de la base

1. Validacion de datos faltantes
# Conteo de NA por columna
colSums(is.na(df_norte))
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0          287            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##          215            0            0            0            0            0 
##      latitud 
##            0

Evidenciamos gran presencia de datos faltantes en la base para las variables de piso (46.6%) y parqueaderos (34.9%), por lo que avanzaremos a excluir las variables de la base de datos ya que desconocemos la naturaleza de esta ausencia y puede generar desviaciones en los siguientes pasos.

df_norte1 <- df_norte %>%
  dplyr::select(-piso, -parqueaderos)
2.Validacion de datos repetidos
# Número de duplicados por ID
duplicados_id <- df_norte1%>% 
  group_by(id) %>% 
  filter(n() > 1)

duplicados_id
## # A tibble: 0 × 11
## # Groups:   id [0]
## # ℹ 11 variables: id <dbl>, zona <chr>, estrato <dbl>, preciom <dbl>,
## #   areaconst <dbl>, banios <dbl>, habitaciones <dbl>, tipo <chr>,
## #   barrio <chr>, longitud <dbl>, latitud <dbl>

No se evidencian datos repetidos en la base.

3. Validacion de datos atípicos
  • Variables númericas:
#variables numericas:
vars_numericas <- c("preciom", "areaconst", 
                    "banios", "habitaciones","longitud","latitud")

# Resumen con skimr solo para esas variables
df_resumen <- skim(df_norte1[vars_numericas])

# Filtrar solo numéricas y seleccionar columnas de interés
tabla_resumen <- df_resumen %>% 
  dplyr::filter(skim_type == "numeric") %>% 
  dplyr::select(
    skim_variable, numeric.mean, numeric.sd,
    numeric.p0, numeric.p25, numeric.p50,
    numeric.p75, numeric.p100
  )

# Renombrar columnas para presentación
colnames(tabla_resumen) <- c(
  "Variable", "Media", "Desv.Std", "Mínimo",
  "Q1", "Mediana", "Q3", "Máximo"
)

# Mostrar tabla bonita
tabla_resumen %>% 
  kable(format = "html", digits = 2,
        caption = "**Tabla III.Resumen estadístico de las variables numéricas**") %>% 
  kable_styling(full_width = FALSE,
                bootstrap_options = c("striped", "hover", "condensed"))
Tabla III.Resumen estadístico de las variables numéricas
Variable Media Desv.Std Mínimo Q1 Mediana Q3 Máximo
preciom 430.35 260.57 89.00 245.00 380.00 550.00 1940.00
areaconst 262.31 167.75 30.00 140.00 240.00 336.50 1440.00
banios 3.51 1.51 0.00 2.00 3.00 4.00 10.00
habitaciones 4.58 1.82 0.00 3.00 4.00 5.00 10.00
longitud -76.51 0.02 -76.59 -76.53 -76.52 -76.50 -76.48
latitud 3.47 0.01 3.43 3.46 3.47 3.48 3.50
# Pasar a formato largo solo esas variables
vars_long <- df_norte1 %>% 
  dplyr::select(all_of(vars_numericas)) %>% 
  pivot_longer(cols = everything(),
               names_to = "variable",
               values_to = "valor")

# Boxplots por variable
ggplot(vars_long, aes(x = variable, y = valor)) +
  geom_boxplot(alpha = 0.7, fill = "#4C9AFF", color = "black") +
  facet_wrap(~ variable, scales = "free") +
  theme_minimal(base_size = 12) +
  labs(
    title = "Distribución de variables numéricas",
    x = "Variable",
    y = "Valor"
  ) +
  theme(
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank()
  )
**Figura 1.1**: Boxplot. Identificación de valores atípicos

Figura 1.1: Boxplot. Identificación de valores atípicos

A partir del análisis descriptivo (Tabla III) y los boxplots (Figura 1.1) no se observan datos atípicos que resulten incoherentes con el mercado inmobiliario. Los valores extremos presentes en precio y área reflejan la diversidad de viviendas según estrato, tamaño y ubicación dentro de la Zona Norte. De igual forma, las variables de localización (latitud y longitud) se encuentran dentro del rango esperado para esta zona, sin evidenciar coordenadas fuera de los límites geográficos de la ciudad. Lo importante es que no se identifican valores absurdos o incompatibles con el tipo de inmuebles analizados.

La única inconsistencia relevante aparece en los valores mínimos de habitaciones y baños, donde se registran valores iguales a cero. Estos casos no son posibles en una vivienda, por lo que deberán ser tratados antes de avanzar con la etapa de modelación.

  • Variables cualitativas:

En el caso de la variable barrio, se identificaron algunas inconsistencias relacionadas con errores de escritura y asignaciones incorrectas. Por ello, se realizó un proceso de depuración para homogenizar los nombres y asegurar su correcta clasificación. De igual manera, se verificó la tipificación de la variable zona, confirmando que los registros correspondientes a la Zona Norte se encuentran correctamente homologados después del filtrado geográfico por latitud.

Para la variable estrato, se emplea un boxplot que permite identificar posibles valores atípicos o categorías mal tipificadas, con el fin de garantizar la coherencia antes de incorporarla en los modelos posteriores.

ggplot(df_norte1, aes(x = as.factor(estrato))) +
  geom_bar(fill = "#4DBBD5") +
  labs(title = "Distribución de Estratos",
       x = "Estrato",
       y = "Frecuencia") +
  theme_minimal()
**Figura 1.2**: Distribucion del Estrato. Zona Norte/Casas

Figura 1.2: Distribucion del Estrato. Zona Norte/Casas

De acuerdo con la Figura 1.2, la variable estrato no presenta desviaciones en su distribución, ya que sus valores se ubican dentro del rango permitido (1 a 6). Adicionalmente, se observa que las viviendas que cumplen con las características filtradas se concentran principalmente en el estrato 5, seguido del estrato 3, lo que indica una mayor presencia de inmuebles en estos niveles socioeconómicos dentro del conjunto de datos analizado.

3.1 Tratamiento de valores atípicos

Dado que los registros con 0 habitaciones y 0 baños representan valores atípicos o inconsistencias en la información, se procede a evaluar cuántos casos presentan estas condiciones en cada una de las variables. Este análisis permite determinar la magnitud del problema y definir las acciones apropiadas para su tratamiento en la etapa de limpieza de datos.

cat("Cantidad de registros con 0 habitaciones: ",
    sum(df_norte1$habitaciones == 0, na.rm = TRUE), "\n")
## Cantidad de registros con 0 habitaciones:  11
cat("Cantidad de registros con 0 baños: ",
    sum(df_norte1$banios == 0, na.rm = TRUE), "\n")
## Cantidad de registros con 0 baños:  7

Los registros con 0 habitaciones representan el 1.7% y los de 0 baños el 1.1%, se considera que su proporción es muy baja. Por ello, se procede a imputar estos valores utilizando la mediana, calculada de manera agrupada por área construida, bajo el supuesto de que estas variables guardan relación con el número de habitaciones y baños.

# 1) Calcular medianas por área construida

medianas <- df_norte1 %>%
  group_by(areaconst) %>%                  # ✅ ahora solo agrupas por areaconst
  summarise(
    med_hab = median(habitaciones[habitaciones > 0], na.rm = TRUE),
    med_ban = median(banios[banios > 0], na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(
    # Si la mediana queda NA (grupo sin valores válidos), usar mediana global
    med_hab = if_else(
      is.na(med_hab),
      median(df_norte1$habitaciones[df_norte1$habitaciones > 0], na.rm = TRUE),
      med_hab
    ),
    med_ban = if_else(
      is.na(med_ban),
      median(df_norte1$banios[df_norte1$banios > 0], na.rm = TRUE),
      med_ban
    )
  )

# 2) Imputar ceros usando esas medianas (con redondeo)
df_norte2 <- df_norte1 %>%
  left_join(medianas, by = c("areaconst")) %>%   # ✅ join solo por areaconst
  mutate(
    habitaciones = if_else(
      habitaciones == 0,
      as.integer(round(med_hab)),                # ✅ redondeo explícito a entero
      habitaciones
    ),
    banios = if_else(
      banios == 0,
      as.integer(round(med_ban)),                # ✅ redondeo explícito a entero
      banios
    )
  ) %>%
  dplyr::select(-med_hab, -med_ban)  
# Función para calcular resumen
resumen_vars <- function(data, var){
  data %>%
    summarise(
      Media = mean({{var}}, na.rm = TRUE),
      Mediana = median({{var}}, na.rm = TRUE),
      Min = min({{var}}, na.rm = TRUE),
      Max = max({{var}}, na.rm = TRUE),
      Desv = sd({{var}}, na.rm = TRUE),
      IQR = IQR({{var}}, na.rm = TRUE)
    )
}

# Crear los resúmenes antes y después
hab_before <- resumen_vars(df_norte1, habitaciones)
hab_after  <- resumen_vars(df_norte2, habitaciones)

ban_before <- resumen_vars(df_norte1, banios)
ban_after  <- resumen_vars(df_norte2, banios)

# Combinar en una tabla
tabla_resumen <- rbind(
  cbind(Variable = "Habitaciones", Estado = "Antes", hab_before),
  cbind(Variable = "Habitaciones", Estado = "Después", hab_after),
  cbind(Variable = "Baños", Estado = "Antes", ban_before),
  cbind(Variable = "Baños", Estado = "Después", ban_after)
)

# Mostrar tabla bonita
tabla_resumen %>%
  kable(digits = 2, caption = "**Tabla Iv. Resumen estadístico antes y después de la imputación**") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed"))
Tabla Iv. Resumen estadístico antes y después de la imputación
Variable Estado Media Mediana Min Max Desv IQR
Habitaciones Antes 4.58 4 0 10 1.82 2
Habitaciones Después 4.66 4 1 10 1.71 2
Baños Antes 3.51 3 0 10 1.51 2
Baños Después 3.56 3 1 10 1.47 2

La Tabla Iv muestra que, tras la imputación, las estadísticas de habitaciones y baños se mantienen prácticamente iguales a las originales. La media cambia solo ligeramente (habitaciones: 4.58→4.66; baños: 3.51→3.56) y la mediana permanece igual para ambas variables. El valor mínimo pasa de 0 a 1, corrigiendo registros inválidos sin alterar la variabilidad de las variables, ya que la desviación estándar (Habitaciones de 1.82 a 1.71 y en Baños de 1.51 a 1.47) no presentan grandes alteraciones y el IQR se mantiene estable.

En síntesis, la imputación permitió corregir valores imposibles sin alterar de manera significativa la distribución de las variables, preservando la coherencia y estabilidad del conjunto de datos. Como resultado de este proceso, se obtuvo una base depurada de viviendas tipo “casa” ubicadas en la zona norte de la ciudad, compuesta por 615 registros y 8 variables: precio, área construida, número de habitaciones, número de baños, estrato, barrio, longitud y latitud.

A partir de esta base tratada, se calcularon los estadísticos descriptivos de las variables numéricas, los cuales se presentan en la Tabla V.

#variables numericas:
vars_numericas <- c("preciom", "areaconst", 
                    "banios", "habitaciones","longitud","latitud")

# Resumen con skimr solo para esas variables
df_resumen_viv1 <- skim(df_norte2[vars_numericas])

# Filtrar solo numéricas y seleccionar columnas de interés
tabla_resumen_viv1 <- df_resumen_viv1 %>% 
  dplyr::filter(skim_type == "numeric") %>% 
  dplyr::select(
    skim_variable, numeric.mean, numeric.sd,
    numeric.p0, numeric.p25, numeric.p50,
    numeric.p75, numeric.p100
  )

# Renombrar columnas para presentación
colnames(tabla_resumen_viv1) <- c(
  "Variable", "Media", "Desv.Std", "Mínimo",
  "Q1", "Mediana", "Q3", "Máximo"
)

# Mostrar tabla bonita
tabla_resumen_viv1 %>% 
  kable(format = "html", digits = 2,
        caption = "**Tabla V.Resumen estadístico de las variables numéricas. Vivienda Tipo 1**") %>% 
  kable_styling(full_width = FALSE,
                bootstrap_options = c("striped", "hover", "condensed"))
Tabla V.Resumen estadístico de las variables numéricas. Vivienda Tipo 1
Variable Media Desv.Std Mínimo Q1 Mediana Q3 Máximo
preciom 430.35 260.57 89.00 245.00 380.00 550.00 1940.00
areaconst 262.31 167.75 30.00 140.00 240.00 336.50 1440.00
banios 3.56 1.47 1.00 2.00 3.00 4.00 10.00
habitaciones 4.66 1.71 1.00 3.00 4.00 5.00 10.00
longitud -76.51 0.02 -76.59 -76.53 -76.52 -76.50 -76.48
latitud 3.47 0.01 3.43 3.46 3.47 3.48 3.50

La Tabla V presenta el resumen estadístico de las variables numéricas para las viviendas tipo “casa” ubicadas en la zona norte de Cali. El precio promedio es de aproximadamente 430 millones, con una desviación estándar de 260 millones, lo que evidencia una alta variabilidad en los valores de los inmuebles. En cuanto a las características físicas, las viviendas presentan un área construida promedio de 262 m², con alrededor de 3.6 baños y 4.7 habitaciones, lo que sugiere inmuebles de tamaño familiar. Finalmente, la baja dispersión en latitud y longitud confirma que las propiedades se concentran efectivamente en el sector norte de la ciudad.

Correlación

Avanzaremos a realizar análisis de correlación entre la variable respuesta (precio de la casa) en función del área construida, estrato, numero de baños, numero de habitaciones y zona donde se ubica la vivienda.

Correlacion entre Precio vs Nro de baños, habitaciones y area construida

Antes de aplicar el análisis de correlación, se evaluará el comportamiento de la variable precio, con el fin de identificar si su distribución se aproxima a la normalidad.

ggplot(df_norte2, aes(preciom)) +
  geom_histogram(aes(y = ..density..), bins = 30, fill = "lightblue") +
  stat_function(fun = dnorm,
                args = list(mean = mean(df_norte2$preciom), sd = sd(df_norte2$preciom)),
                color = "red", size = 1) +
  labs(title = "Distribución del precio")
**Figura 1.3**: Distribución Variable Precio

Figura 1.3: Distribución Variable Precio

shapiro.test(df_norte2$preciom)
## 
##  Shapiro-Wilk normality test
## 
## data:  df_norte2$preciom
## W = 0.8543, p-value < 2.2e-16

La distribución del precio (Figura 1.3) muestra una marcada asimetría hacia la derecha, con una alta concentración de viviendas entre 200 y 600 millones y una cola prolongada asociada a inmuebles de mayor valor. Este comportamiento se confirma con la prueba de Shapiro–Wilk (W = 0.8543, p < 2.2e-16), la cual rechaza la normalidad de la variable. Dado que el precio no sigue una distribución normal, el coeficiente de Pearson se utilizará únicamente con fines exploratorios y se complementará con el coeficiente de Spearman, que no exige normalidad y resulta más robusto ante este tipo de asimetrías.

df_corr <- df_norte2 %>%
  dplyr::select(precio = preciom, areaconst, banios, habitaciones)

ggpairs(
  df_corr,
  lower = list(continuous = wrap("smooth", alpha = 0.3)),
  diag = list(continuous = "densityDiag"),
  upper = list(continuous = wrap("cor", size = 4))
)
**Figura 1.4**:Matriz de Dispersión- Correlación Pearson. Casas en la Zona Norte

Figura 1.4:Matriz de Dispersión- Correlación Pearson. Casas en la Zona Norte

ggpairs(
  df_corr,
  lower = list(continuous = wrap("smooth", alpha = 0.3)),
  diag = list(continuous = "densityDiag"),
  upper = list(continuous = wrap("cor", method = "spearman", size = 4))
)
**Figura 1.5**:Matriz de Dispersión- Correlación Spearman. Casas en la Zona Norte

Figura 1.5:Matriz de Dispersión- Correlación Spearman. Casas en la Zona Norte

El análisis de correlación mediante los coeficientes de Pearson y Spearman (Figuras 1.4 y 1.5) evidencia que el área construida es la variable con mayor asociación con el precio, presentando correlaciones altas y positivas en ambos métodos. Esto confirma que el tamaño del inmueble es el principal determinante del valor de las viviendas en la Zona Norte.

El número de baños también muestra una correlación moderada-alta con el precio, lo que indica que una mayor dotación interna tiende a incrementar el valor del inmueble. Por su parte, el número de habitaciones presenta la relación más débil, aunque sigue siendo significativa, con una asociación positiva y consistente.

Los resultados obtenidos con ambos coeficientes mantienen el mismo orden de relevancia (área > baños > habitaciones), lo cual refuerza la estabilidad del análisis incluso cuando la variable precio no cumple normalidad. En conjunto, estas evidencias respaldan la inclusión de estas variables en el modelo de regresión múltiple.

Correlación entre Precio y Estrato

Para este caso, validaremos si existe homogeneidad en las varianzas para justificar el uso de la Prueba Anova (utilizada para comparación de medias entre grupos), utilizando el Test Levene:

leveneTest(preciom ~ as.factor(estrato), data = df_norte2)
## Levene's Test for Homogeneity of Variance (center = median)
##        Df F value    Pr(>F)    
## group   3  11.563 2.219e-07 ***
##       611                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

La prueba de Levene arrojó un estadístico F = 11.563 con un p-value = 2.219e−07, evidenciando que p < 0.05. Esto implica el rechazo de la hipótesis nula de homogeneidad de varianzas, por lo que las dispersiones del precio no son iguales entre los distintos estratos. En consecuencia, no es adecuado aplicar un ANOVA, y la prueba indicada para evaluar diferencias entre grupos es Kruskal–Wallis, dado que no requiere normalidad ni igualdad de varianzas.

kruskal.test(preciom ~ estrato, data = df_norte2)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  preciom by estrato
## Kruskal-Wallis chi-squared = 310.35, df = 3, p-value < 2.2e-16

La prueba de Kruskal–Wallis evidenció diferencias significativas en los precios entre los distintos estratos (χ² = 310.35, p < 2.2e−16), indicando que el nivel socioeconómico al que pertenece la vivienda influye de manera importante en su valor. Esta tendencia se refleja claramente en el boxplot (Figura 1.6), donde se observa un incremento progresivo del precio medio conforme aumenta el estrato, acompañado de una mayor dispersión en los niveles superiores. En conjunto, estos resultados confirman que el estrato es un factor relevante en la variación del precio de las viviendas en la Zona Norte.

ggplot(df_norte2, aes(x = as.factor(estrato), y = preciom)) +
  geom_boxplot(fill = "#4DBBD5") +
  labs(title = "Estrato y Precio.Casas en el Norte",
       x = "Estrato",
       y = "Precio (millones)") +
  theme_minimal()
**Figura 1.6**:Boxplot Estrato y Precio.Casas en el Norte

Figura 1.6:Boxplot Estrato y Precio.Casas en el Norte

Correlación entre Precio y Longitud-Latitud

Para ello utilizaremos la correlacion de Spearman:

cor.test(df_norte2$preciom, df_norte2$latitud, method = "spearman")
## 
##  Spearman's rank correlation rho
## 
## data:  df_norte2$preciom and df_norte2$latitud
## S = 43923193, p-value = 0.0009474
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##        rho 
## -0.1329766
cor.test(df_norte2$preciom, df_norte2$longitud, method = "spearman")
## 
##  Spearman's rank correlation rho
## 
## data:  df_norte2$preciom and df_norte2$longitud
## S = 64957389, p-value < 2.2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##        rho 
## -0.6755431

El análisis de Spearman mostró que la correlación entre el precio y la latitud, aunque estadísticamente significativa (ρ = –0.13; p = 0.0009), es de magnitud muy débil. Esto indica que, pese a existir una tendencia consistente, la variación norte–sur dentro de la zona analizada no tiene un efecto relevante sobre el valor de las viviendas. En contraste, la longitud presentó una asociación negativa moderada-alta y altamente significativa (ρ = –0.68; p < 2.2e−16), evidenciando un patrón geográfico mucho más marcado: las viviendas ubicadas hacia el occidente tienden a presentar precios superiores. Este resultado confirma que solo la longitud, y no la latitud, aporta información sustancial para explicar la variación del precio.

plot_ly(df_norte2, x = ~latitud, y = ~preciom, type = "scatter",
        mode = "markers", marker = list(opacity = 0.4)) %>%
  add_lines(x = ~latitud,
            y = fitted(loess(preciom ~ latitud, data = df_norte2)),
            line = list(color = "blue", width = 3)) %>%
  layout(
    title = "Tendencia del precio según \n la latitud (LOESS)",
    xaxis = list(title = "Latitud"),
    yaxis = list(title = "Precio (millones)")
  )
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...

Figura 1.7:Curva LOESS. Tendencia del precio segun latitud

plot_ly(df_norte2, x = ~longitud, y = ~preciom, type = "scatter",
        mode = "markers", marker = list(opacity = 0.4)) %>%
  add_lines(x = ~longitud,
            y = fitted(loess(preciom ~ longitud, data = df_norte2)),
            line = list(color = "blue", width = 3)) %>%
  layout(
    title = "Tendencia del precio según \n la longitud (LOESS)",
    xaxis = list(title = "Longitud"),
    yaxis = list(title = "Precio (millones)")
  )
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...

Figura 1.8:Curva LOESS. Tendencia del precio segun longitud

plot_ly(
  data = df_norte2,
  x = ~longitud,
  y = ~latitud,
  type = "scatter",
  mode = "markers",
  marker = list(
    size = 7,
    color = ~preciom,
    colorscale = "Viridis",
    showscale = TRUE
  )
) %>%
  layout(
    title = "Mapa de precios por ubicación",
    xaxis = list(title = "Longitud"),
    yaxis = list(title = "Latitud")
  )

Figura 1.9:Mapa de precios por ubicacion

Los gráficos de tendencia permiten reforzar la interpretación obtenida a partir del coeficiente de Spearman. En el caso de la latitud (Figura 1.7), la curva LOESS muestra fluctuaciones suaves sin una dirección clara, lo que confirma que la variación norte–sur dentro de la zona analizada no se asocia de manera relevante con el precio de las viviendas. Por el contrario, la tendencia respecto a la longitud (Figura 1.8) evidencia una disminución consistente del precio a medida que las viviendas se ubican hacia valores de longitud más altos (sectores más orientales), reflejando un patrón espacial similar al reportado por la correlación negativa moderada-alta. Finalmente, el mapa de precios por ubicación (Figura 1.9) muestra una concentración visible de valores altos hacia el occidente de la zona norte, reforzando que el eje longitudinal sí ejerce una influencia considerable en la valorización inmobiliaria. En conjunto, estos gráficos confirman que la longitud, y no la latitud, constituye un factor espacial relevante en la explicación del precio.

Estimación del Modelo lineal Multiple

Para estimar el mejor modelo de regresión se aplicara un procedimiento de selección paso a paso (Stepwise), utilizando como variables candidatas aquellas que mostraron mayor capacidad explicativa en el análisis de correlación: área construida, estrato (que sera transformada a factor), número de habitaciones, número de baños y longitud. Se excluyó la latitud debido a que no presentó una relación lineal o monótona lo suficientemente clara con el precio de las viviendas en la zona norte, por lo que no aportaría información relevante al modelo.

# Crear versión categórica del estrato
df_norte2$estrato_f <- factor(df_norte2$estrato,
                              levels = sort(unique(df_norte2$estrato)))

# Modelo nulo: solo intercepto
modelo_nulo <- lm(preciom ~ 1, data = df_norte2)

# Modelo completo: todas las variables candidatas
modelo_completo <- lm(preciom ~ areaconst + estrato_f + habitaciones +
                                    banios + longitud,
                      data = df_norte2)

# Stepwise hacia adelante (forward)
modelo_step_forward <- step(
  object = modelo_nulo,
  scope  = list(lower = modelo_nulo, upper = modelo_completo),
  direction = "forward",
  trace = TRUE
)
## Start:  AIC=6843.33
## preciom ~ 1
## 
##                Df Sum of Sq      RSS    AIC
## + areaconst     1  22749904 18938922 6360.1
## + longitud      1  15095348 26593478 6568.9
## + estrato_f     3  14742730 26946096 6581.0
## + banios        1  13579375 28109450 6602.9
## + habitaciones  1   7533530 34155295 6722.8
## <none>                      41688826 6843.3
## 
## Step:  AIC=6360.09
## preciom ~ areaconst
## 
##                Df Sum of Sq      RSS    AIC
## + estrato_f     3   3382892 15556030 6245.1
## + longitud      1   2773628 16165294 6264.7
## + banios        1   1965510 16973411 6294.7
## + habitaciones  1    327121 18611800 6351.4
## <none>                      18938922 6360.1
## 
## Step:  AIC=6245.08
## preciom ~ areaconst + estrato_f
## 
##                Df Sum of Sq      RSS    AIC
## + banios        1    999228 14556802 6206.2
## + habitaciones  1    639894 14916136 6221.2
## + longitud      1    600867 14955163 6222.9
## <none>                      15556030 6245.1
## 
## Step:  AIC=6206.25
## preciom ~ areaconst + estrato_f + banios
## 
##                Df Sum of Sq      RSS    AIC
## + longitud      1    496559 14060244 6186.9
## + habitaciones  1     87252 14469550 6204.5
## <none>                      14556802 6206.2
## 
## Step:  AIC=6186.9
## preciom ~ areaconst + estrato_f + banios + longitud
## 
##                Df Sum of Sq      RSS    AIC
## + habitaciones  1     95200 13965044 6184.7
## <none>                      14060244 6186.9
## 
## Step:  AIC=6184.72
## preciom ~ areaconst + estrato_f + banios + longitud + habitaciones

El procedimiento de selección paso a paso (Stepwise) permite identificar de manera objetiva el conjunto de variables con mayor capacidad explicativa sobre el precio de las viviendas. En cada iteración, el algoritmo seleccionó la variable que generaba la mayor reducción del criterio AIC, mostrando una disminución progresiva desde 6843 hasta 6187. Esta tendencia confirma que cada variable incluida aportó información relevante para mejorar el ajuste del modelo. El proceso incorporó gradualmente el área construida, el estrato, el número de baños, la longitud y, finalmente, el número de habitaciones, conformando un modelo que integra tanto factores estructurales como espaciales, en coherencia con la lógica del mercado inmobiliario. El modelo resultante se expresa de la siguiente forma:

summary(modelo_step_forward)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato_f + banios + longitud + 
##     habitaciones, data = df_norte2)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -865.66  -70.94  -12.14   45.09 1043.60 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -2.003e+05  4.277e+04  -4.683 3.49e-06 ***
## areaconst     7.137e-01  4.906e-02  14.547  < 2e-16 ***
## estrato_f4    4.403e+01  1.979e+01   2.225   0.0265 *  
## estrato_f5    8.966e+01  1.988e+01   4.511 7.75e-06 ***
## estrato_f6    2.138e+02  3.358e+01   6.366 3.83e-10 ***
## banios        2.480e+01  6.102e+00   4.065 5.45e-05 ***
## longitud     -2.618e+03  5.591e+02  -4.683 3.49e-06 ***
## habitaciones  1.000e+01  4.917e+00   2.034   0.0424 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 151.7 on 607 degrees of freedom
## Multiple R-squared:  0.665,  Adjusted R-squared:  0.6612 
## F-statistic: 172.1 on 7 and 607 DF,  p-value: < 2.2e-16

\[ \widehat{\text{Precio}} = -200300 + 0.7137\,\text{ÁreaConstruida} + 24.80\,\text{Baños} - 2618\,\text{Longitud} + 10\,\text{Habitaciones} \\[6pt] \quad +\,44.03\,I(\text{Estrato}=4) +\,89.66\,I(\text{Estrato}=5) +\,213.80\,I(\text{Estrato}=6) \tag{1} \]

El modelo de regresión estimado incorpora las variables área construida, estrato (como variable categórica), número de baños, número de habitaciones y longitud. Los resultados obtenidos evidencian que todos los coeficientes son estadísticamente significativos (p < 0.05), lo que confirma que cada predictor aporta información relevante para explicar la variabilidad del precio de las viviendas en la Zona Norte de Cali.

En primer lugar, el área construida se mantiene como el determinante principal del precio (β = 0.71), indicando que por cada metro cuadrado adicional, el valor esperado de la vivienda aumenta aproximadamente 0.71 millones de pesos. Este resultado es coherente con la lógica del mercado inmobiliario, donde el tamaño es uno de los atributos más valorados.

La incorporación del estrato como variable categórica permite capturar diferencias estructurales entre los niveles socioeconómicos. Tomando como referencia el estrato 3, se observa que las viviendas de estrato 4 presentan, en promedio, un incremento de 44 millones de pesos; las de estrato 5 un incremento de 90 millones; y las de estrato 6 un incremento aún mayor, de aproximadamente 214 millones. Estos efectos no lineales reflejan adecuadamente las brechas de valorización asociadas a calidad del entorno, infraestructura, seguridad y servicios, que caracterizan a los estratos más altos.

En cuanto a la dotación interna, tanto el número de baños (β = 24.8) como el número de habitaciones (β = 10.0) muestran efectos positivos y significativos, confirmando que viviendas con mayor capacidad funcional tienden a presentar precios superiores. No obstante, la magnitud del coeficiente de baños es mayor, lo cual sugiere que este elemento tiene un peso más fuerte dentro de la composición del valor.

Por su parte, la longitud presenta un coeficiente negativo (β = –2,618), lo que indica que variaciones hacia el este u oeste dentro de la Zona Norte se asocian a cambios sistemáticos en el precio. Este patrón espacial es consistente con los resultados previos de correlación, donde la localización mostró una relación significativa con el valor del inmueble (Figura 1.8).

En términos de ajuste, el modelo alcanza un R² de 0.665 y un R² ajustado de 0.661, lo cual implica que explica aproximadamente el 66% de la variabilidad del precio. Este nivel de desempeño es adecuado para un mercado tan heterogéneo como el inmobiliario, donde factores no observados (calidades constructivas, remodelaciones, características del entorno inmediato, entre otros) suelen introducir variabilidad adicional.

En síntesis, el modelo final es estadísticamente sólido, cumple con criterios adecuados de significancia y ajuste, y ofrece interpretaciones coherentes con la dinámica real del mercado inmobiliario en la Zona Norte de la ciudad de Cali. El tratamiento categórico del estrato mejora la fidelidad del modelo, permitiendo capturar efectos socioeconómicos no lineales que no se reflejan bajo una codificación numérica simple.

Como siguiente paso, se evaluará la colinealidad entre los predictores mediante el índice VIF, con el fin de verificar que las variables incluidas en el modelo no presenten problemas de colinealidad o redundancias y que los coeficientes estimados puedan interpretarse de manera estable y confiable.

vif(modelo_step_forward)
##                  GVIF Df GVIF^(1/(2*Df))
## areaconst    1.807730  1        1.344519
## estrato_f    2.190563  3        1.139618
## banios       2.145737  1        1.464833
## longitud     2.120716  1        1.456268
## habitaciones 1.893917  1        1.376197

Todos los valores ajustados de GVIF^(1/(2·Df)) se encuentran muy por debajo del umbral crítico de 5, e incluso por debajo del criterio más estricto de 2.5. Esto indica que no existe colinealidad preocupante entre los predictores del modelo. En consecuencia, los coeficientes estimados no se encuentran inflados y pueden interpretarse de forma estable y confiable.

Finalmente, aunque el modelo presenta un buen nivel de ajuste, pueden considerarse algunas estrategias para mejorar su capacidad explicativa. Entre ellas, la aplicación de transformaciones logarítmicas en la variable precio para reducir posibles asimetrías en su distribución, así como la evaluación de interacciones entre variables que puedan enriquecer la explicación del fenómeno (por ejemplo, la interacción entre área construida y estrato). Asimismo, podría contemplarse la incorporación de atributos del entorno urbano, como accesibilidad o cercanía a vías principales y equipamientos. De igual manera, el uso de enfoques espaciales permitiría capturar posibles patrones de dependencia geográfica, dado que viviendas ubicadas en zonas cercanas suelen presentar comportamientos de precio similares. Estas alternativas podrían incrementar la capacidad predictiva del modelo y ofrecer una caracterización más completa del comportamiento del mercado inmobiliario.

Validación de supuestos del modelo

A continuación, se evalúan los supuestos fundamentales del modelo de regresión lineal múltiple estimado mediante el procedimiento Stepwise, con el fin de verificar si se cumplen las condiciones necesarias para realizar inferencias estadísticas válidas. En esta etapa no se realizan correcciones sobre los posibles problemas identificados; únicamente se señalan y se plantean algunas alternativas potenciales de mejora.

1. Normalidad de los errores

Evaluar si los errores del modelo se distribuyen de manera aproximadamente normal.

qqnorm(residuals(modelo_step_forward))
qqline(residuals(modelo_step_forward), col = "red", lwd = 2)
**Figura 1.10** Q–Q Plot de los residuos

Figura 1.10 Q–Q Plot de los residuos

shapiro.test(residuals(modelo_step_forward))
## 
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo_step_forward)
## W = 0.81798, p-value < 2.2e-16

La Figura 1.10 muestra desviaciones claras respecto a la línea teórica, especialmente en las colas inferior y superior, lo que evidencia la presencia de residuos extremos y una distribución no normal. Este comportamiento se confirma con la prueba de Shapiro–Wilk (W = 0.81798, p < 2.2e-16), que rechaza de manera contundente la hipótesis nula de normalidad. En consecuencia, los errores del modelo no siguen una distribución normal, situación esperable en datos inmobiliarios donde el precio presenta asimetría y valores atípicos asociados a propiedades de muy alto valor. Si bien esta desviación no invalida el modelo, puede afectar la precisión de los intervalos de confianza y las pruebas inferenciales.

Sugerencia: para mejorar este supuesto en futuros análisis, podría considerarse transformar la variable respuesta (por ejemplo, mediante logaritmo) o emplear modelos robustos que reduzcan la influencia de valores extremos.

2. Media cero de los errores (E[e] = 0)

mean(residuals(modelo_step_forward))
## [1] -2.102474e-15

La media de los residuos estimada por el modelo fue: \(\bar{e} = -2.10 \times 10^{-15}\). Este valor es extremadamente cercano a cero (prácticamente cero), lo cual cumple plenamente el supuesto de que los errores deben tener media igual a cero. Este comportamiento es esperable en modelos lineales ajustados mediante Mínimos Cuadrados Ordinarios (OLS), dado que el estimador garantiza que la suma de los residuos sea exactamente cero.

3. Homocedasticidad (varianza constante) de los residuales

A continuación se presenta el gráfico de residuos vs valores ajustados

plot(modelo_step_forward$fitted.values,
     residuals(modelo_step_forward),
     xlab = "Valores ajustados",
     ylab = "Residuos",
     main = "Residuos vs Ajustados")
abline(h = 0, col = "red")
**Figura 1.11** Gráfico de residuos vs valores ajustados

Figura 1.11 Gráfico de residuos vs valores ajustados

gqtest(modelo_step_forward)
## 
##  Goldfeld-Quandt test
## 
## data:  modelo_step_forward
## GQ = 1.7022, df1 = 300, df2 = 299, p-value = 2.424e-06
## alternative hypothesis: variance increases from segment 1 to 2

Visualmente se observa un patrón de dispersión creciente a medida que aumentan los valores predichos (Figura 1.11), lo que sugiere la presencia de heterocedasticidad: los residuos se encuentran más concentrados en viviendas de menor precio y se dispersan ampliamente en inmuebles de mayor valor. Este comportamiento es habitual en mercados inmobiliarios, donde los segmentos de alto valor presentan mayor variabilidad en sus características y precios. Esta evidencia visual se confirma estadísticamente mediante el test de Goldfeld–Quandt (GQ = 1.7022, p = 2.424×10⁻⁶), el cual rechaza la hipótesis nula de varianza constante e indica que la dispersión de los errores aumenta entre los segmentos evaluados. En conjunto, los resultados muestran que el modelo presenta heterocedasticidad, lo que puede afectar la precisión de los errores estándar y, por tanto, la significancia de los coeficientes.

Sugerencia: En aplicaciones futuras podrían considerarse estrategias como:

  • Transformar el precio (log-precio) para estabilizar la varianza.
  • Aplicar modelos con errores robustos (HC3 o White)
  • Modelos no lineales o técnicas como weighted least squares (WLS).

4. Independencia de los errores (E[ei, ej] = 0)

Aunque los datos no son temporales, se aplica de forma estándar la prueba de Durbin–Watson como indicador de autocorrelación en los residuos.

dwtest(modelo_step_forward)
## 
##  Durbin-Watson test
## 
## data:  modelo_step_forward
## DW = 1.7024, p-value = 7.883e-05
## alternative hypothesis: true autocorrelation is greater than 0

El test de Durbin–Watson arrojó un valor DW = 1.7024 con un p-value = 7.883×10⁻⁵, lo que implica el rechazo de la hipótesis nula de ausencia de autocorrelación. En términos prácticos, esto sugiere la presencia de autocorrelación positiva en los residuos del modelo. Aunque esta prueba se desarrolló originalmente para series temporales, su aplicación en datos de corte transversal puede mostrar dependencia asociada a patrones espaciales, especialmente en el caso de mercados inmobiliarios donde la ubicación geográfica introduce correlación entre observaciones cercanas.

Este resultado es coherente con el análisis exploratorio previo, donde se identificó un gradiente espacial del precio en función de la longitud. La autocorrelación en los residuos puede indicar que el modelo no captura completamente la estructura espacial de los datos.

Sugerencias: en futuras aplicaciones podrían incorporarse técnicas que modelen explícitamente la dependencia espacial, como la regresión geográficamente ponderada (GWR), modelos autoregresivos espaciales (SAR) o la inclusión de variables de entorno urbano que representen más adecuadamente la estructura espacial del mercado.

Si bien el modelo incumple algunos supuestos clásicos (normalidad de los errores, homocedasticidad e independencia estricta), estos resultados son coherentes con la naturaleza del mercado inmobiliario y no invalidan el análisis realizado en esta actividad. De acuerdo con lo planteado en el enunciado, no se implementan correcciones sobre el modelo; sin embargo, se sugiere que en aplicaciones futuras se consideren transformaciones del precio (por ejemplo, logaritmo), el uso de errores estándar robustos y la incorporación de modelos espaciales, con el fin de mejorar el ajuste a los supuestos teóricos y la estabilidad inferencial.

Validación del modelo

  • Validacion Simple:

Para evaluar la capacidad predictiva del modelo seleccionado y verificar su estabilidad fuera de la muestra de estimación, se aplicara una validación simple (hold-out). Este método consiste en dividir aleatoriamente la base de datos en dos subconjuntos:

  • Muestra de entrenamiento (70%), utilizada para reestimar el modelo.
  • Muestra de validación (30%), usada exclusivamente para evaluar el desempeño predictivo.

El proceso a aplicar sera el siguiente:

  • Primero, se seleccionara aleatoriamente el 70% de las observaciones, con lo cual se formó la muestra train.

  • Con esta muestra, se reestimara el modelo final identificado por el proceso Stepwise, utilizando la misma especificación funcional.

  • Luego, se generaran predicciones del precio sobre el 30% restante, que actúa como muestra test, la cual el modelo nunca vio durante la estimación.

Finalmente, se compararan los valores reales y predichos mediante métricas de desempeño como el MSE, RMSE y la correlación entre \(𝑌\) y \(\hat{Y}\), lo que permitira evaluar el grado de “encogimiento” del modelo respecto al ajuste original.

Este procedimiento permite determinar si el modelo generaliza adecuadamente a nuevas observaciones y si los patrones identificados no dependen exclusivamente de la muestra con la cual fue estimado:

set.seed(123)   # para reproducibilidad

# 1) Número total de observaciones
n <- nrow(df_norte2)

# 2) Seleccionar ~70% para entrenamiento
train <- sample(1:n, size = floor(0.7 * n))

# 3) Estimar el modelo SOLO con la muestra de entrenamiento
modelo_train <- lm(formula(modelo_step_forward),
                   data = df_norte2[train, ])

summary(modelo_train)
## 
## Call:
## lm(formula = formula(modelo_step_forward), data = df_norte2[train, 
##     ])
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -794.48  -77.13  -12.57   46.96 1051.63 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -2.194e+05  5.106e+04  -4.298 2.14e-05 ***
## areaconst     6.443e-01  6.160e-02  10.460  < 2e-16 ***
## estrato_f4    4.476e+01  2.587e+01   1.730  0.08436 .  
## estrato_f5    9.226e+01  2.441e+01   3.780  0.00018 ***
## estrato_f6    1.846e+02  4.239e+01   4.355 1.67e-05 ***
## banios        2.967e+01  7.546e+00   3.932 9.85e-05 ***
## longitud     -2.868e+03  6.674e+02  -4.298 2.15e-05 ***
## habitaciones  1.206e+01  6.257e+00   1.927  0.05467 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 160.3 on 422 degrees of freedom
## Multiple R-squared:  0.6492, Adjusted R-squared:  0.6434 
## F-statistic: 111.6 on 7 and 422 DF,  p-value: < 2.2e-16
# 4) Predecir en la muestra de validación
predicciones <- predict(
  modelo_train, 
  newdata = df_norte2[-train, ]
)

# 5) Calcular el error cuadrático medio (MSE)
error_mse <- mean((df_norte2$preciom[-train] - predicciones)^2)

# RMSE
error_rmse <- sqrt(error_mse)

# Correlación entre Y observado y Ŷ
cor_yyhat <- cor(df_norte2$preciom[-train], predicciones)

data.frame(
  MSE_validacion_simple  = error_mse,
  RMSE_validacion_simple = error_rmse,
  Correlacion_Y_Yhat     = cor_yyhat
)
##   MSE_validacion_simple RMSE_validacion_simple Correlacion_Y_Yhat
## 1              17368.13               131.7882          0.8378717

Los resultados de la validación simple muestran que el modelo mantiene un comportamiento estable cuando se aplica a datos no utilizados en la estimación. Tras reestimar el modelo con el 70% de la muestra (train), los coeficientes conservan los mismos signos y una magnitud similar a los obtenidos con la base completa, lo cual indica que la estructura del modelo es robusta y no depende de un subconjunto específico de observaciones.

Considerando que el precio promedio de las viviendas en la base analizada es cercano a 430 millones de pesos (Tabla V), el RMSE de aproximadamente 132 millones representa un error relativo cercano al 31% del valor promedio. Este resultado es consistente con el MSE estimado de 17368, que refleja la magnitud promedio del error cuadrático entre los valores observados y predichos. Este nivel de error evidencia la variabilidad inherente al mercado inmobiliario, donde el precio de las viviendas depende de múltiples factores estructurales y de localización que no siempre se encuentran completamente capturados en el conjunto de variables disponible. No obstante, la alta correlación entre valores observados y predichos (r = 0.838) indica que el modelo logra reproducir adecuadamente la tendencia general de los precios en la Zona Norte de Cali.

En particular, este valor de correlación es muy cercano a \(\sqrt{R^2}\) del modelo completo, lo que indica que el encogimiento del modelo es mínimo y que la capacidad predictiva se conserva fuera de la muestra de estimación. En conjunto, estos resultados confirman que el modelo presenta buena generalización, no evidencia sobreajuste significativo y puede utilizarse de manera confiable para apoyar la selección de ofertas inmobiliarias basadas en sus predicciones.

Predecir el precio (a partir del modelo elegido)

A partir del modelo de regresión estimado, definido en la ecuación (1), se realiza la predicción del precio para la vivienda correspondiente a la primera solicitud, considerando las características establecidas para este caso:

  • Area construida= 200
  • Baños= 2
  • Habitaciones= 4
  • Estrato= 4 o 5

Importante: Cabe recordar que la variable parqueaderos fue excluida del análisis debido al alto porcentaje de datos faltantes, lo cual impedía realizar una imputación confiable y podía introducir sesgos en la estimación del modelo. Por otro lado, aunque la variable longitud no aparece en la solicitud original de la vivienda, esta fue incorporada en el modelo final tras resultar estadísticamente significativa durante el proceso de selección mediante Stepwise. Para generar una predicción coherente, se asignó un valor representativo de la Zona Norte de Cali. En particular, se utilizó la longitud −76.52, valor cercano a la media (Tabla V) y ubicado dentro del rango observado en las viviendas del conjunto depurado. Esta aproximación permite mantener la consistencia espacial con el comportamiento observado en el mercado, sin afectar la validez del ejercicio de predicción.

Para el caso en que la vivienda pertenece al estrato 4, se tiene lo siguiente:

# Nueva vivienda - estrato 4
nueva_viv1 <- data.frame(
  areaconst    = 200,
  estrato_f    = factor("4", levels = levels(df_norte2$estrato_f)),
  banios       = 2,
  longitud     = -76.52,
  habitaciones = 4
)

pred_estrato4 <- predict(
  modelo_step_forward,
  newdata  = nueva_viv1,
  interval = "prediction",
  level    = 0.95
)

pred_estrato4
##       fit      lwr      upr
## 1 342.263 42.65556 641.8705

Mientras que para el Estrato 5, tenemos:

# Cambiar solo estrato
nueva_viv1$estrato_f <- factor("5", levels = levels(df_norte2$estrato_f))

pred_estrato5 <- predict(
  modelo_step_forward,
  newdata  = nueva_viv1,
  interval = "prediction",
  level    = 0.95
)

pred_estrato5
##        fit      lwr      upr
## 1 387.8996 88.66492 687.1343

Al aplicar el modelo de regresión múltiple a la Vivienda Tipo 1, se obtuvieron estimaciones diferenciadas según el estrato socioeconómico. Para estrato 4, el precio esperado es de 342.26 millones, con un intervalo de predicción al 95% entre 42.66 y 641.87 millones. Para estrato 5, la estimación aumenta a 387.90 millones, con un intervalo de predicción entre 88.66 y 687.13 millones. Estas diferencias reflejan el efecto positivo del estrato sobre el valor del inmueble, en línea con las condiciones de valorización asociadas a niveles socioeconómicos más altos.

Los intervalos de predicción (IP) se utilizaron porque permiten estimar no solo el valor promedio esperado, sino también el rango plausible en el que podría ubicarse el precio real de una vivienda individual. A diferencia de los intervalos de confianza, que solo capturan la incertidumbre del modelo, los IP incorporan la variabilidad propia del mercado inmobiliario, caracterizado por una alta heterogeneidad en atributos físicos, constructivos y de localización. Por ello, estos intervalos proporcionan una evaluación más realista de la incertidumbre asociada al precio final para una vivienda específica.

Selección de ofertas potenciales

A partir de la predicción obtenida con el modelo de regresión, se identificaran las ofertas del mercado que se ajustan a las características solicitadas para la Vivienda Tipo 1. Considerando que la empresa cuenta con un crédito preaprobado de hasta 350 millones de pesos, se filtran únicamente aquellas alternativas cuyo precio se encuentra dentro de este límite y que cumplen con los atributos estructurales y de estrato requeridos:

  • Precio<= 350 millones
  • Area construida >= 200metros
  • Baños, al menos 2
  • Habitaciones, al menos 4
  • Estrato 4 o 5

Siendo asi obtemos las siguientes 5 ofertas

# Filtrar viviendas que cumplan los criterios del cliente
ofertas_filtradas <- df_norte2 %>%
  filter(
    preciom <= 350,         # dentro del presupuesto
    areaconst >= 200,  
    banios >= 2,
    habitaciones >= 4,
    estrato_f %in% c("4", "5")
  )
# Seleccionar las 5 viviendas más cercanas al perfil
ofertas_top5 <- ofertas_filtradas %>%
  arrange(abs(areaconst - 200)) %>%
  slice(1:5)
plot_ly(
  ofertas_top5,
  type = "scattermapbox",
  lon = ~longitud,
  lat = ~latitud,
  mode = "markers",
  marker = list(size = 12, color = "blue"),
  text = ~paste("Precio:", preciom, "millones<br>",
                "Área:", areaconst, "m²<br>",
                "Estrato:", estrato_f, "<br>",
                "Baños:", banios, "<br>",
                "Habitaciones:", habitaciones)
) %>%
  layout(
    mapbox = list(
      style = "open-street-map",
      zoom = 12,
      center = list(lon = -76.52, lat = 3.45)
    ),
    title = "Ofertas potenciales para la Vivienda Tipo 1"
  )

Las cinco viviendas identificadas constituyen alternativas viables y coherentes con la predicción del modelo para la Vivienda Tipo 1, ya que cumplen simultáneamente con las restricciones de precio, estrato y características estructurales. Todas se encuentran ubicadas dentro del corredor residencial consolidado de la Zona Norte, lo que garantiza acceso a servicios, buena conectividad y condiciones de seguridad acordes con lo solicitado por el cliente.

El mapa georreferenciado confirma que las ofertas están correctamente localizadas en el área objetivo, validando el proceso previo de depuración espacial. Además, se observa una variación de precios asociada a diferencias longitudinales dentro de la zona, consistente con el patrón identificado en el análisis LOESS, donde la ubicación este–oeste influye significativamente en el valor final del inmueble.

Analisis de Vivienda Tipo 2

Seleccion de la base

Para este caso seleccionaremos las viviendas que son apartamentos en la zona sur:

dfsur <- subset(df, zona == "Zona Sur" & tipo == "Apartamento")

# Ver primeros 3 registros
head(dfsur, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  5098 Zona S… 05          4     290        96            1      2            3
## 2   698 Zona S… 02          3      78        40            1      1            2
## 3  8199 Zona S… <NA>        6     875       194            2      5            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
table(dfsur$tipo, dfsur$zona)
##              
##               Zona Sur
##   Apartamento     2787

Se identificaron 2787 registros que cumplen con las condiciones establecidas, correspondientes a viviendas tipo “apartamento” ubicadas en la Zona Sur de la ciudad. A partir de este subconjunto, se procede a verificar que todas las observaciones se encuentren efectivamente localizadas en el sector sur de Cali, con el fin de garantizar la coherencia geográfica del análisis.

map10 <- leaflet(dfsur) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = 5,
    color = "blue",
    fillOpacity = 0.7,
    popup = ~paste(
      "Precio: ", preciom, "<br>",
      "Habitaciones: ", habitaciones, "<br>",
      "Barrio: ", barrio, "<br>",
      "Baños: ", banios
    )
  )

map10

Tal como ocurrio en la base de la zona norte, vemos inconsistencia en la base, por lo que procederemos a filtrar solo apartamentos que se encuentren a una latitud que sea menor a 3.43.

df_sur1 <- subset(df, 
              zona == "Zona Sur" & 
                tipo == "Apartamento" & 
                latitud < 3.43)

table(df_sur1$tipo, df_sur1$zona)
##              
##               Zona Sur
##   Apartamento     2502

Con esto obtenemos una base de 2502 distribuidos en el mapa de la siguiente forma:

map20 <- leaflet(df_sur1) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~longitud,
    lat = ~latitud,
    radius = 5,
    color = "#B254A5",
    fillOpacity = 0.7,
    popup = ~paste(
      "Precio: ", preciom, "<br>",
      "Habitaciones: ", habitaciones, "<br>",
      "Barrio: ", barrio, "<br>",
      "Baños: ", banios
    )
  )

map20

Análisis Exploratorio-Correlación

Con el conjunto de datos ya filtrado para este tipo de vivienda (Aptos-zona Sur), se inicia el análisis exploratorio, incluyendo la revisión, depuración y tratamiento de la información, así como la evaluación de las relaciones entre las variables mediante análisis de correlación.

Tratamiento y Depuración de la base

1. Validacion de datos faltantes
# Conteo de NA por columna
colSums(is.na(df_sur1))
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0          547            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##          350            0            0            0            0            0 
##      latitud 
##            0

Se observa un alto porcentaje de datos faltantes en las variables piso y parqueaderos (21.8% y 13.9%, respectivamente). En el caso de la variable piso, además de presentar una proporción considerable de valores ausentes, su interpretación resulta limitada para este tipo de vivienda. En los apartamentos, la distribución vertical suele estar determinada por la estructura del edificio, por lo que el número de pisos no necesariamente refleja características comparables entre inmuebles. Aunque existen casos particulares como dúplex o townhouses que pueden abarcar más de un nivel, estas situaciones son menos frecuentes y no representan el comportamiento predominante en la base analizada. En consecuencia, se decide excluir la variable piso del análisis.

Asimismo, la variable parqueaderos presenta una cantidad significativa de valores faltantes, lo que dificulta su tratamiento mediante imputación sin introducir posibles sesgos. Por esta razón, también se decide excluirla del análisis.

df_sur2 <- df_sur1 %>%
  dplyr::select(-piso, -parqueaderos)
2.Validacion de datos repetidos
# Número de duplicados por ID
duplicados_id <- df_sur2%>% 
  group_by(id) %>% 
  filter(n() > 1)

duplicados_id
## # A tibble: 0 × 11
## # Groups:   id [0]
## # ℹ 11 variables: id <dbl>, zona <chr>, estrato <dbl>, preciom <dbl>,
## #   areaconst <dbl>, banios <dbl>, habitaciones <dbl>, tipo <chr>,
## #   barrio <chr>, longitud <dbl>, latitud <dbl>

No se evidencian datos repetidos en la base.

3. Validacion de datos atípicos
  • Variables númericas:
#variables numericas:
vars_numericas10 <- c("preciom", "areaconst", 
                    "banios", "habitaciones","longitud","latitud")

# Resumen con skimr solo para esas variables
df_resumen10 <- skim(df_sur2[vars_numericas10])

# Filtrar solo numéricas y seleccionar columnas de interés
tabla_resumen10 <- df_resumen10 %>% 
  dplyr::filter(skim_type == "numeric") %>% 
  dplyr::select(
    skim_variable, numeric.mean, numeric.sd,
    numeric.p0, numeric.p25, numeric.p50,
    numeric.p75, numeric.p100
  )

# Renombrar columnas para presentación
colnames(tabla_resumen10) <- c(
  "Variable", "Media", "Desv.Std", "Mínimo",
  "Q1", "Mediana", "Q3", "Máximo"
)

# Mostrar tabla bonita
tabla_resumen10 %>% 
  kable(format = "html", digits = 2,
        caption = "**Tabla VI. Resumen estadístico de las variables numéricas**") %>% 
  kable_styling(full_width = FALSE,
                bootstrap_options = c("striped", "hover", "condensed"))
Tabla VI. Resumen estadístico de las variables numéricas
Variable Media Desv.Std Mínimo Q1 Mediana Q3 Máximo
preciom 296.16 191.83 78.00 175.00 245.00 330.00 1750.00
areaconst 97.08 52.34 40.00 65.00 85.00 109.81 932.00
banios 2.49 0.93 0.00 2.00 2.00 3.00 8.00
habitaciones 2.96 0.63 0.00 3.00 3.00 3.00 6.00
longitud -76.53 0.01 -76.57 -76.54 -76.53 -76.52 -76.46
latitud 3.38 0.02 3.33 3.37 3.38 3.40 3.43
# Pasar a formato largo solo esas variables
vars_long10 <- df_sur2 %>% 
  dplyr::select(all_of(vars_numericas10)) %>% 
  pivot_longer(cols = everything(),
               names_to = "variable",
               values_to = "valor")

# Boxplots por variable
ggplot(vars_long10, aes(x = variable, y = valor)) +
  geom_boxplot(alpha = 0.7, fill = "#4C9AFF", color = "black") +
  facet_wrap(~ variable, scales = "free") +
  theme_minimal(base_size = 12) +
  labs(
    title = "Distribución de variables numéricas",
    x = "Variable",
    y = "Valor"
  ) +
  theme(
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank()
  )
**Figura 2.1**: Boxplot. Identificación de valores atípicos

Figura 2.1: Boxplot. Identificación de valores atípicos

La Figura 2.1 presentan valores extremos (particularmente el precio y el área construida) estos no corresponden a errores de captura sino a un comportamiento natural del mercado inmobiliario del sur de la ciudad. Esta zona concentra una alta proporción de barrios de estrato 6, donde es habitual encontrar apartamentos con áreas amplias y precios significativamente superiores al promedio general. Por lo tanto, los registros identificados como posibles outliers deben interpretarse como variabilidad propia del mercado y no como valores atípicos que requieran eliminación.

Por otro lado, dado los resultados en la Tabla VI evidenciamos que tenemos apartamentos con 0 baños y habitaciones, estos son considerados atipicos, a continuacion validaremos cuantos registros tenemos asi:

  • Registros con 0 habitaciones
df_sur2 %>% 
  filter(habitaciones == 0) %>% 
  nrow()
## [1] 7
  • Registros con 0 baños
df_sur2 %>% 
  filter(banios == 0) %>% 
  nrow()
## [1] 5

Dado que son pocos registros y por el tamaño que tenemos en la base (2502), procederemos a eliminarlos.

df_sur3 <- df_sur2 %>%
  filter(banios != 0 & habitaciones != 0)

nrow(df_sur3)
## [1] 2494

Finalmente, se trabajará con una base depurada compuesta por 2494 registros para viviendas tipo apartamento de la zona sur de Cali.

  • Variables cualitativas:

Anteriormente ya habiamos tratado las variables de zona y barrios, asi que garantizamos no tener desviaciones en las mismas, por lo que procederemos a validar si tenemos inconsistencia en la variable estrato usando un grafico de boxplot:

ggplot(df_sur3, aes(x = as.factor(estrato))) +
  geom_bar(fill = "#4DBBD5") +
  labs(title = "Distribución de Estratos",
       x = "Estrato",
       y = "Frecuencia") +
  theme_minimal()
**Figura 2.2**: Distribucion del Estrato. Zona Sur/Apartamento

Figura 2.2: Distribucion del Estrato. Zona Sur/Apartamento

No se observan desviaciones en la distribución de la variable estrato, ya que sus valores se encuentran dentro del rango permitido (de 1 a 6). Asimismo, se evidencia que los estratos 4 y 5 presentan la mayor frecuencia dentro de la base de datos seleccionada.

Con base en el conjunto de datos tratado, se estimaron los estadísticos descriptivos de las variables numéricas, los cuales se resumen en la siguiente tabla:

#variables numericas:
vars_numericas <- c("preciom", "areaconst", 
                    "banios", "habitaciones","longitud","latitud")

# Resumen con skimr solo para esas variables
df_resumen_viv2 <- skim(df_sur3[vars_numericas])

# Filtrar solo numéricas y seleccionar columnas de interés
tabla_resumen_viv2 <- df_resumen_viv2 %>% 
  dplyr::filter(skim_type == "numeric") %>% 
  dplyr::select(
    skim_variable, numeric.mean, numeric.sd,
    numeric.p0, numeric.p25, numeric.p50,
    numeric.p75, numeric.p100
  )

# Renombrar columnas para presentación
colnames(tabla_resumen_viv2) <- c(
  "Variable", "Media", "Desv.Std", "Mínimo",
  "Q1", "Mediana", "Q3", "Máximo"
)

# Mostrar tabla
tabla_resumen_viv2 %>% 
  kable(format = "html", digits = 2,
        caption = "**Tabla VII.Resumen estadístico de las variables numéricas. Vivienda Tipo 2**") %>% 
  kable_styling(full_width = FALSE,
                bootstrap_options = c("striped", "hover", "condensed"))
Tabla VII.Resumen estadístico de las variables numéricas. Vivienda Tipo 2
Variable Media Desv.Std Mínimo Q1 Mediana Q3 Máximo
preciom 296.03 191.52 78.00 175.00 245.00 330.00 1750.00
areaconst 97.03 52.28 40.00 65.00 85.00 109.81 932.00
banios 2.50 0.93 1.00 2.00 2.00 3.00 8.00
habitaciones 2.97 0.61 1.00 3.00 3.00 3.00 6.00
longitud -76.53 0.01 -76.57 -76.54 -76.53 -76.52 -76.46
latitud 3.38 0.02 3.33 3.37 3.38 3.40 3.43

La Tabla VII muestra que el precio promedio en los aptos de la zona sur, es cercano a 296 millones de pesos, con una desviación estándar de 191 millones, lo que evidencia una variabilidad considerable en los valores de mercado. En cuanto al tamaño, el área construida promedio es de 97 m², con una mediana de 85 m², lo que sugiere que predominan apartamentos de tamaño medio.

Respecto a la distribución interna, las viviendas cuentan en promedio con 2.5 baños y cerca de 3 habitaciones, características consistentes con apartamentos de uso familiar. Por su parte, las variables de latitud y longitud presentan una dispersión reducida, lo que confirma la concentración geográfica de los inmuebles dentro del área analizada.

Correlación

A continuación, se evalúa la correlación de la variable respuesta (precio de la vivienda) con respecto a variables: área construida, estrato, número de baños, número de habitaciones y zona de ubicación del inmueble.

Variables numericas

De forma similar al análisis previo, se examina si la variable precio en este conjunto de datos se aproxima a una distribución normal.

ggplot(df_sur3, aes(preciom)) +
  geom_histogram(aes(y = ..density..), bins = 30, fill = "lightblue") +
  stat_function(fun = dnorm,
                args = list(mean = mean(df_norte2$preciom), sd = sd(df_norte2$preciom)),
                color = "red", size = 1) +
  labs(title = "Distribución del precio")
**Figura 2.3**: Distribución Variable Precio

Figura 2.3: Distribución Variable Precio

shapiro.test(df_sur3$preciom)
## 
##  Shapiro-Wilk normality test
## 
## data:  df_sur3$preciom
## W = 0.74828, p-value < 2.2e-16

El análisis exploratorio muestra que la variable preciom presenta una distribución claramente asimétrica hacia la derecha, con una concentración de valores entre 150 y 400 millones y una cola extendida que incluye propiedades de alto valor típicas del sur de la ciudad (estrato 5–6). Esta observación se confirma estadísticamente mediante la prueba de normalidad de Shapiro–Wilk, cuyo resultado (W = 0.7486, p-value < 2.2e-16) permite rechazar la hipótesis de normalidad.

Dado lo anterior, para el analisis de correlacion utilizaremos Spearman:

df_corr10 <- df_sur3 %>%
  dplyr::select(precio = preciom, areaconst, banios, habitaciones)

ggpairs(
  df_corr10,
  lower = list(continuous = wrap("smooth", alpha = 0.3)),
  diag = list(continuous = "densityDiag"),
  upper = list(continuous = wrap("cor", method = "spearman", size = 4))
)
**Figura 2.4**:Matriz de Dispersión- Correlación Spearman. Aptos en la Zona Sur

Figura 2.4:Matriz de Dispersión- Correlación Spearman. Aptos en la Zona Sur

El análisis de correlación mediante el coeficiente de Spearman (Figura 2.4) muestra que el área construida es la variable con mayor asociación con el precio de los apartamentos, presentando una correlación positiva alta de 0.864. Este resultado sugiere que, a mayor tamaño del inmueble, mayor tiende a ser su valor de mercado.

El número de baños también presenta una correlación positiva de magnitud moderada-alta con el precio (0,705), lo cual indica que una mayor dotación interna del apartamento suele estar asociada con precios más elevados. Por su parte, el número de habitaciones muestra la relación más débil entre las variables analizadas (0.387), aunque mantiene una asociación positiva y estadísticamente significativa.

En conjunto, los resultados evidencian un patrón consistente en la importancia relativa de las variables (área construida > número de baños > número de habitaciones), lo que respalda su inclusión como variables explicativas en el modelo de regresión múltiple que se estimará posteriormente.

Correlación entre Precio y Estrato

Para este caso, tambien aplicaremos el coeficiente de Sperman:

cor.test(df_sur3$preciom, df_sur3$estrato, method = "spearman")
## Warning in cor.test.default(df_sur3$preciom, df_sur3$estrato, method =
## "spearman"): Cannot compute exact p-value with ties
## 
##  Spearman's rank correlation rho
## 
## data:  df_sur3$preciom and df_sur3$estrato
## S = 637027912, p-value < 2.2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##       rho 
## 0.7536115
ggplot(df_sur3, aes(x = as.factor(estrato), y = preciom)) +
  geom_boxplot(fill = "#4DBBD5") +
  labs(title = "Estrato y Precio.Aptos en el sur",
       x = "Estrato",
       y = "Precio (millones)") +
  theme_minimal()
**Figura 2.5**:Boxplot Estrato y Precio.Aptos en el Sur

Figura 2.5:Boxplot Estrato y Precio.Aptos en el Sur

El análisis de correlación de Spearman evidencia una asociación positiva fuerte entre el precio de la vivienda y el estrato socioeconómico (ρ = 0.7539, p-value < 2.2e-16). Este resultado indica que, a medida que aumenta el estrato, también tiende a incrementarse el precio de los inmuebles de manera consistente y monotónica.

La significancia estadística (p < 0.001) confirma que la relación no es producto del azar, sino un patrón estructural del mercado inmobiliario en la zona analizada. Este comportamiento se refleja también en el boxplot (Figura 2.5), donde se observa un claro escalonamiento del precio entre estratos, siendo los inmuebles de estrato 6 los que presentan los valores más altos y la mayor dispersión.

En conjunto, estos resultados demuestran que el estrato es un determinante relevante del precio, actuando como un indicador territorial y socioeconómico que explica una parte importante de la variabilidad en los valores de las viviendas.

Correlación entre Precio y Longitud-Latitud

Para ello utilizaremos la correlacion de Spearman:

  • Correlacion Latitud:
cor.test(df_sur3$preciom, df_sur3$latitud, method = "spearman")
## 
##  Spearman's rank correlation rho
## 
## data:  df_sur3$preciom and df_sur3$latitud
## S = 3568816209, p-value < 2.2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##        rho 
## -0.3803403
plot_ly(df_sur3, x = ~latitud, y = ~preciom, type = "scatter",
        mode = "markers", marker = list(opacity = 0.4)) %>%
  add_lines(x = ~latitud,
            y = fitted(loess(preciom ~ latitud, data = df_sur3)),
            line = list(color = "blue", width = 3)) %>%
  layout(
    title = "Tendencia del precio según \n la latitud (LOESS)",
    xaxis = list(title = "Latitud"),
    yaxis = list(title = "Precio (millones)")
  )
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...

Figura 2.6:Curva LOESS. Tendencia del precio segun latitud

A pesar de que la correlación entre precio y latitud no es muy alta, la relación es significativa, clara y consistente, tanto estadísticamente (ρ = –0.38, p < 0.001) como visualmente a través de la curva LOESS (Figura 2.6). Esto indica que la latitud sí captura parte de la estructura espacial del mercado inmobiliario del sur, reflejando gradientes territoriales donde ciertos sectores concentran inmuebles de mayor valor. En consecuencia, la latitud puede considerarse una variable predictora pertinente, siempre que se modele adecuadamente su comportamiento no lineal.

  • Correlacion Longitud
cor.test(df_sur3$preciom, df_sur3$longitud, method = "spearman")
## 
##  Spearman's rank correlation rho
## 
## data:  df_sur3$preciom and df_sur3$longitud
## S = 3145218127, p-value < 2.2e-16
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##        rho 
## -0.2165018
plot_ly(df_sur3, x = ~longitud, y = ~preciom, type = "scatter",
        mode = "markers", marker = list(opacity = 0.4)) %>%
  add_lines(x = ~longitud,
            y = fitted(loess(preciom ~ longitud, data = df_sur3)),
            line = list(color = "blue", width = 3)) %>%
  layout(
    title = "Tendencia del precio según \n la longitud (LOESS)",
    xaxis = list(title = "Longitud"),
    yaxis = list(title = "Precio (millones)")
  )
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...

Figura 2.7:Curva LOESS. Tendencia del precio segun longitud

Por el contrario, la relación entre precio y longitud es mucho más débil (ρ = –0.22, p < 0.001) y la tendencia observada no presenta un patrón consistente que aporte información relevante para explicar la variación del precio. La longitud muestra oscilaciones dispersas y no representa una estructura espacial clara dentro de la zona analizada, por lo que su capacidad predictiva es limitada. En este sentido, resulta adecuado excluir la longitud como predictor dentro del modelo, priorizando variables con mayor capacidad explicativa y estabilidad.

plot_ly(
  data = df_sur3,
  x = ~longitud,
  y = ~latitud,
  type = "scatter",
  mode = "markers",
  marker = list(
    size = 7,
    color = ~preciom,
    colorscale = "Viridis",
    showscale = TRUE
  )
) %>%
  layout(
    title = "Mapa de precios por ubicación",
    xaxis = list(title = "Longitud"),
    yaxis = list(title = "Latitud")
  )

Figura 2.8:Mapa de precios por ubicacion

El mapa de precios permite visualizar la distribución espacial del valor de las viviendas dentro de la zona sur. Se observa que los precios más altos se concentran en un sector específico, mientras que la mayoría de los inmuebles presentan valores moderados y se agrupan en un área central bien delimitada. No se aprecia un patrón definido asociado a la longitud, ya que los valores elevados aparecen dispersos horizontalmente. En conjunto, el gráfico confirma que la ubicación influye parcialmente en el precio, pero esta relación está determinada sobre todo por la latitud y por focos residenciales puntuales de mayor valorización.

Estimación del Modelo lineal Multiple

En este apartado se estimarán varios modelos de regresión lineal múltiple, con el objetivo de identificar aquel que presente mejores indicadores de ajuste y significancia estadística. Para ello, se proponen diferentes modelos considerando las variables que mostraron mayor asociación con el precio en el análisis de correlación previo:

  • Modelo 1 \[ \text{precio}_i = \beta_0 + \beta_1 (\text{área})_i + \varepsilon_i \tag{2} \]

  • Modelo 2 \[ \text{precio}_i = \beta_0 + \beta_1 (\text{área})_i + \beta_2 (\text{Estrato_F})_i + \varepsilon_i \tag{3} \]

  • Modelo 3 \[ \text{precio}_i = \beta_0 + \beta_1 (\text{área})_i + \beta_2 (\text{Estrato_F})_i +\beta_3 (\text{Nro_Baños})_i+ \varepsilon_i \tag{4} \]

  • Modelo 4 \[ \text{precio}_i = \beta_0 + \beta_1 (\text{área})_i + \beta_2 (\text{Estrato_F})_i +\beta_3 (\text{Nro_Baños})_i+ \beta_4(\text{Latitud})_i+ \varepsilon_i \tag{5} \]

  • Modelo Full

\[ \begin{aligned} \text{precio}_i =\; & \beta_0 + \beta_1 (\text{Área})_i + \beta_2 (\text{Estrato}_F)_i + \beta_3 (\text{Nro\_Baños})_i \\ & + \beta_4 (\text{Latitud})_i + \beta_5 (\text{Nro\_Habitaciones})_i + \varepsilon_i \end{aligned} \tag{6} \]

Utilizaremos la variable de estrato como factor, con ello tenemos los siguientes resultados:

df_sur3$estrato_f <- as.factor(df_sur3$estrato)

modelo_full <- lm(preciom ~ areaconst + banios + habitaciones + estrato_f  + latitud,
                  data = df_sur3)
modelo_1 <- lm(preciom ~ areaconst, data = df_sur3)

modelo_2 <- lm(preciom ~ areaconst + estrato_f, data = df_sur3)

modelo_3 <- lm(preciom ~ areaconst + estrato_f + banios, data = df_sur3)

modelo_4 <- lm(preciom ~ areaconst + estrato_f + banios + latitud, data = df_sur3)

modelo_5 <- modelo_full   # modelo final seleccionado por Stepwise
options(modelsummary_factory_default = "kableExtra")
options(modelsummary_factory_html = "kableExtra")

modelsummary(
  list(
    "Modelo 1" = modelo_1,
    "Modelo 2" = modelo_2,
    "Modelo 3" = modelo_3,
    "Modelo 4" = modelo_4,
    "Modelo Full" = modelo_5
  ),
  statistic = c("({std.error})", "{p.value}"),
  stars = TRUE,
  escape = FALSE,   
  title = "**Tabla VIII.** Comparación de Modelos de Regresión Múltiple"
)
Tabla VIII. Comparación de Modelos de Regresión Múltiple
Modelo 1  Modelo 2  Modelo 3  Modelo 4 Modelo Full
(Intercept) 28.295*** 10.059 -38.836*** 2876.992*** 2774.803***
(5.321) (8.001) (8.233) (356.074) (357.738)
<0.001 0.209 <0.001 <0.001 <0.001
areaconst 2.759*** 1.909*** 1.477*** 1.518*** 1.537***
(0.048) (0.044) (0.050) (0.049) (0.050)
<0.001 <0.001 <0.001 <0.001 <0.001
estrato_f4 48.158*** 28.788*** 21.782** 19.657*
(8.058) (7.781) (7.727) (7.759)
<0.001 <0.001 0.005 0.011
estrato_f5 86.827*** 58.023*** 48.633*** 46.936***
(8.204) (8.032) (8.010) (8.026)
<0.001 <0.001 <0.001 <0.001
estrato_f6 295.970*** 239.300*** 206.305*** 202.656***
(9.492) (9.736) (10.419) (10.498)
<0.001 <0.001 <0.001 <0.001
banios 47.522*** 46.066*** 49.304***
(3.008) (2.974) (3.213)
<0.001 <0.001 <0.001
latitud -858.638*** -822.200***
(104.828) (105.604)
<0.001 <0.001
habitaciones -9.765**
(3.692)
0.008
Num.Obs. 2494 2494 2494 2494 2494
R2 0.567 0.738 0.762 0.768 0.769
R2 Adj. 0.567 0.738 0.762 0.768 0.768
AIC 31205.6 29957.4 29721.0 29656.6 29651.6
BIC 31223.1 29992.4 29761.8 29703.2 29704.0
Log.Lik. -15599.793 -14972.723 -14853.499 -14820.305 -14816.800
F 3266.639 1755.286 1594.415 1375.156 1182.547
RMSE 125.96 97.96 93.39 92.15 92.02
+ p < 0.1, * p < 0.05, ** p < 0.01, *** p < 0.001

Al comparar los cuatro modelos estimados (Tabla VIII), se observa una mejora progresiva en el ajuste conforme se incorporan nuevas variables explicativas. El Modelo Full presenta el mejor desempeño en algunos indicadores de ajuste, aunque las diferencias respecto al Modelo 4 son mínimas.

En primer lugar, el Modelo Full muestra la mayor capacidad explicativa, con un \(R^2\)=0.769 y un \(R^2_{adj}\) de 0.768, los valores más altos entre los modelos estimados, lo que indica que explica la mayor proporción de la variabilidad observada en el precio de los apartamentos. Asimismo, registra el menor error de predicción, con un RMSE de 92.02, lo que sugiere predicciones ligeramente más precisas. En términos de criterios de información, el modelo Full presenta el menor AIC (29651.6), mientras que el BIC es ligeramente menor en el Modelo 4 (29703 frente a 29704), lo cual favorece al modelo más parsimonioso al penalizar la inclusión de variables adicionales.

No obstante, la mejora obtenida respecto al Modelo 4 es marginal en todos los indicadores. Por ejemplo, el \(R^2_{adj}\) se mantiene prácticamente igual (0.768), mientras que la reducción en el RMSE es mínima (92.15 frente a 92.02). Además, el Modelo Full incorpora la variable habitaciones con un coeficiente negativo, lo que implicaría que, manteniendo constantes las demás variables, un mayor número de habitaciones estaría asociado con una disminución en el precio del inmueble. Aunque este resultado puede explicarse por posibles efectos de colinealidad con el área construida u otras características del inmueble, su interpretación económica resulta menos clara dentro de la lógica del mercado inmobiliario.

En este contexto, se opta por seleccionar el Modelo 4 como especificación final, ya que ofrece un equilibrio adecuado entre capacidad explicativa, estabilidad estadística y parsimonia, manteniendo prácticamente el mismo nivel de ajuste que el modelo completo, pero con una estructura más simple y con coeficientes más coherentes desde el punto de vista económico. Adicionalmente, en el Modelo 4 todas las variables incluidas resultan estadísticamente significativas al 5% o mejor, lo que indica que cada una aporta información relevante para explicar el comportamiento del precio. En particular, el área construida, los niveles de estrato, el número de baños y la latitud muestran coeficientes significativos y coherentes con la dinámica del mercado inmobiliario, reforzando la validez del modelo seleccionado.

Siendo así, el modelo queda expresado de la siguiente forma:

\[ \text{precio}_i = 2876.992 + 1.518 \cdot (\text{área}_i) + 21.782 \cdot (\text{estrato_f4}_i) + 48.633 \cdot (\text{estrato_f5}_i) + 206.305\cdot (\text{estrato_f6}_i) \\[6pt] \quad + 46.066 \cdot (\text{baños}_i) - 855.638 \cdot (\text{latitud}_i) + \varepsilon_i \tag{7} \]

El área construida se consolida como el principal determinante del precio de los apartamentos, incrementando en promedio 1.518 millones de pesos por cada metro cuadrado adicional. Este resultado es consistente con la lógica del mercado inmobiliario, donde el tamaño del inmueble constituye uno de los factores más influyentes en su valoración.

El estrato socioeconómico también presenta un efecto significativo sobre el precio. Tomando como referencia el estrato 3, los apartamentos ubicados en estrato 4, 5 y 6 aumentan su valor en aproximadamente 21.8, 48.6 y 206.3 millones de pesos, respectivamente. Estas diferencias reflejan claramente la segmentación socioeconómica del mercado inmobiliario y la valorización asociada a zonas con mayores niveles de ingreso y mejores condiciones urbanas.

En cuanto a las características internas del inmueble, el número de baños muestra un efecto positivo relevante, incrementando el precio en aproximadamente 46 millones de pesos por cada baño adicional. Este resultado sugiere que una mayor dotación de servicios internos es percibida como un atributo de mayor calidad y confort, lo cual se refleja en el valor de mercado de los apartamentos.

Por su parte, la latitud presenta un coeficiente negativo significativo, lo que indica que la ubicación geográfica dentro del sector sur continúa influyendo en la valorización de los inmuebles. Este resultado sugiere que pequeñas variaciones en la localización dentro de la zona analizada pueden estar asociadas a diferencias en accesibilidad, calidad del entorno urbano o cercanía a zonas con mayor valorización.

En conjunto, el modelo integra adecuadamente factores físicos, socioeconómicos y espaciales, permitiendo explicar de forma consistente el comportamiento del precio de los apartamentos en el sur de la ciudad. El Modelo 4 presenta un ajuste sólido (\(R^2\)=0.768), lo que indica que logra explicar cerca del 77% de la variabilidad observada en los precios, un resultado adecuado para datos inmobiliarios caracterizados por alta heterogeneidad. No obstante, aún existe una fracción de variabilidad no explicada (23%), lo cual sugiere oportunidades de mejora mediante la incorporación de variables adicionales relacionadas con características del inmueble y su entorno, como antigüedad, nivel del apartamento, presencia de ascensor, ubicación dentro del barrio o cercanía a equipamientos urbanos y vías principales, lo que podría fortalecer la capacidad predictiva del modelo.

Como paso final, se evaluará la colinealidad entre los predictores mediante el índice VIF, con el propósito de verificar que las variables incluidas en el modelo no presenten redundancias significativas y que los coeficientes estimados puedan interpretarse de manera estable y confiable.

vif(modelo_4)
##               GVIF Df GVIF^(1/(2*Df))
## areaconst 1.950959  1        1.396767
## estrato_f 2.053434  3        1.127405
## banios    2.219952  1        1.489950
## latitud   1.408696  1        1.186885

El análisis de colinealidad mediante el índice VIF muestra que todas las variables presentan valores bajos (\(GVIF^{\frac{1}{2Df}}\) entre 1.13 y 1.49), muy por debajo de los umbrales comúnmente utilizados para detectar problemas de multicolinealidad. Esto indica que los predictores del modelo no presentan redundancias importantes y que los coeficientes estimados pueden interpretarse de manera estable. En consecuencia, estos resultados respaldan la adecuada especificación del Modelo 4, confirmándolo como la alternativa más apropiada para explicar el precio de los apartamentos en el conjunto de datos analizado.

Validación de supuestos del modelo

En esta etapa se examinan los supuestos clásicos de la regresión lineal múltiple asociados al Modelo 4, con el objetivo de verificar la validez de las inferencias derivadas del modelo. En caso de detectarse posibles desviaciones, estas se reportarán junto con recomendaciones metodológicas, sin realizar ajustes adicionales en esta fase del análisis.

residuos <- residuals(modelo_4)
ajustados <- fitted(modelo_4)

#normalidad
shapiro_test <- shapiro.test(residuos)

#media=0
t_test <- t.test(residuos, mu = 0)

#vaianzas constantes
bp_test <- bptest(modelo_4)

#independencia
dw_test <- dwtest(modelo_4)
tabla_supuestos <- tibble(
  Supuesto = c(
    "Normalidad de los errores",
    "Media cero de los errores",
    "Homocedasticidad",
    "Independencia de los errores"
  ),
  Prueba = c(
    "Shapiro-Wilk",
    "t-test (mu=0)",
    "Breusch-Pagan",
    "Durbin-Watson"
  ),
  Estadístico = c(
    round(shapiro_test$statistic, 4),
    round(t_test$statistic, 4),
    round(bp_test$statistic, 4),
    round(dw_test$statistic, 4)
  ),
  `p-value` = c(
    formatC(shapiro_test$p.value, format="e", digits=2),
    round(t_test$p.value, 4),
    round(bp_test$p.value, 4),
    round(dw_test$p.value, 4)
  )
)

tabla_supuestos %>%
  kable(
    caption = "Tabla IX. Validación de supuestos del modelo",
    align = "c"
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE,
    position = "center"
  )
Tabla IX. Validación de supuestos del modelo
Supuesto Prueba Estadístico p-value
Normalidad de los errores Shapiro-Wilk 0.7382 1.18e-52
Media cero de los errores t-test (mu=0) 0.0000 1
Homocedasticidad Breusch-Pagan 860.8863 0
Independencia de los errores Durbin-Watson 1.7098 0

Los resultados presentados en la Tabla IX permiten evaluar el cumplimiento de los supuestos clásicos de la regresión lineal asociados al Modelo 4 (ecuación 7).

En primer lugar, el test de Shapiro–Wilk (W = 0.738, p < 0.001) indica que los residuos no siguen una distribución normal. Este resultado es frecuente en bases de datos con gran número de observaciones, donde pequeñas desviaciones respecto a la normalidad tienden a ser detectadas por las pruebas formales. En este contexto, la ausencia de normalidad no compromete de manera crítica la validez del modelo, especialmente considerando el tamaño muestral elevado (n ≈ 2500) y el respaldo del Teorema Central del Límite, que permite mantener inferencias razonablemente confiables sobre los coeficientes estimados.

Por otra parte, el t-test para la media de los errores confirma que la media de los residuos no difiere significativamente de cero (p = 1), cumpliéndose el supuesto \(E(\varepsilon_i) = 0\). Este resultado sugiere que el modelo no presenta sesgos sistemáticos en la estimación del precio y que las predicciones se encuentran correctamente centradas alrededor de los valores observados.

En cuanto a la homocedasticidad, el test de Breusch–Pagan (p < 0.001) evidencia la presencia de heterocedasticidad significativa, lo que indica que la varianza de los errores no es constante a lo largo del rango de valores predichos. Este comportamiento es común en modelos inmobiliarios, donde viviendas de mayor valor suelen presentar mayor dispersión en los precios observados. Ante esta situación, es recomendable complementar el análisis utilizando errores estándar robustos (tipo White o HC), lo que permitiría obtener inferencias más confiables sin modificar la estructura del modelo.

Finalmente, el estadístico de Durbin–Watson (DW = 1.71) sugiere que no existe una autocorrelación fuerte entre los residuos. Aunque el p-value reportado indica cierta dependencia estadística, el valor del estadístico se mantiene relativamente cercano a 2, lo que permite considerar que el supuesto de independencia de los errores se cumple de forma razonable para los fines del análisis.

En conjunto, los resultados muestran que el modelo presenta un comportamiento globalmente adecuado, aunque se identifican desviaciones respecto a los supuestos de normalidad y homocedasticidad. Estas situaciones no invalidan el modelo, pero sugieren posibles mejoras metodológicas. Entre las recomendaciones se encuentran la utilización de errores estándar robustos, la evaluación de transformaciones en la variable precio (por ejemplo, logaritmos) o la incorporación de variables adicionales relacionadas con características del inmueble y del entorno urbano. Estas estrategias podrían contribuir a mejorar la estabilidad de las estimaciones y fortalecer la capacidad explicativa del modelo.

Validación del modelo

  • Validacion Simple

Siguiendo la misma metodología empleada en el análisis anterior, se realiza una validación simple del modelo estimado para los apartamentos del sur de la ciudad de Cali, con el fin de evaluar su capacidad predictiva sobre datos no utilizados en la estimación.

set.seed(123)   # para reproducibilidad

# 1) Número total de observaciones
n1 <- nrow(df_sur3)

# 2) Seleccionar ~70% para entrenamiento
train1 <- sample(1:n1, size = floor(0.7 * n))

# 3) Estimar el modelo SOLO con la muestra de entrenamiento
modelo_train1 <- lm(formula(modelo_4),
                   data = df_sur3[train1, ])

summary(modelo_train1)
## 
## Call:
## lm(formula = formula(modelo_4), data = df_sur3[train1, ])
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -673.26  -46.51   -4.35   38.54  896.96 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 1406.3503  1018.3002   1.381  0.16798    
## areaconst      0.7798     0.1021   7.635 1.52e-13 ***
## estrato_f4    33.9565    19.5192   1.740  0.08265 .  
## estrato_f5    60.6526    20.4610   2.964  0.00321 ** 
## estrato_f6   257.8425    27.3738   9.419  < 2e-16 ***
## banios        70.0753     7.3252   9.566  < 2e-16 ***
## latitud     -424.4105   299.5823  -1.417  0.15731    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 99.44 on 423 degrees of freedom
## Multiple R-squared:  0.746,  Adjusted R-squared:  0.7424 
## F-statistic:   207 on 6 and 423 DF,  p-value: < 2.2e-16
# 4) Predecir en la muestra de validación
predicciones1 <- predict(
  modelo_train1, 
  newdata = df_sur3[-train1, ]
)

# 5) Calcular el error cuadrático medio (MSE)
error_mse1 <- mean((df_sur3$preciom[-train1] - predicciones1)^2)

# RMSE
error_rmse1 <- sqrt(error_mse1)

# Correlación entre Y observado y Ŷ
cor_yyhat1 <- cor(df_sur3$preciom[-train1], predicciones1)

data.frame(
  MSE_validacion_simple  = error_mse1,
  RMSE_validacion_simple = error_rmse1,
  Correlacion_Y_Yhat     = cor_yyhat1
)
##   MSE_validacion_simple RMSE_validacion_simple Correlacion_Y_Yhat
## 1              9268.619               96.27367          0.8632441

Los resultados de la validación simple muestran que el modelo mantiene un comportamiento estable cuando se aplica a datos no utilizados en la estimación. Al reestimar el modelo con el 70% de la muestra, el coeficiente de determinación se mantiene en \(R^2\)=0.746, valor cercano al obtenido con la base completa (\(R^2\)=0.768), lo que sugiere que la capacidad explicativa del modelo se conserva.

En términos predictivos, el modelo presenta un RMSE de 96.27 millones sobre la muestra de validación, un valor muy cercano al error obtenido en la estimación original (RMSE = 92.15), lo que indica que el desempeño predictivo se mantiene fuera de la muestra. Asimismo, la correlación entre los valores observados y predichos alcanza r=0.863, evidenciando una fuerte asociación entre ambos.

En conjunto, estos resultados confirman que el Modelo 4 presenta una adecuada capacidad de generalización, no evidencia sobreajuste significativo y puede utilizarse de manera confiable para apoyar la estimación del precio de apartamentos en el sur de la ciudad.

Predecir el precio (a partir del modelo elegido)

Con el modelo elegido (modelo_4) debemos predecir el precio de la vivienda con las características de la segunda solicitud, en este caso, recordemos que tenemos:

  • Area construida= 300
  • Baños= 3
  • Habitaciones= 5
  • Estrato= 5 o 6
  • parqueaderos= 3

Importante: Aunque la solicitud de la vivienda incluye variables como el número de habitaciones y el número de parqueaderos, estas no se incorporan en el modelo final seleccionado. En el caso de habitaciones, durante el proceso de estimación se observó que su inclusión no mejoraba de manera sustancial el ajuste del modelo y, además, generaba un coeficiente negativo difícil de interpretar desde la lógica del mercado inmobiliario. Por su parte, la variable parqueaderos fue excluida previamente del análisis debido al alto porcentaje de datos faltantes en la base de apartamentos del sur, lo que impedía realizar una imputación confiable sin introducir posibles sesgos en la estimación.

En consecuencia, el modelo final explica el precio principalmente a partir de variables estructurales más robustas, como el área construida, el estrato socioeconómico, el número de baños y la localización geográfica, por lo que la predicción del precio se realiza únicamente utilizando las variables incluidas en la especificación final del modelo.

Por otro lado, aunque la variable latitud no aparece explícitamente en la solicitud original de la vivienda, esta fue incorporada en el modelo final tras resultar estadísticamente significativa durante el proceso de selección del mejor modelo. Para generar una predicción coherente, se asignó un valor representativo del sector sur de la ciudad. En particular, se utiliza la latitud 3.38, correspondiente aproximadamente al valor promedio observado en el conjunto de datos depurado (Tabla VII) y ubicado dentro del rango de localización de los apartamentos analizados.

En consecuencia, para el caso en que la vivienda se ubica en el estrato 5, la ecuación del modelo se reduce a:

# Nueva vivienda - estrato 5
nueva_viv2 <- data.frame(
  areaconst    = 300,
  estrato_f    = factor("5", levels = levels(df_sur3$estrato_f)),
  banios       = 3,
  latitud     = 3.38
)

pred_estrato5_sur <- predict(
  modelo_4,
  newdata  = nueva_viv2,
  interval = "prediction",
  level    = 0.95
)

pred_estrato5_sur
##        fit      lwr      upr
## 1 616.9361 434.9837 798.8885

Mientras que para el Estrato 6, tenemos:

# Cambiar solo estrato
nueva_viv2$estrato_f <- factor("6", levels = levels(df_sur3$estrato_f))

pred_estrato6_sur <- predict(
  modelo_4,
  newdata  = nueva_viv2,
  interval = "prediction",
  level    = 0.95
)

pred_estrato6_sur
##        fit      lwr      upr
## 1 774.6079 592.6522 956.5636

Los resultados muestran que, para apartamentos del sur de Cali, con 300 m², 3 baños y ubicada en una latitud representativa del sur (3.38), el precio estimado varía de manera importante según el estrato socioeconómico. Para estrato 5, el modelo predice un valor aproximado de 616 millones de pesos, con un intervalo de confianza al 95% que oscila entre 434 millones y 798 millones. Esta amplitud refleja la heterogeneidad propia del mercado medio-alto de la zona, donde las diferencias en acabados, ubicación y características del conjunto residencial generan variabilidad en los precios.

En el caso del estrato 6, el valor esperado se incrementa hasta aproximadamente 774 millones de pesos, con un intervalo de confianza al 95% que va de 592 millones a 956 millones. Este aumento es coherente con el efecto estimado para el estrato 6 en el modelo.

Selección de ofertas potenciales

A partir de la predicción obtenida con el modelo de regresión, se identificaran las ofertas del mercado que se ajustan a las características solicitadas para la Vivienda Tipo 2. Considerando que la empresa cuenta con un crédito preaprobado de hasta 850 millones de pesos, se filtran aquellas alternativas cuyo precio se encuentra dentro de este límite y que cumplen con los principales atributos estructurales y socioeconómicos requeridos.

En particular, se seleccionan las viviendas que cumplen con las siguientes condiciones:

  • Precio<= 850 millones
  • Area construida de 300 metros o más
  • Baños, al menos 3
  • Estrato 5 o 6

Cabe señalar que, aunque la solicitud inicial incluye el número de habitaciones, este atributo no se utilizara como criterio de filtrado estricto en esta etapa con el fin de ampliar el conjunto de alternativas disponibles en el mercado. Posteriormente, dentro de las viviendas que cumplen los criterios principales, se identificaran aquellas que presentan una configuración interna más cercana al perfil solicitado.

Aplicando estos criterios, se obtuvieron el top de ofertas potenciales que se ajustan de manera razonable a las condiciones establecidas y que se presentan a continuación:

# Filtrar viviendas que cumplan los criterios del cliente

ofertas_filtradas_sur <- df_sur3 %>%
  filter(
    preciom <= 850,         # dentro del presupuesto
    areaconst >= 300,  # rango razonable alrededor de 200 m2
    banios >= 3,
    estrato_f %in% c("5", "6")
  )
# Seleccionar las 5 viviendas más cercanas al perfil
ofertas_top5_sur <- ofertas_filtradas_sur %>%
  arrange(abs(areaconst - 200)) %>%
  slice(1:5)
plot_ly(
  ofertas_top5_sur,
  type = "scattermapbox",
  lon = ~longitud,
  lat = ~latitud,
  mode = "markers",
  marker = list(size = 12, color = "blue"),
  text = ~paste("Precio:", preciom, "millones<br>",
                "Área:", areaconst, "m²<br>",
                "Estrato:", estrato_f, "<br>",
                "Baños:", banios, "<br>",
                "Habitaciones:", habitaciones)
) %>%
  layout(
    mapbox = list(
      style = "open-street-map",
      zoom = 12,
      center = list(lon = -76.52, lat = 3.45)
    ),
    title = "Ofertas potenciales para la Vivienda Tipo 2"
  )

En este caso se identificaron cuatro ofertas de viviendas que cumplen con las características principales solicitadas. De estas, una oferta satisface completamente todos los criterios establecidos, incluyendo el requerimiento de cinco habitaciones. Por su parte, dos de las viviendas presentan cuatro habitaciones, por lo que solo incumplen parcialmente este atributo, mientras que una vivienda cuenta con tres habitaciones, alejándose en mayor medida de la configuración interna solicitada. No obstante, todas las alternativas cumplen con las condiciones principales relacionadas con precio, área construida, número de baños y estrato, lo que las convierte en opciones potenciales para considerar dentro del proceso de selección.

Conclusiones y Recomendaciones

Conclusiones generales del análisis

El análisis realizado permitió evaluar el comportamiento del precio de la vivienda en la ciudad de Cali a partir de variables estructurales y de localización incluidas en la base de datos. Mediante un proceso sistemático de depuración, exploración y modelación estadística, se identificaron los factores que presentan mayor relación con el valor de los inmuebles, permitiendo estimar rangos de precios plausibles para las viviendas solicitadas por el cliente.

Durante la etapa de preparación de los datos fue necesario excluir algunas variables del análisis con el fin de garantizar la consistencia del modelo. En particular, la variable barrio no fue incorporada en la modelación debido a que presenta un número muy elevado de categorías (más de 300 barrios diferentes). La inclusión de esta variable en un modelo de regresión implicaría generar una gran cantidad de variables dummy, lo cual podría provocar problemas de sobreparametrización, pérdida de grados de libertad y dificultades en la interpretación de los resultados. Además, la información espacial ya se encuentra parcialmente representada a través de las variables latitud y longitud, que permiten capturar la ubicación geográfica de los inmuebles de manera continua y más parsimoniosa.

Por otra parte, la variable estrato socioeconómico fue incorporada en el modelo como una variable categórica (factor) en lugar de tratarse como una variable numérica continua. Esta decisión metodológica permite capturar de forma más adecuada las diferencias estructurales existentes entre los distintos niveles socioeconómicos de la ciudad, evitando asumir que el efecto de pasar de un estrato a otro es necesariamente lineal o proporcional. Al modelar el estrato como factor, el modelo estima efectos específicos para cada categoría, lo que facilita interpretar cómo cambian los precios de la vivienda entre distintos niveles socioeconómicos y permite representar de forma más realista la segmentación del mercado inmobiliario urbano.

En consecuencia, el modelo final (estimado para ambos tipos de viviendas) se construyó utilizando variables estructurales de la vivienda (área construida, número de habitaciones, número de baños y estrato) junto con variables de localización geográfica, lo cual permitió obtener estimaciones razonables del precio de mercado y comprender de manera más integral los factores que determinan la valorización de los inmuebles en la ciudad.

Conclusiones por tipo de vivienda

Vivienda Tipo 1 – Casa Zona Norte

Para el caso de la vivienda tipo 1 (casa ubicada en la zona norte), el modelo de regresión múltiple permitió estimar el precio esperado considerando las características solicitadas por la empresa. Los resultados muestran que el estrato socioeconómico ejerce un efecto positivo sobre el valor estimado del inmueble, observándose un incremento en la predicción del precio al pasar de estrato 4 a estrato 5. Este comportamiento es consistente con la estructura del mercado inmobiliario urbano, donde la valorización de las viviendas se encuentra fuertemente asociada al nivel socioeconómico del entorno.

Adicionalmente, el modelo evidencia que el área construida es uno de los determinantes más importantes del precio de las viviendas, lo cual refleja la lógica del mercado inmobiliario: a mayor tamaño del inmueble, mayor es su valoración económica. Este resultado confirma que el espacio habitable constituye uno de los atributos más valorados por los compradores, ya que está directamente relacionado con la funcionalidad y el confort de la vivienda.

De manera complementaria, el número de baños también presenta un efecto positivo sobre el precio estimado, lo cual sugiere que la disponibilidad de servicios sanitarios adicionales incrementa el valor percibido del inmueble. Este tipo de características estructurales suelen ser altamente valoradas por las familias, ya que mejoran la habitabilidad y el nivel de comodidad dentro de la vivienda.

Las estimaciones obtenidas indican que el precio esperado se ubica aproximadamente entre 342 y 388 millones de pesos, dependiendo del estrato considerado. Este rango constituye una referencia cuantitativa útil para la toma de decisiones, ya que permite evaluar si las ofertas disponibles en el mercado se encuentran dentro de niveles razonables de valorización.

Adicionalmente, el modelo identificó un componente espacial relevante asociado a la variable longitud, lo que sugiere que la ubicación dentro de la zona norte también influye en la formación del precio. Este resultado evidencia que, incluso dentro de una misma zona urbana, existen diferencias de valorización entre barrios, asociadas a factores como accesibilidad, entorno urbano y calidad del equipamiento.

En conjunto, los resultados sugieren que el precio de las casas en la zona norte se explica principalmente por factores estructurales del inmueble (tamaño y número de baños), complementados por variables socioeconómicas y espaciales, lo que permite identificar con mayor precisión las características que determinan el valor de mercado de este tipo de vivienda.

Vivienda Tipo 2 – Apartamento

En el caso de la vivienda tipo 2 (apartamento), el análisis exploratorio y la modelación permitieron identificar patrones similares a los observados en las casas, aunque con particularidades propias de este tipo de inmueble.

En los apartamentos, variables como el área construida y el estrato socioeconómico continúan siendo determinantes importantes en la formación del precio. El modelo confirma que el área construida tiene un impacto positivo y significativo sobre el valor del inmueble, lo cual evidencia que el tamaño del apartamento constituye uno de los factores más influyentes en la valorización dentro del mercado inmobiliario.

Asimismo, el número de baños también contribuye positivamente a la formación del precio, ya que incrementa la funcionalidad y el nivel de confort del inmueble. Este resultado es consistente con la lógica del mercado residencial, donde los compradores valoran viviendas que ofrecen mayor comodidad y mejor distribución de los espacios.

El modelo de regresión múltiple permitió estimar precios esperados plausibles para apartamentos con las características solicitadas, proporcionando una referencia cuantitativa del valor de mercado. En particular, el modelo estima un precio aproximado de 616 millones de pesos para el estrato 5 y de 774 millones para el estrato 6, lo cual evidencia el impacto significativo que tiene el nivel socioeconómico del sector en la valorización final del inmueble.

Adicionalmente, la variable latitud capturó parte de la variabilidad espacial en los precios, indicando que incluso dentro de la zona sur existen gradientes territoriales de valorización que influyen en el valor de las propiedades. Esto sugiere que algunos sectores dentro de la zona presentan mayores niveles de valorización, posiblemente asociados a mejores condiciones urbanísticas o mayor proximidad a servicios y equipamientos urbanos.

Finalmente, el filtrado de la base de datos permitió identificar las ofertas disponibles que cumplen con las condiciones establecidas por el cliente. Sin embargo, el número reducido de alternativas encontradas sugiere que la combinación de características solicitadas —especialmente área, número de habitaciones, estrato y presupuesto— restringe considerablemente el conjunto de viviendas disponibles en el mercado.

Recomendaciones

Recomendaciones metodológicas (del procedimiento)

A partir del análisis realizado, se pueden proponer algunas recomendaciones para mejorar futuros estudios sobre el mercado inmobiliario:

  1. Mejorar la calidad y consistencia de los datos: Durante el proceso de depuración se identificaron inconsistencias en algunas variables (por ejemplo, valores iguales a cero en baños y habitaciones, alto numero de valores faltantes en parqueaderos y piso). En futuros análisis se recomienda implementar reglas de validación desde la captura de los datos para evitar este tipo de registros.

  2. Ampliar el conjunto de variables explicativas: Para mejorar la capacidad predictiva del modelo, sería conveniente incluir variables adicionales como:

    • antigüedad del inmueble
    • estado de conservación
    • cercanía a servicios urbanos
    • características del conjunto residencial.
  3. Evaluar modelos complementarios: Aunque la regresión múltiple proporciona interpretabilidad, en contextos inmobiliarios también podrían explorarse métodos como árboles de decisión o Random Forest, que capturan relaciones no lineales entre las variables.

Recomendaciones para el cliente (empresa inmobiliaria)

Desde el punto de vista del cliente que busca adquirir las viviendas, se sugieren las siguientes consideraciones:

  1. Flexibilizar algunas características de búsqueda: El número reducido de alternativas encontradas sugiere que las condiciones establecidas (especialmente número de habitaciones o área mínima) restringen considerablemente el mercado disponible. Ajustar ligeramente estos criterios podría ampliar las opciones de compra.

  2. Considerar la influencia del estrato en el presupuesto: El análisis evidencia que el estrato tiene un impacto importante en el precio de las viviendas. En consecuencia, pequeñas variaciones en esta variable pueden generar diferencias significativas en el valor final del inmueble.

  3. Utilizar intervalos de predicción como referencia de mercado: Los intervalos de predicción obtenidos permiten estimar el rango en el que podría ubicarse el precio real de viviendas con características similares. Esto constituye una herramienta útil para negociar precios y evaluar si una oferta está sobrevalorada o subvalorada.

  4. Evaluar la ubicación dentro de la zona: Aunque el análisis se centró en características estructurales, la ubicación específica dentro de cada zona puede influir significativamente en el valor del inmueble, por lo que se recomienda complementar el análisis estadístico con una evaluación cualitativa del entorno urbano.

Cierre del análisis

En conjunto, el estudio desarrollado proporciona una aproximación cuantitativa al comportamiento del mercado inmobiliario en la ciudad de Cali, permitiendo identificar cómo variables estructurales de la vivienda y factores socioeconómicos influyen en la determinación de su precio. A partir del proceso de depuración, exploración y modelación mediante regresión múltiple, fue posible estimar rangos de precios plausibles para viviendas con características específicas, así como identificar alternativas disponibles en el mercado que se ajustan a los requerimientos planteados por el cliente.

Más allá de la estimación puntual del precio, el uso de intervalos de predicción permitió incorporar la variabilidad inherente al mercado inmobiliario, caracterizado por una alta heterogeneidad en atributos físicos, ubicación y condiciones del entorno urbano. De esta manera, el modelo no solo aporta una estimación promedio, sino también un marco probabilístico que facilita una evaluación más realista del valor esperado de los inmuebles.

En términos prácticos, los resultados obtenidos constituyen una herramienta de apoyo para la toma de decisiones inmobiliarias, ya que permiten contrastar las características deseadas por el cliente con la oferta real del mercado y evaluar la viabilidad de las alternativas disponibles dentro del presupuesto establecido. Asimismo, el análisis evidencia la importancia de considerar simultáneamente factores estructurales y socioeconómicos en la valoración de viviendas, lo cual resulta fundamental para diseñar estrategias de búsqueda, negociación y selección de inmuebles en un mercado urbano dinámico.