Enunciado

Maria comenzó como agente de bienes raíces en Cali hace 10 años. Después de laborar dos años para una empresa nacional, se traslado a Bogotá y trabajó para otra agencia de bienes raíces. Sus amigos y familiares la convencieron de que con su experiencia y conocimientos del negocio debía abrir su propia agencia. Terminó por adquirir la licencia de intermediario y al poco tiempo fundó su propia compañía, C&A (Casas y Apartamentos) en Cali. Santiago y Lina, dos vendedores de la empresa anterior aceptaron trabajar en la nueva compaña. En la actualidad ocho agentes de bienes raíces colaboran con ella en C&A.

Actualmente las ventas de bienes raíces en Cali se han visto disminuidas de manera significativa en lo corrido del año. Durante este periodo muchas instituciones bancarias de ahorro y vivienda están prestando grandes sumas de dinero para la industria y la construcción comercial y residencial. Cuando el efecto producto de las tensiones políticas y sociales disminuya, se espera que la actividad económica de este sector se reactive.

Hace dos días, María recibió una carta solicitando asesoría para la compra de dos viviendas por parte de una compañía internacional que desea ubicar a dos de sus empleados con sus familias en la ciudad.

Las solicitudes incluyen las siguientes condiciones:

Características Vivienda 1 Vivienda 2
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
Crédito preaprobado 350 millones 850 millones

Ayude a María a responder la solicitud, mediante técnicas de modelación que usted conoce. Ella requiere le envíe un informe ejecutivo donde analice los dos casos y sus recomendaciones (Informe). Como soporte del informe debe anexar las estimaciones, validaciones y comparación de modelos requeridos (Anexos) .

Anexos

Preparación de Datos

#install.packages("devtools") # solo la primera vez
#devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
library(paqueteMODELOS)
library(dplyr)
library(summarytools)
library(knitr)
library(corrplot)
library(cluster)
library(factoextra)
library(FactoMineR)
library(leaflet)
library(plotly)
library(lmtest)
library(DT)
library(Metrics)
data("vivienda")

Se inicia con la preparación de datos definida en la Actividad 1, en la cual se realizan los siguientes ajustes:

  1. Reclasificar la variable piso como discreta.

  2. Reclasificar la variable estrato como categórica.

  3. Eliminar los 3 registros en los que se observa que en dos de ellos hay 13 variables sin datos y en el otro registro hay 12 variables sin datos.

  4. Se considera que el valor de 0 baños es inconsistente para una vivienda, por lo que se imputa el valor mínimo de 1 en esos registros.

  5. Imputar los datos faltantes de las variables categóricas y/o discretas con la moda.

#Reclasificar la variable piso como discreta.
vivienda$piso <- as.integer(vivienda$piso)

#Reclasificar la variable estrato como categórica.
vivienda$estrato <- as.character(vivienda$estrato)

# Contar cuántos NA hay por fila
na_por_fila <- apply(is.na(vivienda), 1, sum)

#Eliminación de los 3 registros con mayor cantidad de datos faltantes
v_sna <- vivienda[na_por_fila < 12, ]

#Imputación de los registros con 0 banios
v_sna$banios[v_sna$banios == 0] <- 1

#Imputación de datos faltantes en piso y parqueaderos con la moda
# Función para calcular la moda
moda <- function(x) {
  ux <- na.omit(unique(x))
  ux[which.max(tabulate(match(x, ux)))]
}

# Imputar NA con la moda en todas las columnas que tengan datos faltantes
for (col in names(v_sna)[colSums(is.na(v_sna)) > 0]) {
  v_sna[[col]][is.na(v_sna[[col]])] <- moda(v_sna[[col]])
}

Datos de trabajo

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

Pasos requeridos para la obtención de los resultados Vivienda 1

  1. Realice un filtro a la base de datos e incluya solo las ofertas de : base1: casas, de la zona norte de la ciudad. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta. (Adicional un mapa con los puntos de las bases. Discutir si todos los puntos se ubican en la zona correspondiente o se presentan valores en otras zonas, por que?).

A continuación se presentan los primeros 3 registros de la base filtrada para el análisis de la vivienda 1. Adicionalmente se muestran los valores de las variables zona y tipo para verificar el correcto filtrado de los datos.

v=v_sna[v_sna$zona=="Zona Norte" & v_sna$tipo == "Casa",]
head(v, 3)
## # A tibble: 3 × 13
##      id zona     piso estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <int> <chr>     <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1209 Zona N…     2 5           320       150            2      4            6
## 2  1592 Zona N…     2 5           780       380            2      3            3
## 3  4057 Zona N…     2 6           750       445            1      7            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
#Valores únicos de las variables filtradas
unique(v$zona)
## [1] "Zona Norte"
unique(v$tipo)
## [1] "Casa"

Localización de las casas identificadas en la Zona Norte

# Localización de las casas
leaflet(v) %>%
  addTiles() %>%  # Mapa base
  addCircleMarkers(~longitud, ~latitud,
                   popup = ~as.character(barrio),
                   radius = 4,      # tamaño del punto (puedes probar 2, 3, 5...)
                   color = "blue",  # color del borde
                   fillColor = "lightblue", # color de relleno
                   fillOpacity = 0.7)

Geográficamente las casas clasificadas al Norte de la ciudad, realmente se distribuyen en diferentes zonas. Lo cual puede ocurrir por errores en la digitación de las coordenadas o en la identificación de la zona.

  1. Realice un análisis exploratorio de datos enfocado en la 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. Use gráficos interactivos con el paquete plotly e interprete los resultados.
# Selección de variables de interés, se omite zona ya que solo corresponde a la Zona Norte y se agrega número de parqueaderos al ser mencionada en el punto 3.
df <- v %>% 
  select(id,preciom, areaconst, estrato, banios, habitaciones, parqueaderos)
#Se deja estrato como numérica al ser ordinal
df$estrato <- as.numeric(df$estrato)
  
# Correlaciones numéricas
# Usamos Spearman (robusto a no linealidades y ordinalidad de estrato)
cors <- cor(df[, !(names(df) %in% c("id"))],
            method = "spearman",
            use = "pairwise.complete.obs")

# Heatmap interactivo
heatmap_cor <- plot_ly(
  x = colnames(cors), y = rownames(cors),
  z = cors, type = "heatmap", 
  text = round(cors, 2), hovertemplate = "X: %{x}<br>Y: %{y}<br>rho: %{text}<extra></extra>"
) %>%
  layout(title = "Matriz de correlaciones (Spearman)")

heatmap_cor

Las variables que presentan una correlación fuerte con el precio de la vivienda son el área construida y el estrato. Los baños presentan una correlación positiva un poco menos fuerte, pero a la vez significativa.

No se observa una correlación fuerte por parte de las variables habitaciones y parqueaderos con el precio de la vivienda.

**Análisis bivariado

# Precio vs Área construida
plot_ly(df, x = ~areaconst, y = ~preciom, color = ~estrato,
        type = "scatter", mode = "markers",
        text = ~paste("Estrato:", estrato)) %>%
  layout(title = "Precio vs Área construida (color por estrato)")

Se identifica gráficamente la correlación positiva entre el área construida y el precio de vivienda, evidenciando adicionalmente que los valores extremos de precio y área de viviendas se presentan predominantemente en los estratos 5 y 6.



  1. Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños ) ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deber están contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).
#Modelo de regresión líneal múltiple
mod <- lm(preciom ~ areaconst + estrato + banios + habitaciones + parqueaderos, data = df)
summary(mod)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios + habitaciones + 
##     parqueaderos, data = df)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -941.57  -78.42  -18.26   45.19 1082.73 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -234.54892   29.62212  -7.918 9.21e-15 ***
## areaconst       0.81276    0.04381  18.550  < 2e-16 ***
## estrato        83.90147    7.28818  11.512  < 2e-16 ***
## banios         28.16985    5.46747   5.152 3.33e-07 ***
## habitaciones    0.58410    4.10505   0.142    0.887    
## parqueaderos    5.51724    5.24937   1.051    0.294    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 158.7 on 716 degrees of freedom
## Multiple R-squared:  0.6526, Adjusted R-squared:  0.6501 
## F-statistic: 268.9 on 5 and 716 DF,  p-value: < 2.2e-16

A partir del modelo estimado con las variables de interés se pueden realizar las siguientes afirmaciones:

  • Todas las variables consideradas tienen una relación directa frente al precio de los inmuebles. Es decir, que a medida que aumenta el valor de la variable tambien aumenta en alguna medida el precio de la vivienda.

  • No obstante, para cada variable se presenta el valor p, que permite establecer la influencia real de cada variable en el precio del inmueble. Las variables que realmente influyen en el precio de los inmuebles son areaconst, estrato, y banios. Mientras que habitaciones y parqueaderos no presentan suficiente evidencia de influencia en el precio.

  • Los resultados frente a la influencia en el precio de cada variable, son coherentes frente al análisis de correlaciones en el que no se identificó correlación fuerte por parte de las variables habitaciones y parqueaderos con el precio de la vivienda.

  • El R2= 0,65 indica que el modelo explica el 65% de la variabilidad con las variables consideradas, lo cual indica que hay otros factores relevantes que no se están incluyendo.

  • Algunas mejoras que se pueden realizar al modelo serían eliminar una a una las variables no influyentes para evaluar su aporte real y considerar la inclusión de variables adicionales que recojan la variabilidad que no está siendo explicada y puedan mejorar la predicción.

  1. Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).

Evaluación de los supuestos del modelo

  1. Los errores εi siguen una distribución normal: \[εi∼N(0,σ2)\] Se realiza el análisis sobre los residuales estandarizados y se evalúa la hipótesis de normalidad.
# Obtener residuales estandarizados
residuales_estandarizados <- rstandard(mod)

par(mfrow = c(1, 2))
# Generar el QQ-Plot para evaluar normalidad
qqnorm(residuales_estandarizados, main="QQ-Plot de los Residuales", col="blue",
       cex.main = 1,   # Tamaño del título
       cex.axis = 0.8)
qqline(residuales_estandarizados, col="red", lwd=2)  # Agregar línea de referencia

# Determinar residuos ordinarios y aplicar test de normalidad
ei <- residuals(mod)
shapiro.test(ei)
## 
##  Shapiro-Wilk normality test
## 
## data:  ei
## W = 0.83618, p-value < 2.2e-16

Hipótesis del test de normalidad:

H0: Los errores siguen una distribución normal.

H1: Los errores no siguen una distribución normal.

Al aplicar el test de Shapiro-Wilk se obtiene un valor p menor a 0.05 sobre los residuales del modelo. Por lo tanto, se rechaza la hipótesis nula, evidenciando que los errores no siguen una distribución normal. Esto reafirma lo que evidencia el QQ-Plot al presentar una dispersión en el extremo superior del modelo. Esto puede deberse a una gran presencia de valores atípicos en los precios de las casas de la Zona norte.



2. Los errores tienen varianza constante (homocedasticidad)

#prueba Breusch-Pagan
bptest(mod)
## 
##  studentized Breusch-Pagan test
## 
## data:  mod
## BP = 135.9, df = 5, p-value < 2.2e-16

Prueba de hipótesis:

H0: Los errores tienen varianza constante (homocedasticidad).

H1: Los errores no tienen varianza constante (heterocedasticidad).

Aplicando la prueba de Breusch-Pagan, se rechaza la hipótesis nula, por lo tanto se evidencia la presencia de heterocedasticidad para el modelo.



3. No hay correlación entre los errores (independencia).

# Durbin-Watson Test
# Evalúa si los errores presentan autocorrelación de primer orden
dw_test <- dwtest(mod)
print(dw_test)
## 
##  Durbin-Watson test
## 
## data:  mod
## DW = 1.6212, p-value = 1.353e-07
## alternative hypothesis: true autocorrelation is greater than 0
# Breusch-Godfrey Test
# Permite evaluar autocorrelación de orden superior en los errores
bg_test <- bgtest(mod)
print(bg_test)
## 
##  Breusch-Godfrey test for serial correlation of order up to 1
## 
## data:  mod
## LM test = 26.146, df = 1, p-value = 3.166e-07

H0: Los errores son independientes, es decir, no presentan autocorrelación.

H1: Los errores no son independientes, es decir, presentan autocorrelación.

Aplicando las pruebas de Durbin-Watson y Breusch-Godfrey, se rechaza la hipótesis nula. Por lo tanto en el modelo no hay evidencia de independencia en los errores.

Los supuestos de normalidad e independencia de los errores no se cumplen para el modelo, por lo tanto las inferencias realizadas para los precios de las casa de la Zona Norte no serán confiables.

Algunas sugerencias de ajustes sobre el modelo podrían ser, eliminacion de atipicos, eliminación de variables no significativas que pueden estar correlacionadas con otras variables. O realizar una transformación que mejore el ajuste y el cumplimiento de los supuestos del modelo.



  1. Con el modelo identificado debe predecir el precio de la vivienda con las características de la primera solicitud.

Precio estrato 4

# Definir la nueva vivienda
nueva_vivienda <- data.frame(
  areaconst = 200,
  estrato = 4,
  banios = 2,
  habitaciones = 4,
  parqueaderos = 1
)

# Hacer la predicción
predict(mod, newdata = nueva_vivienda)
##        1 
## 327.8023

Precio estrato 5

# Definir la nueva vivienda
nueva_vivienda2 <- data.frame(
  areaconst = 200,
  estrato = 5,
  banios = 2,
  habitaciones = 4,
  parqueaderos = 1
)

# Hacer la predicción
predict(mod, newdata = nueva_vivienda2)
##        1 
## 411.7037

Predicciones usando set de prueba

set.seed(123)  # para reproducibilidad

# 1. Separar datos en entrenamiento y prueba (70/30, por ejemplo)
n <- nrow(df)
train_index <- sample(1:n, size = 0.7*n)  

train <- df[train_index, ]   # datos de entrenamiento
test  <- df[-train_index, ]  # datos de prueba

# 2. Ajustar el modelo con los datos de entrenamiento
modelo <- lm(preciom ~ areaconst + estrato + banios + habitaciones + parqueaderos, data = train)

# 3. Hacer predicciones sobre el set de prueba
test$predicciones <- predict(modelo, newdata = test)

# 4. Evaluar el desempeño
head(test[, c("preciom", "predicciones")])  # ver precios reales vs predichos
## # A tibble: 6 × 2
##   preciom predicciones
##     <dbl>        <dbl>
## 1     320         437.
## 2     780         590.
## 3     750         856.
## 4     625         544.
## 5     420         473.
## 6     230         212.

Evaluación de métricas MAE y RMSE

# Métricas

mae <- mae(test$preciom, test$predicciones)
rmse <- rmse(test$preciom, test$predicciones)

mae
## [1] 108.6988
rmse
## [1] 180.1705

Visualmente comparando las predicciones sobre el set de prueba se evidencian diferencias significativas frente al precio de mercado.

Los valores de las métricas del error absoluto promedio MAE=108 y la raiz del error cuadrático medio RMSE=180 evidencian que hay diferencias muy grandes en la predicción y que hay gran influencia de valores atípicos



6. Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 1. Tenga en cuenta que la empresa tiene crédito pre-aprobado de máximo 350 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.

#Generación de predicciones
df$pred_precio <- predict(mod, newdata = df)

#Filtro de viviendas de interés, se amplian las condiciones para considerar más opciones
ofertas <- df %>%
  filter(areaconst >= 180 & areaconst <= 250,   # área aproximada a 200
         banios %in% c(2, 3),
         habitaciones %in% c(3, 4, 5),
         parqueaderos  %in% c(1, 2),
         estrato %in% c(4, 5),
         pred_precio <= 400)   # se amplia el precio ya que el precio de mercado tiende a 
                               #estar por debajo del precio de predicción

Se presentan 8 alternativas flexibilizando algunas variables de interés

#Se seleccionan aquellas 8 ofertas cuyos valores de mercado son más bajos
ofertas_top5 <- ofertas %>%
  arrange(preciom) %>%
  head(8)
ofertas_top5
## # A tibble: 8 × 8
##      id preciom areaconst estrato banios habitaciones parqueaderos pred_precio
##   <dbl>   <dbl>     <dbl>   <dbl>  <dbl>        <dbl>        <dbl>       <dbl>
## 1  4684     271       226       4      3            3            1        377.
## 2  4511     275       190       4      2            3            1        319.
## 3  5412     280       180       4      3            3            1        339.
## 4   515     280       180       4      3            4            1        340.
## 5  3586     330       240       4      2            3            1        360.
## 6  3891     355       190       4      3            5            2        354.
## 7  6807     360       240       4      2            3            1        360.
## 8  1222     360       216       4      2            4            2        346.
#Se agregan variables de latitud y longitud
ofertas_top5 <- ofertas_top5 %>%
  left_join(v %>% select(id, longitud, latitud), by = "id")

Localización de casas tentativas

leaflet(ofertas_top5) %>%
  addTiles() %>%
  addCircleMarkers(~longitud, ~latitud,
                   popup = ~paste0("Precio estimado: ", round(pred_precio,1), " M",
                                   "<br>Precio mercado: ", preciom, " m²",
                                   "<br>Área: ", areaconst, " m²",
                                   "<br>Estrato: ", estrato,
                                   "<br>Baños: ", banios,
                                   "<br>Habitaciones: ", habitaciones,
                                   "<br>id: ", id),
                   radius = 6,
                   color = "blue",
                   fillOpacity = 0.7)

Las potenciales ofertas corresponden a las seleccionadas en la zona norte cuyos id corresponden a: 515, 1222, 3586, 4511 y 4684

Pasos requeridos para la obtención de los resultados Vivienda 2

  1. Realice un filtro a la base de datos e incluya solo las ofertas de : base1: apartamentos, de la zona sur de la ciudad. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta. (Adicional un mapa con los puntos de las bases. Discutir si todos los puntos se ubican en la zona correspondiente o se presentan valores en otras zonas, por que?).

A continuación se presentan los primeros 3 registros de la base filtrada para el análisis de la vivienda 2. Adicionalmente se muestran los valores de las variables zona y tipo para verificar el correcto filtrado de los datos.

v2=v_sna[v_sna$zona=="Zona Sur" & v_sna$tipo == "Apartamento",]
head(v2, 3)
## # A tibble: 3 × 13
##      id zona     piso estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <int> <chr>     <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  5098 Zona S…     5 4           290        96            1      2            3
## 2   698 Zona S…     2 3            78        40            1      1            2
## 3  8199 Zona S…     2 6           875       194            2      5            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
#Valores únicos de las variables filtradas
unique(v2$zona)
## [1] "Zona Sur"
unique(v2$tipo)
## [1] "Apartamento"

Localización de las casas identificadas en la Zona Sur

# Localización de los apartamentos
leaflet(v2) %>%
  addTiles() %>%  # Mapa base
  addCircleMarkers(~longitud, ~latitud,
                   popup = ~as.character(barrio),
                   radius = 4,      # tamaño del punto (puedes probar 2, 3, 5...)
                   color = "blue",  # color del borde
                   fillColor = "lightblue", # color de relleno
                   fillOpacity = 0.7)

Geográficamente las casas clasificadas al Sur de la ciudad, realmente se distribuyen en diferentes zonas. Lo cual puede ocurrir por errores en la digitación de las coordenadas o en la identificación de la zona.

  1. Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio del apartamento) en función del área construida, estrato, numero de baños, numero de habitaciones y zona donde se ubica la vivienda. Use gráficos interactivos con el paquete plotly e interprete los resultados.
# Selección de variables de interés, se omite zona ya que solo corresponde a la Zona Sur y se agrega número de parqueaderos al ser mencionada en el punto 3.
df2 <- v2 %>% 
  select(id,preciom, areaconst, estrato, banios, habitaciones, parqueaderos)
#Se deja estrato como numérica al ser ordinal
df2$estrato <- as.numeric(df2$estrato)
  
# Correlaciones numéricas
# Usamos Spearman (robusto a no linealidades y ordinalidad de estrato)
cors <- cor(df2[, !(names(df2) %in% c("id"))],
            method = "spearman",
            use = "pairwise.complete.obs")

# Heatmap interactivo
heatmap_cor <- plot_ly(
  x = colnames(cors), y = rownames(cors),
  z = cors, type = "heatmap", 
  text = round(cors, 2), hovertemplate = "X: %{x}<br>Y: %{y}<br>rho: %{text}<extra></extra>"
) %>%
  layout(title = "Matriz de correlaciones (Spearman)")

heatmap_cor

Las variables que presentan una correlación fuerte con el precio de la vivienda son el área construida, el estrato, la cantidad de baños y la cantidad de parqueaderos.

No se observa una correlación fuerte por parte de la variable habitaciones con el precio de la vivienda.

# Precio vs Área construida
plot_ly(df2, x = ~areaconst, y = ~preciom, color = ~estrato,
        type = "scatter", mode = "markers",
        text = ~paste("Estrato:", estrato)) %>%
  layout(title = "Precio vs Área construida (color por estrato)")

Se identifica gráficamente la correlación positiva entre el área construida y el precio de vivienda, evidenciando adicionalmente una gran dispersión frente a los valores extremos de precio y área en las viviendas.



  1. Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños ) ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deber están contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).
#Modelo de regresión líneal múltiple
mod2 <- lm(preciom ~ areaconst + estrato + banios + habitaciones + parqueaderos, data = df2)
summary(mod2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios + habitaciones + 
##     parqueaderos, data = df2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1143.63   -37.88    -2.65    38.05   923.94 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -268.14679   12.86750 -20.839  < 2e-16 ***
## areaconst       1.35004    0.04864  27.757  < 2e-16 ***
## estrato        59.22882    2.66505  22.224  < 2e-16 ***
## banios         45.43316    3.02871  15.001  < 2e-16 ***
## habitaciones  -17.54937    3.31804  -5.289 1.32e-07 ***
## parqueaderos   72.74628    3.66473  19.850  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 92.97 on 2781 degrees of freedom
## Multiple R-squared:  0.7649, Adjusted R-squared:  0.7644 
## F-statistic:  1809 on 5 and 2781 DF,  p-value: < 2.2e-16

A partir del modelo estimado con las variables de interés se pueden realizar las siguientes afirmaciones:

Con la excepción de la variable habitaciones, el resto de variables tienen una relación directa frente al precio de los inmuebles. Es decir, que a medida que aumenta el valor de la variable tambien aumenta en alguna medida el precio de la vivienda.

Para el caso de las habitaciones, a medida que aumenta la cantidad de habitaciones, disminuye el precio de la vivienda.

No obstante, para cada variable se presenta el valor p, que permite establecer la influencia real de cada variable en el precio del inmueble. En este caso todas las variables influyen en el precio de los inmuebles.

Los resultados frente a la influencia en el precio de cada variable, son coherentes frente al análisis de correlaciones. No se esperaba significancia frente a la variable de habitaciones, no obstante el modelo confirma que su presencia aporta al entendimiento de la variabilidad del precio de la vivienda.

El R2= 0,76 indica que el modelo explica el 76% de la variabilidad con las variables consideradas, lo cual indica que hay otros factores relevantes que no se están incluyendo.

El modelo se puede mejorar incluyendo variables adicionales que recojan la variabilidad que no está siendo explicada y puedan mejorar la predicción.



  1. Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).

Evaluación de los supuestos del modelo

  1. Los errores εi siguen una distribución normal: \[εi∼N(0,σ2)\] Se realiza el análisis sobre los residuales estandarizados y se evalúa la hipótesis de normalidad.
# Obtener residuales estandarizados
residuales_estandarizados <- rstandard(mod2)

par(mfrow = c(1, 2))
# Generar el QQ-Plot para evaluar normalidad
qqnorm(residuales_estandarizados, main="QQ-Plot de los Residuales", col="blue",
       cex.main = 1,   # Tamaño del título
       cex.axis = 0.8)
qqline(residuales_estandarizados, col="red", lwd=2)  # Agregar línea de referencia

# Determinar residuos ordinarios y aplicar test de normalidad
ei <- residuals(mod2)
shapiro.test(ei)
## 
##  Shapiro-Wilk normality test
## 
## data:  ei
## W = 0.78265, p-value < 2.2e-16

Hipótesis del test de normalidad:

H0: Los errores siguen una distribución normal.

H1: Los errores no siguen una distribución normal.

Al aplicar el test de Shapiro-Wilk se obtiene un valor p menor a 0.05 sobre los residuales del modelo. Por lo tanto, se rechaza la hipótesis nula, evidenciando que los errores no siguen una distribución normal. Esto reafirma lo que evidencia el QQ-Plot al presentar una dispersión en el extremo superior del modelo. Esto puede deberse a una gran presencia de valores atípicos en los precios de los apartamentos de la Zona Sur.



2. Los errores tienen varianza constante (homocedasticidad)

#prueba Breusch-Pagan
bptest(mod2)
## 
##  studentized Breusch-Pagan test
## 
## data:  mod2
## BP = 890.48, df = 5, p-value < 2.2e-16

Prueba de hipótesis:

H0: Los errores tienen varianza constante (homocedasticidad).

H1: Los errores no tienen varianza constante (heterocedasticidad).

Aplicando la prueba de Breusch-Pagan, se rechaza la hipótesis nula, por lo tanto se evidencia la presencia de heterocedasticidad para el modelo.



3. No hay correlación entre los errores (independencia).

# Durbin-Watson Test
# Evalúa si los errores presentan autocorrelación de primer orden
dw_test <- dwtest(mod2)
print(dw_test)
## 
##  Durbin-Watson test
## 
## data:  mod2
## DW = 1.5434, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0
# Breusch-Godfrey Test
# Permite evaluar autocorrelación de orden superior en los errores
bg_test <- bgtest(mod2)
print(bg_test)
## 
##  Breusch-Godfrey test for serial correlation of order up to 1
## 
## data:  mod2
## LM test = 146.15, df = 1, p-value < 2.2e-16

H0: Los errores son independientes, es decir, no presentan autocorrelación.

H1: Los errores no son independientes, es decir, presentan autocorrelación.

Aplicando las pruebas de Durbin-Watson y Breusch-Godfrey, se rechaza la hipótesis nula. Por lo tanto en el modelo no hay evidencia de independencia en los errores.

Los supuestos de normalidad e independencia de los errores no se cumplen para el modelo, por lo tanto las inferencias realizadas para los precios de los apartamentos de la Zona Sur no serán confiables.

Algunas sugerencias de ajustes sobre el modelo podrían ser, eliminacion de atípicos o realizar una transformación que mejore el ajuste y el cumplimiento de los supuestos del modelo.



  1. Con el modelo identificado debe predecir el precio de la vivienda con las características de la segunda solicitud.

Precio estrato 5

# Definir la nueva vivienda
nueva_vivienda <- data.frame(
  areaconst = 300,
  estrato = 5,
  banios = 3,
  habitaciones = 5,
  parqueaderos = 3
)

# Hacer la predicción
predict(mod2, newdata = nueva_vivienda)
##        1 
## 699.8008

Precio estrato 6

# Definir la nueva vivienda
nueva_vivienda2 <- data.frame(
  areaconst = 300,
  estrato = 6,
  banios = 3,
  habitaciones = 5,
  parqueaderos = 3
)

# Hacer la predicción
predict(mod2, newdata = nueva_vivienda2)
##        1 
## 759.0297

Predicciones usando set de prueba

set.seed(123)  # para reproducibilidad

# 1. Separar datos en entrenamiento y prueba (70/30, por ejemplo)
n <- nrow(df2)
train_index <- sample(1:n, size = 0.7*n)  

train <- df2[train_index, ]   # datos de entrenamiento
test  <- df2[-train_index, ]  # datos de prueba

# 2. Ajustar el modelo con los datos de entrenamiento
modelo2 <- lm(preciom ~ areaconst + estrato + banios + habitaciones + parqueaderos, data = train)

# 3. Hacer predicciones sobre el set de prueba
test$predicciones <- predict(modelo2, newdata = test)

# 4. Evaluar el desempeño
head(test[, c("preciom", "predicciones")])  # ver precios reales vs predichos
## # A tibble: 6 × 2
##   preciom predicciones
##     <dbl>        <dbl>
## 1     875        671. 
## 2     220        181. 
## 3     150        118. 
## 4     305        486. 
## 5     115         51.9
## 6     175        173.

Evaluación de métricas MAE y RMSE

# Métricas

mae <- mae(test$preciom, test$predicciones)
rmse <- rmse(test$preciom, test$predicciones)

mae
## [1] 55.11728
rmse
## [1] 89.10835

Visualmente comparando las predicciones sobre el set de prueba se evidencian diferencias significativas frente al precio de mercado.

Los valores de las métricas del error absoluto promedio MAE=55 y la raiz del error cuadrático medio RMSE=89 evidencian que hay diferencias muy grandes en la predicción y que hay gran influencia de valores atípicos.



6. Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 2. Tenga en cuenta que la empresa tiene crédito pre-aprobado de máximo 850 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.

#Generación de predicciones
df2$pred_precio <- predict(mod2, newdata = df2)

#Filtro de viviendas de interés, se amplian las condiciones para considerar más opciones
ofertas2 <- df2 %>%
  filter(areaconst >= 250 & areaconst <= 350,   # área aproximada a 200
         banios %in% c(3, 4),
         habitaciones %in% c(3, 4, 5),
         parqueaderos  %in% c(3, 4),
         estrato %in% c(5, 6),
         pred_precio <= 1000)   # se amplia el precio ya que el precio de mercado tiende a 
                               #estar por debajo del precio de predicción

Se presentan 7 alternativas flexibilizando algunas variables de interés

#Se seleccionan aquellas 7 ofertas cuyos valores de mercado son más bajos
ofertas_top7 <- ofertas2 %>%
  arrange(preciom) %>%
  head(7)
ofertas_top7
## # A tibble: 7 × 8
##      id preciom areaconst estrato banios habitaciones parqueaderos pred_precio
##   <dbl>   <dbl>     <dbl>   <dbl>  <dbl>        <dbl>        <dbl>       <dbl>
## 1  6175     350       270       5      3            4            3        677.
## 2  6205     350       260       5      3            3            3        681.
## 3  7680     450       267       5      3            3            3        690.
## 4  4958     950       329       6      3            3            4        906.
## 5  4962     980       274       6      4            4            3        787.
## 6  3809     980       306       6      4            3            4        920.
## 7  4870     980       306       6      4            3            4        920.
#Se agregan variables de latitud y longitud
ofertas_top7 <- ofertas_top7 %>%
  left_join(v2 %>% select(id, longitud, latitud), by = "id")

Localización de apartamentos tentativos

leaflet(ofertas_top7) %>%
  addTiles() %>%
  addCircleMarkers(~longitud, ~latitud,
                   popup = ~paste0("Precio estimado: ", round(pred_precio,1), " M",
                                   "<br>Precio mercado: ", preciom, " m²",
                                   "<br>Área: ", areaconst, " m²",
                                   "<br>Estrato: ", estrato,
                                   "<br>Baños: ", banios,
                                   "<br>Habitaciones: ", habitaciones,
                                   "<br>id: ", id),
                   radius = 6,
                   color = "blue",
                   fillOpacity = 0.7)



Conclusiones del proceso estadístico

Para mejorar la precisión de las predicciones y la consistencia de los modelos frente a los supuestos se recomienda:

  • Evaluar valores extremos de modo que se incluyan variables asociadas a estos valores que aporten en su explicación dentro del modelo o que se eliminen dada su influencia en la alta variabilidad de la predicción del modelo.

  • Eliminar del modelo las variables no influyentes, ya que no aportan en la predicción y si aumentan la complejidad de la interpretación del modelo.

  • Evaluar la inclusión de variables adicionales que recojan la variabilidad que no está siendo explicada y que puedan mejorar la predicción.

  • Realizar una transformación que mejore el ajuste y el cumplimiento de los supuestos del modelo.

  • Utilizar un modelo de predicción que no cumple con los supuestos y que no explica una variabilidad significativa del fenómeno de interés no es confiable y no permitirá realizar recomendaciones acertadas frente a una decisión comercial.

Informe Ejecutivo

Base de Datos y Variables

Los datos de los tres últimos meses presentan las siguientes variables:

Variable Descripción
zona Ubicación de la vivienda: Zona Centro, Zona Norte,…
piso Piso que ocupa la vivienda: primer piso, segundo piso…
estrato Estrato socio-económico: 3, 4, 5, 6
preciom Precio de la vivienda en millones de pesos
areaconst Área construida
parqueaderos Número de parqueaderos
banios Número de baños
habitaciones Número de habitaciones
tipo Tipo de vivienda: Casa, Apartamento
barrio Barrio de ubicación de la vivienda: 20 de Julio, Álamos,…
longitud Coordenada geográfica
latitud Coordenada geográfica

Recomendaciones Vivienda 1

  • Los precios de las casas ubicadas en la zona norte de la ciudad se encuentran directamente relacionados con el área construida, el estrato y la cantidad de baños.

  • El modelo indica que el aumento de estrato 4 a 5 puede significar un incremento de 84 millones en el precio de la casa, para la zona de interés el valor de referencia presenta mayor coincidencia con viviendas de estrato 4.

  • A continuación se presentan 5 ofertas tentativas de casas localizadas en la zona norte cuyo precio de mercado es acorde al crédito preaprobado y que cuentan con las condiciones mínimas requeridas para consideración del cliente.

# Filtras por los ids de interés
ids_interes <- c(515, 1222, 3586, 4511, 4684)

ofertas_filtradas <- ofertas_top5 %>%
  filter(id %in% ids_interes)

datatable(
  ofertas_filtradas %>%
    select(id, pred_precio, preciom, areaconst, estrato, banios, habitaciones, parqueaderos),
  options = list(
    pageLength = 5,
    autoWidth = TRUE,
    scrollX = TRUE
  ),
  rownames = FALSE
)
# Mapa solo con esos puntos
leaflet(ofertas_filtradas) %>%
  addTiles() %>%
  addCircleMarkers(
    ~longitud, ~latitud,
    popup = ~paste0("Precio estimado: ", round(pred_precio,1), " M",
                    "<br>Precio mercado: ", preciom, " M",
                    "<br>Área: ", areaconst, " m²",
                    "<br>Estrato: ", estrato,
                    "<br>Baños: ", banios,
                    "<br>Habitaciones: ", habitaciones,
                    "<br>ID: ", id),
    radius = 6,
    color = "blue",
    fillOpacity = 0.7
  ) %>%
  addLabelOnlyMarkers(
    ~longitud, ~latitud,
    label = ~paste(preciom, "M"),
    labelOptions = labelOptions(
      noHide = TRUE,         # 👈 mantiene el label siempre visible
      direction = "top",     # posición del texto
      textOnly = TRUE,
      style = list(
        "color" = "black",
        "font-size" = "12px",
        "font-weight" = "bold"
      )
    )
  )

Recomendaciones Vivienda 2

  • Los precios de los apartamentos ubicados en la zona sur de la ciudad se encuentran directamente relacionados con el área construida, el estrato, la cantidad de parqueaderos y la cantidad de baños. A diferencia de la zona norte en esta zona la cantidad de parqueaderos tienen una gran injerencia en el precio de las viviendas.

  • Por otro lado la relación del precio con respecto a las habitaciones es inversa.

  • El modelo indica que el aumento de estrato 5 a 6 puede significar un incremento de 59 millones en el precio del apartamento, para la zona de interés el valor de referencia presenta mayor coincidencia con viviendas de estrato 5.

  • A continuación se presentan 7 ofertas tentativas de apartamentos localizados en la zona sur cuyo precio de mercado es acorde al crédito preaprobado o puede ser superior considerando que los precios de vivienda pueden ser negociables y que no hay muchas ofertas que se ajusten al límite presupuestal dadas las condiciones requeridas por el cliente.

datatable(
  ofertas_top7 %>%
    select(id, pred_precio, preciom, areaconst, estrato, banios, habitaciones, parqueaderos),
  options = list(
    pageLength = 5,
    autoWidth = TRUE,
    scrollX = TRUE
  ),
  rownames = FALSE
)
# Mapa solo con esos puntos
leaflet(ofertas_top7) %>%
  addTiles() %>%
  addCircleMarkers(
    ~longitud, ~latitud,
    popup = ~paste0("Precio estimado: ", round(pred_precio,1), " M",
                    "<br>Precio mercado: ", preciom, " M",
                    "<br>Área: ", areaconst, " m²",
                    "<br>Estrato: ", estrato,
                    "<br>Baños: ", banios,
                    "<br>Habitaciones: ", habitaciones,
                    "<br>ID: ", id),
    radius = 6,
    color = "blue",
    fillOpacity = 0.7
  ) %>%
  addLabelOnlyMarkers(
    ~longitud, ~latitud,
    label = ~paste(preciom, "M"),
    labelOptions = labelOptions(
      noHide = TRUE,         # 👈 mantiene el label siempre visible
      direction = "top",     # posición del texto
      textOnly = TRUE,
      style = list(
        "color" = "black",
        "font-size" = "12px",
        "font-weight" = "bold"
      )
    )
  )

Recomendaciones generales

  • Es necesario verificar la precisión de la información de referencia que utiliza la empresa C&A, ya que de su veracidad, depende la calidad del servicio prestado, la credibilidad hacia los clientes y el prestigio que permitirá una consolidación en el mercado inmobiliario.

  • La información de zona no es consistente al revisar su localización en el mapa, esta información se puede validar con datos complementarios de barrio para mejorar su precisión y disminuir los casos que puedan requerir validación de campo.