Actividad 2. Caso C&A

library(paqueteMODELOS)
library(naniar)
library(knitr)
library(kableExtra)
library(lmtest)
library(leaflet)
library(ggplot2)
library(plotly)
library(corrplot)

data(vivienda)
datos <- vivienda
#visualizar datos faltantes
print(faltantes <- colSums(is.na(datos)) %>%
  as.data.frame()) 
##                 .
## id              3
## zona            3
## piso         2638
## estrato         3
## preciom         2
## areaconst       3
## parqueaderos 1605
## banios          3
## habitaciones    3
## tipo            3
## barrio          3
## longitud        3
## latitud         3
gg_miss_var(datos)  # Muestra la proporción de datos faltantes por cada variable

Las variables ‘piso’ y ‘parqueadero’ presentan gran cantidad de datos faltantes, por ende, se decide eliminar la variable ‘piso’, y para la variable ‘parqueadero’ se imputará con un valor fijo, tomando (0) suponiendo que las propiedades no tienen parqueaderos. A su vez, se decide por eliminar las variables ‘id’ y ‘barrio’ que no son relevantes en el análisis.

datos <- subset(datos, select = -c(id, piso, barrio))
#Rellenando valores NA de parqueadero
datos$parqueaderos[is.na(datos$parqueaderos)] <- 0
# Posteriormente, se eliminan filas con valores faltantes
datos <- datos[complete.cases(datos), ]
# Se visualiza la efectividad de los procesos de eliminación de datos faltantes
print(colSums(is.na(datos)) %>%
  as.data.frame()) 
##              .
## zona         0
## estrato      0
## preciom      0
## areaconst    0
## parqueaderos 0
## banios       0
## habitaciones 0
## tipo         0
## longitud     0
## latitud      0
print(datos)
## # A tibble: 8,319 × 10
##    zona         estrato preciom areaconst parqueaderos banios habitaciones tipo 
##    <chr>          <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
##  1 Zona Oriente       3     250        70            1      3            6 Casa 
##  2 Zona Oriente       3     320       120            1      2            3 Casa 
##  3 Zona Oriente       3     350       220            2      2            4 Casa 
##  4 Zona Sur           4     400       280            3      5            3 Casa 
##  5 Zona Norte         5     260        90            1      2            3 Apar…
##  6 Zona Norte         5     240        87            1      3            3 Apar…
##  7 Zona Norte         4     220        52            2      2            3 Apar…
##  8 Zona Norte         5     310       137            2      3            4 Apar…
##  9 Zona Norte         5     320       150            2      4            6 Casa 
## 10 Zona Norte         5     780       380            2      3            3 Casa 
## # ℹ 8,309 more rows
## # ℹ 2 more variables: longitud <dbl>, latitud <dbl>
  1. Ofertas de casas de la zona norte de la ciudad.
df_casas = subset(datos, (datos$zona == "Zona Norte" & datos$tipo == "Casa"))
head(df_casas, 3)
## # A tibble: 3 × 10
##   zona       estrato preciom areaconst parqueaderos banios habitaciones tipo 
##   <chr>        <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
## 1 Zona Norte       5     320       150            2      4            6 Casa 
## 2 Zona Norte       5     780       380            2      3            3 Casa 
## 3 Zona Norte       6     750       445            0      7            6 Casa 
## # ℹ 2 more variables: longitud <dbl>, latitud <dbl>
resul = data.frame(table(df_casas$tipo), table(df_casas$zona))
colnames(resul) = c("tipo", "conteo", "zona", "conteo")
resul
##   tipo conteo       zona conteo
## 1 Casa    722 Zona Norte    722
mapa_nort = leaflet() %>% addCircleMarkers(lng = df_casas$longitud,
                                           lat = df_casas$latitud,
                                           radius = 0.3,
                                           color = "blue",
                                           label = df_casas$id) %>% addTiles()
mapa_nort

A partir del análisis de la ubicación de las propiedades, se ha observado que gran parte de las propiedades de la zona norte son casas. Además, se detectan otras propiedades que se distribuyen de manera poco común en otras áreas de la ciudad. Esta anomalía es causada por posibles errores en la recopilación de datos.

Esta variabilidad atípica puede deberse a la interpretación de los resultados y a la toma de decisiones fundamentadas en estos datos. Por ello, es crucial tener en cuenta este factor al examinar y emplear información geoespacial, con el fin de evitar conclusiones inexactas o sesgadas. Siempre que sea posible, se sugiere realizar una revisión minuciosa de los registros de ubicación para identificar y corregir posibles errores, garantizando así la precisión de los datos geográficos en el análisis.

  1. 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, número de habitaciones y zona donde se ubica la vivienda.
df_casas = subset(datos, (datos$tipo == "Casa"))
grafico_area <- plot_ly(data = df_casas, x = ~areaconst, y = ~preciom, type = "scatter", mode = "markers") %>%
  layout(title = "Precio vs Área Construida",
         xaxis = list(title = "Área Construida"),
         yaxis = list(title = "Precio"))
grafico_area
summary(df_casas$areaconst)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    30.0   154.0   240.0   273.4   350.0  1745.0
correlacion_pearson <- cor(df_casas$areaconst, df_casas$preciom, method = "pearson")
print(correlacion_pearson)
## [1] 0.6529498

La media con respecto al área de la vivienda se sitúa en 273.4 metros cuadrados, lo que indica el promedio de todos los valores registrados. Por otro lado, la mediana se ubica en 240 metros cuadrados, lo que sugiere que la mitad de las propiedades tienen un área inferior a este valor central. Al observar la relación entre el metro cuadrado y el precio, se nota que no existe una correlación fuerte y directamente proporcional. Esto es respaldado por el coeficiente de correlación de Pearson, con un valor específico de 0.6529.

grafico_estrato <- plot_ly(data = df_casas, x = ~estrato, y = ~preciom, type = "box") %>%
  layout(title = "Precio vs Estrato",
         xaxis = list(title = "Estrato"),
         yaxis = list(title = "Precio"))
grafico_estrato
correlacion_spearman <- cor(df_casas$preciom, df_casas$estrato, method = "spearman")
print(correlacion_spearman)
## [1] 0.7530054

En primer lugar, se puede apreciar que la relación entre el estrato socioeconómico y el precio es proporcional directa, y se justifica por el coeficiente de correlación de 0.7530. Algunas de las propiedades ubicadas en estrato 5 presentan valores de venta más altos, cerca de 1999 millones de pesos, debido a la presencia de valores atípicos identificados. Además, el 75 % de las propiedades tienen un precio por encia de los 650 millones de pesos y la mediana en el precio de venta es 480 millones de pesos, indicando que mitad de las propiedades tienen un precio de venta inferior a este valor.

grafico_banos <- plot_ly(data = df_casas, x = ~banios, y = ~preciom, type = "scatter", mode = "markers") %>%
  layout(title = "Precio vs Número de Baños",
         xaxis = list(title = "Número de Baños"),
         yaxis = list(title = "Precio"))
grafico_banos
correlacion_pearson <- cor(df_casas$preciom, df_casas$banios, method = "pearson")
print(correlacion_pearson)
## [1] 0.5581002
summary(df_casas$banios)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   3.000   4.000   3.894   5.000  10.000

Para el número de baños, se calcula una media de 3.89 unidades, representando el valor promedio de todos los valores, mientras que la mediana es de 4 unidades, lo que sugiere que la mitad de las propiedades tienen cuatro baños o menos. Al examinar la relación entre el número de baños y el precio, se observa una dispersión en los datos. El coeficiente de correlación de Pearson obtenido es 0.5581, lo que indica una relación débil entre el precio y el número de baños.

grafico_habitaciones <- plot_ly(data = df_casas, x = ~habitaciones, y = ~preciom, type = "scatter", mode = "markers") %>%
  layout(title = "Precio vs Número de Habitaciones",
         xaxis = list(title = "Número de Habitaciones"),
         yaxis = list(title = "Precio"))
grafico_habitaciones
correlacion_pearson <- cor(df_casas$preciom, df_casas$habitaciones, method = "pearson")
print(correlacion_pearson)
## [1] 0.09683573
summary(df_casas$habitaciones)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.00    3.00    4.00    4.61    5.00   10.00

En cuanto al número de habitaciones, la media es de 4.61 unidades y la mediana es de 4 unidades. Esto sugiere que, en promedio, las propiedades tienen aproximadamente cuatro habitaciones, y la mitad de las propiedades tienen cuatro habitaciones o menos. Al igual que con el número de baños, se observa una dispersión debil en la relación entre el número de habitaciones y el precio. El coeficiente de correlación de Pearson presenta un valor de de 0.097.

grafico_zona <- plot_ly(data = df_casas, x = ~zona, y = ~preciom, type = "box") %>%
  layout(title = "Precio vs Zona",
         xaxis = list(title = "Zona"),
         yaxis = list(title = "Precio"))
grafico_zona
anova_result <- aov(preciom ~ zona, data = df_casas)
summary(anova_result)
##               Df    Sum Sq  Mean Sq F value Pr(>F)    
## zona           4  52244372 13061093   116.4 <2e-16 ***
## Residuals   3214 360654741   112214                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

En cuanto a la ubicación de las propiedades, la zona oeste presenta la mediana más alta, indicando que la mitad de las propiedades tienen un precio de 680 millones de pesos en el mercado inmobiliario. Además, alrededor del 75 % de las casas tienen un precio de venta cercano a 935 millones de pesos en dicha zona. El análisis de varianza (ANOVA) sugiere que existen diferencias significativas en el precio de la casa entre las diferentes zonas.El valor p (<2e-16) es mucho menor que el nivel de significancia común (0.05), por lo que rechazamos la hipótesis nula de que no hay diferencias entre las zonas.

  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).
df_casas$estrato = as.numeric(df_casas$estrato)
modelo1=lm(preciom~ areaconst + estrato + habitaciones + parqueaderos + banios, df_casas)
summary(modelo1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = df_casas)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1319.88  -113.30   -25.16    69.75  1179.44 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -345.92562   20.29873 -17.042  < 2e-16 ***
## areaconst       0.81001    0.02538  31.913  < 2e-16 ***
## estrato       112.80957    4.44614  25.372  < 2e-16 ***
## habitaciones  -13.63190    2.57845  -5.287 1.33e-07 ***
## parqueaderos   40.30572    2.78541  14.470  < 2e-16 ***
## banios         38.52338    3.32115  11.599  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 203.9 on 3213 degrees of freedom
## Multiple R-squared:  0.6765, Adjusted R-squared:  0.676 
## F-statistic:  1344 on 5 and 3213 DF,  p-value: < 2.2e-16

El término independiente, o intercepto, se establece en -345.9256. Esto indica el valor estimado de una vivienda cuando todas las demás variables en el modelo están en cero. En la práctica, este escenario es poco probable, ya que no puede haber una casa con área construida, estrato, habitaciones, parqueaderos y baños iguales a cero.

El coeficiente correspondiente al área construida es de 0.81. Esto implica que por cada metro cuadrado adicional en la propiedad, el precio aumenta en 0.81 millones de pesos, manteniendo las otras variables constantes. Similarmente, el coeficiente para el estrato es de 112.81, indicando que por cada aumento de un nivel en el estrato socioeconómico, el precio de la casa aumenta en 112.81 millones de pesos, manteniendo constantes las demás variables. A su vez, el coeficiente indicado parra el número de habitaciones indica que por cada habitación adicional, el precio de la casa disminuye en 13.63 millones de pesos, manteniendo constantes las demás variables. Este resultado podría indicar un problema de multicolinealidad o una relación no lineal. El coeficiente correspondiente a parqueaderos indica que por cada parqueadero adicional, el precio de la casa aumenta en 40.31 millones de pesos, manteniendo constantes las demás variables. Del mismo modo, El coeficiente relacionado por el número de baños indica que por cada baño adicional, el precio de la casa aumenta en 38.52 millones de pesos, manteniendo constantes las demás variables.

El coeficiente de determinación R² se calcula en 0.6765. Esto significa que aproximadamente el 67.65% de la variabilidad observada en los precios de las casas puede ser explicada por las variables incluidas en el modelo.

En términos de mejoras al modelo, se sugiere considerar la eliminación de variables que no aporten significativamente al modelo para aumentar su eficacia o realizar transformaciones a relaciones no lineales.

  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).
#Linealidad
# Gráfico de residuos vs valores ajustados
plot(fitted(modelo1), residuals(modelo1), main = "Residuos vs Ajustados", xlab = "Valores Ajustados", ylab = "Residuos")
abline(h = 0, col = "red")

# Prueba de Durbin-Watson
library(lmtest)
dwtest(modelo1)
## 
##  Durbin-Watson test
## 
## data:  modelo1
## DW = 1.5127, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0
# Prueba de Breusch-Pagan
library(lmtest)
bptest(modelo1)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo1
## BP = 397.81, df = 5, p-value < 2.2e-16
# Histograma de residuos
hist(residuals(modelo1), main = "Histograma de Residuos", xlab = "Residuos")

# Prueba de Shapiro-Wilk
shapiro.test(residuals(modelo1))
## 
##  Shapiro-Wilk normality test
## 
## data:  residuals(modelo1)
## W = 0.88308, p-value < 2.2e-16
# Calcular VIF
library(car)
vif(modelo1)
##    areaconst      estrato habitaciones parqueaderos       banios 
##     1.465483     1.818414     1.613973     1.552399     2.102466

En la gráfica de linealidad se observa que los residuos no se distribuyen aleatoriamente alrededor de la línea horizontal en 0, creando patrones claros de agrupamiento, y por tanto no se cumple el supuesto de linealidad. En el valor estadístico de Durbin-Watson, se aprecia que DW = 1.51, indicando que existe autocorrelación positiva. Asimismo, en la prueba de Breusch-Pagan, el valor p es menor que 0.05, indicando presencia de heterocedasticidad. La prueba de Shapiro-Wilk el valor p es menor que el umbral 0.05, y los residuos no siguen una distribución normal. Además, el Factor de Inflación de la Varianza (VIF) para cada variable fue menor que 5, indicando que no hay multicolinealidad.

Para corregir estos aspectos se podría considerar la transformación de la variable dependiente o también se podría solucionar utilizando modelos más robustos.

  1. Con el modelo identificado debe predecir el precio de la vivienda con las características de la primera solicitud.
df1= data.frame(
  areaconst = 200,
  parqueaderos = 1,
  estrato = c(4, 5),
  banios = 2,
  habitaciones = 4,
  tipo='Casa',
  zona='Norte'
)
df1
##   areaconst parqueaderos estrato banios habitaciones tipo  zona
## 1       200            1       4      2            4 Casa Norte
## 2       200            1       5      2            4 Casa Norte
predict(modelo1,df1)
##        1        2 
## 330.1387 442.9483
  1. Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 1. Tenga encuentra 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.
# Generar predicciones
df_casas$prediccion <- predict(modelo1, newdata = df_casas)
# Filtrar viviendas dentro del rango
ofertas <- df_casas %>% filter(prediccion <= 350, areaconst <= 200, parqueaderos <= 1, 
                               banios <= 2, habitaciones <= 4, zona == "Zona Norte", 
                               estrato ==c(4, 5))
# Ordenar por precio predicho y seleccionar las 5 mejores ofertas
ofertas <- ofertas %>% arrange(prediccion) %>% head(5)

# Seleccionar columnas relevantes para la tabla
ofertas_tabla <- ofertas %>%
  select(prediccion, areaconst, estrato, habitaciones, banios, parqueaderos, latitud, longitud)

library(DT)

# Creación de la tabla
datatable(ofertas_tabla, 
          colnames = c("#", "Precio Predicho (Millones de pesos)", "Área Construida (m²)", "Estrato", 
                       "Habitaciones", "Baños", "Parqueaderos", "Latitud", "Longitud"),
          options = list(
            pageLength = 5, 
            dom = 't',       
            scrollX = TRUE  
          ))
library(leaflet)
mapa <- leaflet(ofertas) %>%
  addTiles() %>%  
  addMarkers(
    lng = ~longitud, lat = ~latitud,
    popup = ~paste(
      "Precio Predicho: $", round(prediccion), "M<br>",
      "Área Construida: ", areaconst, "m²<br>",
      "Estrato: ", estrato, "<br>",
      "Habitaciones: ", habitaciones, "<br>",
      "Baños: ", banios, "<br>",
      "Parqueaderos: ", parqueaderos
    )
  )
mapa

Por medio de un análisis se puede concluir que la quinta oferta es la más apropiada y cumple con gran parte de las características. Además, es importante precisar que cumple con el límite de crédito preaprobado de 350 millones de pesos. Sin embargo, las demás ofertas presentan características y ubicaciones diferentes para discutir opciones viables con el cliente.