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:


Frecuencia


Obtención de los Resultados

# Cargue de librerias
library(dlookr); library(paqueteMODELOS); library(leaflet); library(VIM)
library(dplyr); library(ggplot2); library(gridExtra); library(dplyr)
library(plotly); library(broom); library(tidyr)

# Cargue de los datos
data("vivienda"); data <- vivienda; head(vivienda)
## # A tibble: 6 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1147 Zona O… <NA>        3     250        70            1      3            6
## 2  1169 Zona O… <NA>        3     320       120            1      2            3
## 3  1350 Zona O… <NA>        3     350       220            2      2            4
## 4  5992 Zona S… 02          4     400       280            3      5            3
## 5  1212 Zona N… 01          5     260        90            1      2            3
## 6  1724 Zona N… 01          5     240        87            1      3            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Analisis Vivienda 1: Casa en la Zona Norte

Para facilitar una visualización más clara de la base de datos, se filtra y se proyecta en el mapa para confirmar que la selección de Casas en la Zona Norte sea la correcta.

# 1.1 Filtro a la base de datos, Seleccion de Zona Norte y Tipo: Casa
data_casas <- subset(data, zona == "Zona Norte" & tipo == "Casa") # Filtro por filas
leaflet(data_casas %>% filter(!is.na(latitud), !is.na(longitud))) %>%
  addTiles() %>% addCircleMarkers(~longitud, ~latitud, color = "blue", radius = 5) %>%
  setView(lng = mean(data_casas$longitud, na.rm = TRUE), lat = mean(data_casas$latitud, na.rm = TRUE), zoom = 12) %>%
  addControl("<h3>Viviendas Zona Norte - BD Sin Depurar</h3>", position = "topleft")

Se observa que hay numerosos puntos que no corresponden con la ubicación de Casas en la Zona Norte de Cali. Para depurar los datos y realizar un análisis más preciso, se aplicó un filtro de valores atípicos utilizando los cuartiles, con el objetivo de reducir el margen de error en la ubicación.

Procesamiento de datos

# Eliminación de columnas innecesarias para el análisis
data_casas <- data_casas %>% select(preciom, areaconst, estrato, habitaciones, parqueaderos, banios, longitud, latitud) 
# Convertir la variable 'estrato' en categórica
data_casas$estrato <- as.factor(data_casas$estrato); str(data_casas$estrato)
##  Factor w/ 4 levels "3","4","5","6": 3 3 4 2 3 2 3 3 1 1 ...
# Tratamiento de valores nulos
data_casas <- data_casas[data_casas$habitaciones != 0 & data_casas$banios != 0, ]

Se llevó a cabo un análisis en el que se determinó que las viviendas sin baños ni habitaciones podrían clasificarse como lotes o parqueaderos. Por esta razón, se excluyeron estos datos del análisis.

# Tratamiento de outliers de las variables longitud y latitud
###################################################################
# Inicializar variables
threshold <- 0.01; max_iter <- 10; data_original <- data_casas
percent_outliers <- numeric(max_iter); iterations <- numeric(max_iter)
# Filtrar y registrar datos
for (iter in 1:max_iter) {
  q25_lat <- quantile(data_casas$latitud, 0.25, na.rm = TRUE)
  q75_lat <- quantile(data_casas$latitud, 0.75, na.rm = TRUE)
  iqr_lat <- IQR(data_casas$latitud, na.rm = TRUE)
  q25_lon <- quantile(data_casas$longitud, 0.25, na.rm = TRUE)
  q75_lon <- quantile(data_casas$longitud, 0.75, na.rm = TRUE)
  iqr_lon <- IQR(data_casas$longitud, na.rm = TRUE)
  
  data_casas <- data_casas %>%
    filter(between(latitud, q25_lat - 1.5 * iqr_lat, q75_lat + 1.5 * iqr_lat),
           between(longitud, q25_lon - 1.5 * iqr_lon, q75_lon + 1.5 * iqr_lon))
  
  percent_outliers[iter] <- (1 - nrow(data_casas) / nrow(data_original)) * 100
  iterations[iter] <- iter
  
  if ((1 - nrow(data_casas) / nrow(data_original)) <= threshold) break
}

# Graficar porcentaje de valores atípicos
ggplot(data.frame(Iteration = iterations[1:iter], PercentOutliers = percent_outliers[1:iter]), 
       aes(x = Iteration, y = PercentOutliers)) +
  geom_line() + geom_point() +
  labs(title = "Porcentaje de Valores Atípicos por Iteración", x = "Número de Iteración", y = "Porcentaje de Valores Atípicos (%)") +
  theme_minimal()

# Crear el mapa
leaflet(data_casas %>% filter(!is.na(latitud), !is.na(longitud))) %>%
  addTiles() %>%
  addCircleMarkers(~longitud, ~latitud, color = "blue", radius = 5) %>%
  setView(lng = mean(data_casas$longitud, na.rm = TRUE), lat = mean(data_casas$latitud, na.rm = TRUE), zoom = 12) %>%
  addControl(paste0("<h3>Casas Zona Norte - Iteración ", iter, "</h3>"), position = "topleft")

Podemos observar que, tras 5 iteraciones, el filtro de datos por cuartiles aplicado a las variables de latitud y longitud se estabilizó. Además, el mapa resultante muestra una visualización más depurada y concentrada en la Zona Norte, lo que permitirá realizar un análisis más preciso del modelo.

Datos Missing e Imputación

# Datos Missing
# Calcular la correlación entre parqueaderos y preciom antes de la imputación
cor_before <- cor(data_casas$parqueaderos, data_casas$preciom, use = "complete.obs")

# Recuento y porcentaje de NA por variable sin imputación
na_summary <- data_casas %>%  summarise(across(everything(), ~sum(is.na(.)))) %>%
  pivot_longer(cols = everything(), names_to = "variable", values_to = "count_na") %>%
  mutate(percent_na = count_na / nrow(data_casas) * 100)
print(na_summary)
## # A tibble: 8 × 3
##   variable     count_na percent_na
##   <chr>           <int>      <dbl>
## 1 preciom             0        0  
## 2 areaconst           0        0  
## 3 estrato             0        0  
## 4 habitaciones        0        0  
## 5 parqueaderos      201       34.0
## 6 banios              0        0  
## 7 longitud            0        0  
## 8 latitud             0        0

Tenemos 201 datos faltantes en la variable “parqueaderos”, lo que representa el 34% del total. Se decidió realizar una imputación utilizando la técnica de KNN para abordar este problema.

# Imputar con KNN
data_casas_imputado <- kNN(data_casas, variable = "parqueaderos")
# Evaluación del metodo de imputación aplicado

# Comparar distribuciones
data_casas %>%  mutate(source = ifelse(is.na(parqueaderos), "Original NA", "Original Not NA")) %>%
  bind_rows(data_casas_imputado %>% mutate(source = "Imputado")) %>% ggplot(aes(x = parqueaderos, fill = source)) +
  geom_density(alpha = 0.5) + labs(title = "Distribución de 'parqueaderos': Original vs Imputado", x = "Valor de parqueaderos", y = "Densidad") + theme_minimal()

# Recuento y porcentaje de NA por variable con imputación
na_summary <- data_casas_imputado %>%  summarise(across(everything(), ~sum(is.na(.)))) %>%
  pivot_longer(cols = everything(), names_to = "variable", values_to = "count_na") %>%
  mutate(percent_na = count_na / nrow(data_casas) * 100)
print(na_summary)
## # A tibble: 9 × 3
##   variable         count_na percent_na
##   <chr>               <int>      <dbl>
## 1 preciom                 0          0
## 2 areaconst               0          0
## 3 estrato                 0          0
## 4 habitaciones            0          0
## 5 parqueaderos            0          0
## 6 banios                  0          0
## 7 longitud                0          0
## 8 latitud                 0          0
## 9 parqueaderos_imp        0          0
# Calcular la correlación entre parqueaderos y preciom después de la imputación
cor_after <- cor(data_casas_imputado$parqueaderos, data_casas_imputado$preciom, use = "complete.obs")
# Crear un dataframe con las correlaciones antes y después
correlation_comparison <- data.frame(
  Metodo = c("Antes de imputación", "Después de imputación"),
  Correlacion = c(cor_before, cor_after)
)
# Mostrar el dataframe con las correlaciones
print(correlation_comparison)
##                  Metodo Correlacion
## 1   Antes de imputación   0.4321497
## 2 Después de imputación   0.4941782
# Definiendo dataset limpio
data_casas_clean <- data_casas_imputado; str(data_casas_clean)
## 'data.frame':    591 obs. of  9 variables:
##  $ preciom         : num  320 780 230 180 500 520 380 395 460 390 ...
##  $ areaconst       : num  150 380 160 120 210 455 300 165 319 357 ...
##  $ estrato         : Factor w/ 4 levels "3","4","5","6": 3 3 1 1 1 3 1 3 3 3 ...
##  $ habitaciones    : num  6 3 3 3 6 4 8 4 4 6 ...
##  $ parqueaderos    : num  2 2 1 1 1 2 2 2 2 2 ...
##  $ banios          : num  4 3 2 3 6 5 5 4 5 3 ...
##  $ longitud        : num  -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud         : num  3.48 3.49 3.45 3.47 3.45 ...
##  $ parqueaderos_imp: logi  FALSE FALSE TRUE TRUE TRUE TRUE ...
##  - attr(*, "spec")=List of 3
##   ..$ cols   :List of 13
##   .. ..$ id          : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ zona        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ piso        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ estrato     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ preciom     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ areaconst   : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ parqueaderos: list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ banios      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ habitaciones: list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ tipo        : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ barrio      : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
##   .. ..$ longitud    : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   .. ..$ latitud     : list()
##   .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
##   ..$ default: list()
##   .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
##   ..$ delim  : chr ";"
##   ..- attr(*, "class")= chr "col_spec"
##  - attr(*, "problems")=<externalptr>

Después de la imputación, no quedan valores faltantes en las variables, lo que confirma la efectividad del método KNN utilizado. Además, la correlación entre “parqueaderos” y “preciom” aumentó de 0.4321 a 0.4942, indicando que la imputación ha fortalecido la relación entre estas variables. Estos cambios mejoran la calidad y precisión del análisis, lo que resulta en un modelo predictivo más robusto.

Análisis exploratorio de los datos

Variables Numericas:

# 2.1. Análisis de Variables Numéricas
# 2.1.1. Matriz de Correlación
# Seleccionar variables numéricas
datos_numericos <- data_casas %>% select(preciom, areaconst, banios, habitaciones)
# Calcular matriz de correlación
corr_matrix <- cor(datos_numericos, use = "complete.obs")
# Convertir a formato largo
corr_long <- as.data.frame(as.table(corr_matrix))
# Graficar heatmap
plot_ly(corr_long, x = ~Var2, y = ~Var1, z = ~Freq, type = 'heatmap',
        colorscale = 'Viridis', text = ~paste0(round(Freq, 2)), texttemplate = '%{text}') %>%
  layout(title = 'Matriz de Correlación entre Variables Numéricas',
         xaxis = list(title = 'Variables'),
         yaxis = list(title = 'Variables'))

Matriz de Correlación: La matriz de correlación entre las variables numéricas muestra relaciones importantes entre ellas:

  • La variable “areaconst” (Área Construida) tiene una correlación alta (0.74) con el “preciom” (Precio), lo cual es esperado ya que generalmente, el precio de una propiedad aumenta con el tamaño del área construida.

  • También se observa una correlación moderada entre el número de “banios” (baños) y “habitaciones” con “preciom” (0.57 y 0.43 respectivamente), lo que indica que estos factores también influyen en el valor de la propiedad, aunque en menor medida que el área construida.

# 2.1.2. Gráficos de Dispersión
# Crear gráficos de dispersión
plots_numeric <- list(
  plot_ly(data_casas_clean, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers',
          name = 'Precio vs Área Construida') %>%
    layout(title = 'Precio vs Área Construida',
           xaxis = list(title = 'Área Construida'), 
           yaxis = list(title = 'Precio'),
           legend = list(orientation = 'h', x = 0.5, xanchor = 'center', y = -0.2)), # Leyenda debajo del título
  
  plot_ly(data_casas_clean, x = ~banios, y = ~preciom, type = 'scatter', mode = 'markers',
          name = 'Precio vs Número de Baños') %>%
    layout(title = 'Precio vs Número de Baños',
           xaxis = list(title = 'Número de Baños'), 
           yaxis = list(title = 'Precio'),
           legend = list(orientation = 'h', x = 0.5, xanchor = 'center', y = -0.2)), # Leyenda debajo del título
  
  plot_ly(data_casas_clean, x = ~habitaciones, y = ~preciom, type = 'scatter', mode = 'markers',
          name = 'Precio vs Número de Habitaciones') %>%
    layout(title = 'Precio vs Número de Habitaciones',
           xaxis = list(title = 'Número de Habitaciones'), 
           yaxis = list(title = 'Precio'),
           legend = list(orientation = 'h', x = 0.5, xanchor = 'center', y = -0.2)), # Leyenda debajo del título
  
  plot_ly(data_casas_clean, x = ~parqueaderos, y = ~preciom, type = 'scatter', mode = 'markers',
          name = 'Precio vs Número de Parqueaderos') %>%
    layout(title = 'Precio vs Número de Parqueaderos',
           xaxis = list(title = 'Número de Parqueaderos'), 
           yaxis = list(title = 'Precio'),
           legend = list(orientation = 'h', x = 0.5, xanchor = 'center', y = -0.2))  # Leyenda debajo del título
)

# Mostrar gráficos en un layout de 2x2
subplot(plots_numeric, nrows = 2, margin = 0.05) %>%
  layout(title = 'Diagramas de Dispersión de Variables Numéricas',
         showlegend = TRUE) # Asegúrate de que la leyenda se muestre

Diagramas de Dispersión: En los diagramas de dispersión, se confirma visualmente la relación positiva entre el “preciom” y el “areaconst”, observándose una tendencia de aumento del precio con el incremento del área construida. La dispersión del precio frente al número de baños y habitaciones sugiere una tendencia similar, aunque con más variabilidad, lo que podría indicar la influencia de otros factores no considerados en este análisis.

Variables Categoricas:

# 2.2. Análisis de Variables Categóricas
# 2.2.1. Realizar el análisis ANOVA
anova_result <- aov(preciom ~ estrato, data = data_casas)
summary(anova_result)
##              Df   Sum Sq Mean Sq F value Pr(>F)    
## estrato       3 14420497 4806832   110.2 <2e-16 ***
## Residuals   587 25611077   43630                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# 2.2.2. Boxplot para Estrato
# Definir colores para cada nivel de la variable estrato
colores_estrato <- c("red", "blue", "green", "orange")  # Ajusta los colores según sea necesario
# Crear boxplot para la variable estrato con colores diferenciados
boxplot_estrato <- plot_ly(data_casas, x = ~estrato, y = ~preciom, type = 'box', color = ~estrato, colors = colores_estrato) %>%
  layout(title = 'Distribución del Precio por Estrato',
         xaxis = list(title = 'Estrato'), yaxis = list(title = 'Precio'))
# Mostrar el boxplot
boxplot_estrato

Incremento del Precio con el Estrato: A medida que el estrato aumenta (de 3 a 6), también se observa un incremento en el precio de las viviendas. Esto sugiere una relación directa entre el estrato socioeconómico y el valor de la propiedad, donde los estratos más altos tienden a tener precios más elevados.

Significancia Estadística: La tabla que acompaña la gráfica muestra un resultado de ANOVA con un valor de p muy pequeño (<2e-16), lo que indica que las diferencias en el precio entre los diferentes estratos son estadísticamente significativas. Esto respalda la observación visual de que el estrato tiene un impacto considerable en el precio de las viviendas.

Estimación Modelo Lineal

# 3. Estimación del modelo de regresión lineal múltiple
modelo <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = data_casas)
summary(modelo) # Resumen del modelo
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = data_casas)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -759.01  -70.05  -14.87   40.70 1000.15 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    9.88597   29.04995   0.340   0.7338    
## areaconst      0.65604    0.05714  11.480  < 2e-16 ***
## estrato4      78.22125   26.27548   2.977   0.0031 ** 
## estrato5     143.11394   24.34022   5.880 8.97e-09 ***
## estrato6     265.12634   39.90018   6.645 1.05e-10 ***
## habitaciones   7.15024    6.19484   1.154   0.2491    
## parqueaderos  27.94967    6.13971   4.552 7.14e-06 ***
## banios        18.74554    8.47921   2.211   0.0276 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 155.8 on 382 degrees of freedom
##   (201 observations deleted due to missingness)
## Multiple R-squared:  0.6057, Adjusted R-squared:  0.5985 
## F-statistic: 83.84 on 7 and 382 DF,  p-value: < 2.2e-16
coeficientes <- tidy(modelo); print(coeficientes) # Obtener coeficientes y p-valores
## # A tibble: 8 × 5
##   term         estimate std.error statistic  p.value
##   <chr>           <dbl>     <dbl>     <dbl>    <dbl>
## 1 (Intercept)     9.89    29.0        0.340 7.34e- 1
## 2 areaconst       0.656    0.0571    11.5   2.07e-26
## 3 estrato4       78.2     26.3        2.98  3.10e- 3
## 4 estrato5      143.      24.3        5.88  8.97e- 9
## 5 estrato6      265.      39.9        6.64  1.05e-10
## 6 habitaciones    7.15     6.19       1.15  2.49e- 1
## 7 parqueaderos   27.9      6.14       4.55  7.14e- 6
## 8 banios         18.7      8.48       2.21  2.76e- 2
  • Modelo de Regresión: El modelo de regresión tiene un R-cuadrado múltiple de 0.6057 y un R-cuadrado ajustado de 0.5985, lo que indica que aproximadamente el 60% de la variabilidad en el precio puede explicarse por las variables independientes incluidas en el modelo. Esto sugiere que el modelo es moderadamente bueno para predecir el precio basado en las variables seleccionadas.

  • El valor de F-statistic de 83.84 y un p-valor < 2.2e-16 indican que el modelo en su conjunto es altamente significativo, lo que significa que al menos una de las variables independientes tiene una relación significativa con la variable dependiente (precio).

  • Intercepto: No es significativo con un p-valor de 0.734, lo que sugiere que el valor predicho del precio cuando todas las variables independientes son cero no es diferente de cero.

  • areaconst (Área Construida): Tiene un coeficiente de 0.656, que es altamente significativo (p-valor de 2.07e-26), lo que indica que por cada unidad adicional de área construida, el precio aumenta en 0.656 unidades, manteniendo las demás variables constantes.

  • Estratos: Todos los coeficientes asociados con los estratos (4, 5, 6) son significativos y positivos: Estrato 4: Incrementa el precio en 78.2 unidades (p-valor de 0.0031). Estrato 5: Incrementa el precio en 143 unidades (p-valor de 8.97e-9). Estrato 6: Incrementa el precio en 265 unidades (p-valor de 1.05e-10).

  • Esto confirma que el estrato socioeconómico tiene un impacto significativo en el precio de las propiedades, siendo mayor en los estratos más altos.

  • Habitaciones: Aunque su coeficiente es positivo (7.15), no es estadísticamente significativo (p-valor de 0.249), lo que sugiere que **el número de habitaciones no tiene un impacto significativo en el precio dentro de este modelo.

  • Parqueaderos: Tiene un coeficiente significativo de 27.9 (p-valor de 7.14e-6), lo que indica que tener parqueaderos aumenta el precio de la propiedad.

  • Baños: También es significativo con un coeficiente de 18.7 (p-valor de 0.0276), lo que sugiere que el número de baños tiene un impacto positivo en el precio, aunque es menos pronunciado en comparación con otras variables como el área construida y los estratos.

Supuestos

# 4. Validación de supuestos
###################################################################
# 4.1 Linealidad y Homoscedasticidad: Graficar residuos vs. valores ajustados
###################################################################
ggplot(modelo, aes(x = .fitted, y = .resid)) +
  geom_point() +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  labs(title = "Residuos vs. Valores Ajustados", x = "Valores Ajustados", y = "Residuos")

###################################################################
# 4.2 Independencia de los Errores: Gráfico de residuos vs. orden
###################################################################
ggplot(modelo, aes(x = seq_along(.resid), y = .resid)) +
  geom_point() +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  labs(title = "Residuos vs. Orden", x = "Orden", y = "Residuos")

###################################################################
# 4.3 Normalidad de los Errores: Histograma de residuos y Q-Q plot
###################################################################
par(mfrow = c(1, 2))  # Configurar para múltiples gráficos
hist(modelo$residuals, main = "Histograma de Residuos", xlab = "Residuos")
qqnorm(modelo$residuals, main = "Q-Q Plot de Residuos")
qqline(modelo$residuals, col = "red")

par(mfrow = c(1, 1))  # Volver a la configuración original
# Prueba de Shapiro-Wilk
shapiro_test <- shapiro.test(modelo$residuals)
print(shapiro_test)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo$residuals
## W = 0.83179, p-value < 2.2e-16
# Cargar el paquete lmtest
library(lmtest)

# Prueba de Breusch-Pagan
bp_test <- bptest(modelo)
print(bp_test)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 68.919, df = 7, p-value = 2.443e-12

Análisis Supuestos

Linealidad:

  • El gráfico de residuos vs. valores ajustados sugiere que la relación entre las variables independientes y la dependiente es aproximadamente lineal, aunque hay cierta variabilidad en los residuos que podría indicar que la linealidad no es perfecta. Independencia de los Errores:

  • El gráfico de residuos vs. orden muestra que no hay un patrón claro, lo que sugiere que los errores son independientes entre sí, cumpliendo así con este supuesto.

  • Normalidad de los Residuos: La prueba de Shapiro-Wilk arrojó un p-valor extremadamente bajo (< 2.2e-16), lo que indica que los residuos no siguen una distribución normal. Esto podría afectar la validez de las inferencias estadísticas basadas en este modelo.

  • Homoscedasticidad: La prueba de Breusch-Pagan arrojó un p-valor muy bajo (2.443e-12), indicando la presencia de heterocedasticidad. Esto significa que la variabilidad de los errores no es constante, lo que podría llevar a estimaciones ineficientes y errores estándar incorrectos.

Predicción:

# Crear un DataFrame con las características de la vivienda
vivienda1 <- data.frame(areaconst = 200,estrato = factor(c(4, 5), levels = levels(data_casas_clean$estrato)), banios = 2,habitaciones = 4, parqueaderos = 1)
# Predecir el precio
predicciones <- predict(modelo, newdata = vivienda1)
# Mostrar las predicciones
print(predicciones)
##        1        2 
## 313.3562 378.2489

Al comparar las dos predicciones, se observa que la vivienda ubicada en el estrato 5 tiene un precio predicho significativamente más alto (alrededor de 64.89 unidades más) que la vivienda en el estrato 4, manteniendo constantes las demás características. Esto confirma nuevamente la influencia significativa del estrato socioeconómico en el precio de las propiedades, con los precios incrementando a medida que se sube de estrato.

Sugerencias potenciales:

# Filtrar y seleccionar las 5 ofertas más baratas
ofertas <- data %>%
  filter(preciom >= min(predicciones) & preciom <= max(predicciones), 
         areaconst >= 200,  # Ajustar según el rango deseado
         parqueaderos == 1, 
         banios == 2, 
         habitaciones == 4, 
         tipo == "Casa",
         zona == "Zona Norte",
         estrato %in% c(4, 5)) %>%
  arrange(preciom) %>%
  head(5)
# Crear el mapa
leaflet(ofertas) %>% addTiles() %>%
  addCircleMarkers(~longitud, ~latitud, color = 'blue', 
                   popup = ~paste("<br>Tipo:", tipo, "<br>Área:", areaconst, "<br>Parqueaderos:", parqueaderos, "<br>Baños:", banios, "<br>Habitaciones:", habitaciones, "<br>Estrato:", estrato, "<br>Zona:", zona, "<br>Precio:", preciom), 
                   radius = 8, fillOpacity = 0.7) %>% setView(lng = mean(ofertas$longitud), lat = mean(ofertas$latitud), zoom = 12)
# Mostrando los resultados
print(ofertas %>% select(preciom, areaconst, parqueaderos, banios, habitaciones, estrato))
## # A tibble: 1 × 6
##   preciom areaconst parqueaderos banios habitaciones estrato
##     <dbl>     <dbl>        <dbl>  <dbl>        <dbl>   <dbl>
## 1     350       346            1      2            4       5

Resultado:

  • Después de aplicar estos filtros, solo una vivienda cumple con todos los criterios especificados. Esto indica que las condiciones de búsqueda son bastante específicas y que la base de datos contiene muy pocas propiedades que se ajustan exactamente a este perfil. Interpretación:

  • Esta única vivienda representa un caso que encaja perfectamente con las condiciones establecidas para la búsqueda, lo cual puede ser útil para análisis más detallados, comparaciones con predicciones o decisiones de compra.

Sugerencias potenciales:

# Filtrar y seleccionar las 5 ofertas más baratas
ofertas <- data %>%
  filter(preciom >= min(predicciones) & preciom <= max(predicciones), 
         ##areaconst >= 300,  # Ajustar según el rango deseado
         ##parqueaderos == 1, 
         banios == 2, 
         habitaciones == 4, 
         tipo == "Casa",
         zona == "Zona Norte",
         estrato %in% c(4, 5)) %>%
  arrange(preciom) %>%
  head(5)
# Crear el mapa
leaflet(ofertas) %>% addTiles() %>%
  addCircleMarkers(~longitud, ~latitud, color = 'blue', 
                   popup = ~paste("<br>Tipo:", tipo, "<br>Área:", areaconst, "<br>Parqueaderos:", parqueaderos, "<br>Baños:", banios, "<br>Habitaciones:", habitaciones, "<br>Estrato:", estrato, "<br>Zona:", zona, "<br>Precio:", preciom), 
                   radius = 8, fillOpacity = 0.7) %>% setView(lng = mean(ofertas$longitud), lat = mean(ofertas$latitud), zoom = 12)
# Mostrando los resultados
print(ofertas %>% select(preciom, areaconst, parqueaderos, banios, habitaciones, estrato))
## # A tibble: 4 × 6
##   preciom areaconst parqueaderos banios habitaciones estrato
##     <dbl>     <dbl>        <dbl>  <dbl>        <dbl>   <dbl>
## 1     340       295            2      2            4       4
## 2     350       216            2      2            4       5
## 3     350       346            1      2            4       5
## 4     360       216            2      2            4       4

Resultado:

  • Al ampliar un poco mas el rango podemos ver mas posibles ofertas.