Informe de Análisis de Evaluación de la oferta inmobiliaria urbana

Introducción:

Este trabajo abordará el modelo de regresión lineal múltiple, enfocado en la validación de sus supuestos y la realización de predicciones, aplicado a un caso de asesoría inmobiliaria. El trabajo consiste en ayudar a una compañía internacional a tomar decisiones informadas para la compra de dos viviendas en la ciudad, con el objetivo de ubicar a dos de sus empleados y sus familias. A través del modelo, se evaluarán diferentes factores que influyen en el precio de las viviendas, como el tamaño, ubicación y características, para ofrecer recomendaciones basadas en análisis predictivos.

Análisis de Componentes Principales

data("vivienda")
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id          : num [1:8322] 1147 1169 1350 5992 1212 ...
##  $ zona        : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ piso        : chr [1:8322] NA NA NA "02" ...
##  $ estrato     : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
##  $ preciom     : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
##  $ areaconst   : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
##  $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
##  $ banios      : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
##  $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
##  $ tipo        : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
##  $ barrio      : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
##  $ longitud    : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
##  - 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>

Preparación de los datos

Se realiza un resumen estadístico básico de las variables contenidas en la base de datos (Vivienda), se procede a identificar los datos faltantes y de estos datos se indaga en cuantas variables de ese registro se tienen datos faltantes

viviendaII <- vivienda
summary(viviendaII)
##        id           zona               piso              estrato     
##  Min.   :   1   Length:8322        Length:8322        Min.   :3.000  
##  1st Qu.:2080   Class :character   Class :character   1st Qu.:4.000  
##  Median :4160   Mode  :character   Mode  :character   Median :5.000  
##  Mean   :4160                                         Mean   :4.634  
##  3rd Qu.:6240                                         3rd Qu.:5.000  
##  Max.   :8319                                         Max.   :6.000  
##  NA's   :3                                            NA's   :3      
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  30.0   Min.   : 1.000   Min.   : 0.000  
##  1st Qu.: 220.0   1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 330.0   Median : 123.0   Median : 2.000   Median : 3.000  
##  Mean   : 433.9   Mean   : 174.9   Mean   : 1.835   Mean   : 3.111  
##  3rd Qu.: 540.0   3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1999.0   Max.   :1745.0   Max.   :10.000   Max.   :10.000  
##  NA's   :2        NA's   :3        NA's   :1605     NA's   :3       
##   habitaciones        tipo              barrio             longitud     
##  Min.   : 0.000   Length:8322        Length:8322        Min.   :-76.59  
##  1st Qu.: 3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median : 3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   : 3.605                                         Mean   :-76.53  
##  3rd Qu.: 4.000                                         3rd Qu.:-76.52  
##  Max.   :10.000                                         Max.   :-76.46  
##  NA's   :3                                              NA's   :3       
##     latitud     
##  Min.   :3.333  
##  1st Qu.:3.381  
##  Median :3.416  
##  Mean   :3.418  
##  3rd Qu.:3.452  
##  Max.   :3.498  
##  NA's   :3
filas_con_faltantes_precio <- viviendaII[is.na(vivienda$preciom), ]
faltantes_en_otras_variables <- apply(filas_con_faltantes_precio, 1, function(x) sum(is.na(x)))
print(faltantes_en_otras_variables)
## [1] 13 13
umbral_faltantes <- 11  # Establece un umbral para eliminiar
viviendaII <- viviendaII[apply(vivienda, 1, function(x) sum(is.na(x))) <= umbral_faltantes, ]

Se elimina la variable id del conjunto de datos ya que es una variable que no aporta información al conjunto de datos

# Eliminar la columna 'ID'
viviendaII <- subset(vivienda, select = -id)
summary(viviendaII)
##      zona               piso              estrato         preciom      
##  Length:8322        Length:8322        Min.   :3.000   Min.   :  58.0  
##  Class :character   Class :character   1st Qu.:4.000   1st Qu.: 220.0  
##  Mode  :character   Mode  :character   Median :5.000   Median : 330.0  
##                                        Mean   :4.634   Mean   : 433.9  
##                                        3rd Qu.:5.000   3rd Qu.: 540.0  
##                                        Max.   :6.000   Max.   :1999.0  
##                                        NA's   :3       NA's   :2       
##    areaconst       parqueaderos        banios        habitaciones   
##  Min.   :  30.0   Min.   : 1.000   Min.   : 0.000   Min.   : 0.000  
##  1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000   1st Qu.: 3.000  
##  Median : 123.0   Median : 2.000   Median : 3.000   Median : 3.000  
##  Mean   : 174.9   Mean   : 1.835   Mean   : 3.111   Mean   : 3.605  
##  3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000   3rd Qu.: 4.000  
##  Max.   :1745.0   Max.   :10.000   Max.   :10.000   Max.   :10.000  
##  NA's   :3        NA's   :1605     NA's   :3        NA's   :3       
##      tipo              barrio             longitud         latitud     
##  Length:8322        Length:8322        Min.   :-76.59   Min.   :3.333  
##  Class :character   Class :character   1st Qu.:-76.54   1st Qu.:3.381  
##  Mode  :character   Mode  :character   Median :-76.53   Median :3.416  
##                                        Mean   :-76.53   Mean   :3.418  
##                                        3rd Qu.:-76.52   3rd Qu.:3.452  
##                                        Max.   :-76.46   Max.   :3.498  
##                                        NA's   :3        NA's   :3

Se procede a determinar la tecnica mas apropiada para la imputación de los datos númericos

La variable con mas datos nulos es la variable parqueaderos,Se realiza un analisis de dicha variable para determinar la tecnica apropiada para la imputación

# Crear un boxplot para la variable 'parqueaderos'
ggplot(viviendaII, aes(y = parqueaderos)) +
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Boxplot de Parqueaderos",
       y = "Número de Parqueaderos") +
  theme_minimal()
## Warning: Removed 1605 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

# Crear un Q-Q plot
qqnorm(viviendaII$parqueaderos, main = "Q-Q Plot de la Variable")
qqline(viviendaII$parqueaderos, col = "red")

Se observa que esta variable tiene una distribución asimetrica por lo cual se decide imputar los datos faltantes por la mediana

# Calcular la mediana de 'parqueaderos', ignorando los NA
mediana_parqueaderos <- median(viviendaII$parqueaderos, na.rm = TRUE)

# Imputar los datos faltantes en 'parqueaderos' con la mediana
viviendaII$parqueaderos[is.na(viviendaII$parqueaderos)] <- mediana_parqueaderos

summary(viviendaII)
##      zona               piso              estrato         preciom      
##  Length:8322        Length:8322        Min.   :3.000   Min.   :  58.0  
##  Class :character   Class :character   1st Qu.:4.000   1st Qu.: 220.0  
##  Mode  :character   Mode  :character   Median :5.000   Median : 330.0  
##                                        Mean   :4.634   Mean   : 433.9  
##                                        3rd Qu.:5.000   3rd Qu.: 540.0  
##                                        Max.   :6.000   Max.   :1999.0  
##                                        NA's   :3       NA's   :2       
##    areaconst       parqueaderos        banios        habitaciones   
##  Min.   :  30.0   Min.   : 1.000   Min.   : 0.000   Min.   : 0.000  
##  1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000   1st Qu.: 3.000  
##  Median : 123.0   Median : 2.000   Median : 3.000   Median : 3.000  
##  Mean   : 174.9   Mean   : 1.867   Mean   : 3.111   Mean   : 3.605  
##  3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000   3rd Qu.: 4.000  
##  Max.   :1745.0   Max.   :10.000   Max.   :10.000   Max.   :10.000  
##  NA's   :3                         NA's   :3        NA's   :3       
##      tipo              barrio             longitud         latitud     
##  Length:8322        Length:8322        Min.   :-76.59   Min.   :3.333  
##  Class :character   Class :character   1st Qu.:-76.54   1st Qu.:3.381  
##  Mode  :character   Mode  :character   Median :-76.53   Median :3.416  
##                                        Mean   :-76.53   Mean   :3.418  
##                                        3rd Qu.:-76.52   3rd Qu.:3.452  
##                                        Max.   :-76.46   Max.   :3.498  
##                                        NA's   :3        NA's   :3
# Contar datos faltantes en cada variable del data frame
missing_counts <- sapply(viviendaII, function(x) sum(is.na(x)))
print(missing_counts)
##         zona         piso      estrato      preciom    areaconst parqueaderos 
##            3         2638            3            2            3            0 
##       banios habitaciones         tipo       barrio     longitud      latitud 
##            3            3            3            3            3            3

Se procede a transformar la variable piso a numerica y luego definir el metodo de imputación adecuado

# Converción de la variable 'piso' a numerico
viviendaII$piso <- as.numeric(viviendaII$piso)
summary(viviendaII)
##      zona                piso           estrato         preciom      
##  Length:8322        Min.   : 1.000   Min.   :3.000   Min.   :  58.0  
##  Class :character   1st Qu.: 2.000   1st Qu.:4.000   1st Qu.: 220.0  
##  Mode  :character   Median : 3.000   Median :5.000   Median : 330.0  
##                     Mean   : 3.771   Mean   :4.634   Mean   : 433.9  
##                     3rd Qu.: 5.000   3rd Qu.:5.000   3rd Qu.: 540.0  
##                     Max.   :12.000   Max.   :6.000   Max.   :1999.0  
##                     NA's   :2638     NA's   :3       NA's   :2       
##    areaconst       parqueaderos        banios        habitaciones   
##  Min.   :  30.0   Min.   : 1.000   Min.   : 0.000   Min.   : 0.000  
##  1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000   1st Qu.: 3.000  
##  Median : 123.0   Median : 2.000   Median : 3.000   Median : 3.000  
##  Mean   : 174.9   Mean   : 1.867   Mean   : 3.111   Mean   : 3.605  
##  3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000   3rd Qu.: 4.000  
##  Max.   :1745.0   Max.   :10.000   Max.   :10.000   Max.   :10.000  
##  NA's   :3                         NA's   :3        NA's   :3       
##      tipo              barrio             longitud         latitud     
##  Length:8322        Length:8322        Min.   :-76.59   Min.   :3.333  
##  Class :character   Class :character   1st Qu.:-76.54   1st Qu.:3.381  
##  Mode  :character   Mode  :character   Median :-76.53   Median :3.416  
##                                        Mean   :-76.53   Mean   :3.418  
##                                        3rd Qu.:-76.52   3rd Qu.:3.452  
##                                        Max.   :-76.46   Max.   :3.498  
##                                        NA's   :3        NA's   :3
# Crear un boxplot para la variable 'parqueaderos'
ggplot(viviendaII, aes(y = piso)) +
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Boxplot de Parqueaderos",
       y = "Número de Parqueaderos") +
  theme_minimal()
## Warning: Removed 2638 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

# Crear un Q-Q plot
qqnorm(viviendaII$piso, main = "Q-Q Plot de la Variable")
qqline(viviendaII$piso, col = "red")

Se decide imputar los datos faltantes por la media ya que piso es una variable numérica y tiende a tener una distribución simétrica sin outliers significativos.

# Se calcula la media de la variable 'piso', ignorando los NA
mean_piso <- mean(viviendaII$piso, na.rm = TRUE)

# Se realiza la imputación datos faltantes en 'piso' con la media
viviendaII$piso[is.na(viviendaII$piso)] <- mean_piso

# Contar datos faltantes en cada variable del data frame
missing_counts <- sapply(viviendaII, function(x) sum(is.na(x)))
print(missing_counts)
##         zona         piso      estrato      preciom    areaconst parqueaderos 
##            3            0            3            2            3            0 
##       banios habitaciones         tipo       barrio     longitud      latitud 
##            3            3            3            3            3            3
# Verificar el número de filas antes y después de la eliminación
cat("Número de filas antes de eliminar:", nrow(viviendaII), "\n")
## Número de filas antes de eliminar: 8322
<se decide eliminar el los registros que tienen datos nulos ya que se observa que no son representativos para el analisis

filas_con_faltantes_precio <- viviendaII[is.na(viviendaII$preciom), ]

print(filas_con_faltantes_precio)
## # A tibble: 2 × 12
##   zona   piso estrato preciom areaconst parqueaderos banios habitaciones tipo 
##   <chr> <dbl>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
## 1 <NA>   3.77      NA      NA        NA            2     NA           NA <NA> 
## 2 <NA>   3.77      NA      NA        NA            2     NA           NA <NA> 
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
faltantes_en_otras_variables <- apply(filas_con_faltantes_precio, 1, function(x) sum(is.na(x)))
print(faltantes_en_otras_variables)
## [1] 10 10
umbral_faltantes <- 8  # Establece un umbral de variables vacias
viviendaII <- viviendaII[apply(viviendaII, 1, function(x) sum(is.na(x))) <= umbral_faltantes, ]


# Contar datos faltantes en cada variable del data frame
missing_counts <- sapply(viviendaII, function(x) sum(is.na(x)))
print(missing_counts)
##         zona         piso      estrato      preciom    areaconst parqueaderos 
##            0            0            0            0            0            0 
##       banios habitaciones         tipo       barrio     longitud      latitud 
##            0            0            0            0            0            0
cat("Número de filas después de eliminar:", nrow(viviendaII), "\n")
## Número de filas después de eliminar: 8319

Se implementa un boxplot como método visual para detectar outliers .Los puntos fuera de los bigotes del boxplot suelen ser considerados outliers.

# Seleccionar solo las columnas numéricas
numericas <- viviendaII[sapply(viviendaII, is.numeric)]

# Crear una función para graficar boxplots de todas las variables numéricas
library(reshape2) # Para convertir a formato largo

# Convertir el data frame a formato largo
vivienda_long <- melt(numericas)
## No id variables; using all as measure variables
# Crear boxplots
ggplot(vivienda_long, aes(x = variable, y = value)) +
  geom_boxplot() +
  labs(title = "Boxplots de Variables Numéricas",
       x = "Variable",
       y = "Valor") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Crear un boxplot para la variable 'preciom'
ggplot(viviendaII, aes(y = preciom)) +
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Boxplot de preciom",
       y = "Precio") +
  theme_minimal()

# Crear un Q-Q plot
qqnorm(viviendaII$preciom, main = "Q-Q Plot de la Variable")
qqline(viviendaII$preciom, col = "red")

# Crear un boxplot para la variable 'areaconst'
ggplot(viviendaII, aes(y = areaconst)) +
  geom_boxplot(fill = "lightblue", color = "black") +
  labs(title = "Boxplot de areaconst",
       y = "areaconst") +
  theme_minimal()

# Crear un Q-Q plot
qqnorm(viviendaII$areaconst, main = "Q-Q Plot de la Variable")
qqline(viviendaII$areaconst, col = "red")

DESARROLLO DE ACTIVIDAD

  1. Realice un filtro a la base de datos e incluya sólo las ofertas de apartamentos. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta.

# Filtrar la base de datos para incluir solo apartamentos
vivienda_apartamentos <- filter(viviendaII, tipo == "Apartamento")
# Mostrar los primeros 3 registros de la base de datos filtrada
head(vivienda_apartamentos, 3)
## # A tibble: 3 × 12
##   zona     piso estrato preciom areaconst parqueaderos banios habitaciones tipo 
##   <chr>   <dbl>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl> <chr>
## 1 Zona N…     1       5     260        90            1      2            3 Apar…
## 2 Zona N…     1       5     240        87            1      3            3 Apar…
## 3 Zona N…     1       4     220        52            2      2            3 Apar…
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
# Comprobar la consulta: tabla de frecuencias de la columna 'tipo'
table(vivienda_apartamentos$tipo)
## 
## Apartamento 
##        5100
# Resumen de la base de datos filtrada para verificar otras características
summary(vivienda_apartamentos)
##      zona                piso           estrato         preciom      
##  Length:5100        Min.   : 1.000   Min.   :3.000   Min.   :  58.0  
##  Class :character   1st Qu.: 3.000   1st Qu.:4.000   1st Qu.: 175.0  
##  Mode  :character   Median : 3.771   Median :5.000   Median : 279.0  
##                     Mean   : 4.400   Mean   :4.727   Mean   : 366.9  
##                     3rd Qu.: 5.000   3rd Qu.:6.000   3rd Qu.: 430.0  
##                     Max.   :12.000   Max.   :6.000   Max.   :1950.0  
##    areaconst      parqueaderos        banios       habitaciones  
##  Min.   : 35.0   Min.   : 1.000   Min.   :0.000   Min.   :0.000  
##  1st Qu.: 68.0   1st Qu.: 1.000   1st Qu.:2.000   1st Qu.:3.000  
##  Median : 90.0   Median : 2.000   Median :2.000   Median :3.000  
##  Mean   :112.8   Mean   : 1.641   Mean   :2.617   Mean   :2.971  
##  3rd Qu.:130.0   3rd Qu.: 2.000   3rd Qu.:3.000   3rd Qu.:3.000  
##  Max.   :932.0   Max.   :10.000   Max.   :8.000   Max.   :9.000  
##      tipo              barrio             longitud         latitud     
##  Length:5100        Length:5100        Min.   :-76.59   Min.   :3.334  
##  Class :character   Class :character   1st Qu.:-76.54   1st Qu.:3.380  
##  Mode  :character   Mode  :character   Median :-76.53   Median :3.419  
##                                        Mean   :-76.53   Mean   :3.419  
##                                        3rd Qu.:-76.52   3rd Qu.:3.453  
##                                        Max.   :-76.46   Max.   :3.498

  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.

# Seleccionar las variables de interés
datos_correlacion <- select(vivienda_apartamentos, preciom, areaconst, estrato, banios, habitaciones)

# Calcular la matriz de correlación
matriz_correlacion <- cor(datos_correlacion, use = "complete.obs")

# Mostrar la matriz de correlación
matriz_correlacion
##                preciom areaconst   estrato    banios habitaciones
## preciom      1.0000000 0.8287437 0.6672717 0.7404732    0.2974940
## areaconst    0.8287437 1.0000000 0.5492273 0.7267377    0.4092708
## estrato      0.6672717 0.5492273 1.0000000 0.6155148    0.1778522
## banios       0.7404732 0.7267377 0.6155148 1.0000000    0.5006605
## habitaciones 0.2974940 0.4092708 0.1778522 0.5006605    1.0000000
GGally::ggpairs(datos_correlacion)

fig_area <- plot_ly(data = vivienda_apartamentos, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers',
                    marker = list(size = 10, color = 'rgba(152, 0, 0, .8)',
                                  line = list(color = 'rgba(152, 0, 0, 1.0)', width = 2))) %>%
  layout(title = "Precio vs. Área Construida",
         xaxis = list(title = "Área Construida (m²)"),
         yaxis = list(title = "Precio (millones)"))

fig_area
fig_banios <- plot_ly(data = vivienda_apartamentos, x = ~banios, y = ~preciom, type = 'scatter', mode = 'markers',
                      marker = list(size = 10, color = 'rgba(0, 152, 0, .8)',
                                    line = list(color = 'rgba(0, 152, 0, 1.0)', width = 2))) %>%
  layout(title = "Precio vs. Número de Baños",
         xaxis = list(title = "Número de Baños"),
         yaxis = list(title = "Precio (millones)"))

fig_banios
fig_habitaciones <- plot_ly(data = vivienda_apartamentos, x = ~habitaciones, y = ~preciom, type = 'scatter', mode = 'markers',
                            marker = list(size = 10, color = 'rgba(0, 0, 152, .8)',
                                          line = list(color = 'rgba(0, 0, 152, 1.0)', width = 2))) %>%
  layout(title = "Precio vs. Número de Habitaciones",
         xaxis = list(title = "Número de Habitaciones"),
         yaxis = list(title = "Precio (millones)"))

fig_habitaciones
fig_estrato <- plot_ly(data = vivienda_apartamentos, x = ~estrato, y = ~preciom, type = 'scatter', mode = 'markers',
                       marker = list(size = 10, color = 'rgba(152, 152, 0, .8)',
                                     line = list(color = 'rgba(152, 152, 0, 1.0)', width = 2))) %>%
  layout(title = "Precio vs. Estrato",
         xaxis = list(title = "Estrato"),
         yaxis = list(title = "Precio (millones)"))

fig_estrato

INTERPRETACIÓN:

El precio de la vivienda (preciom) muestra una correlación moderada con el área construida (areaconst), el estrato socioeconómico (estrato) y el número de baños (banios), lo que sugiere que estas variables son buenos predictores del precio. En particular, el área y los baños están más estrechamente relacionados con el valor de la vivienda, lo que refuerza su relevancia en la determinación del precio.

El número de habitaciones presenta una relación más débil con el precio en comparación con las demás variables, indicando que el número de habitaciones no es tan influyente en la fijación del valor de la vivienda.

La falta de correlación significativa entre el estrato y el número de habitaciones sugiere que el tamaño y la cantidad de habitaciones no son necesariamente un reflejo del nivel socioeconómico de una vivienda, lo que podría deberse a otros factores más específicos de cada estrato.

  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).

# Estimación del modelo de regresión lineal múltiple
modelo <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = vivienda_apartamentos)

# Resumen del modelo
summary(modelo)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = vivienda_apartamentos)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1750.71   -57.83    -1.81    49.01   995.32 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -341.52301   13.31306  -25.65   <2e-16 ***
## areaconst       2.06443    0.04269   48.36   <2e-16 ***
## estrato        66.98964    2.50629   26.73   <2e-16 ***
## habitaciones  -33.70024    3.26211  -10.33   <2e-16 ***
## parqueaderos   72.23139    3.25323   22.20   <2e-16 ***
## banios         53.70001    2.96638   18.10   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 132.4 on 5094 degrees of freedom
## Multiple R-squared:  0.7907, Adjusted R-squared:  0.7905 
## F-statistic:  3848 on 5 and 5094 DF,  p-value: < 2.2e-16
# Calcular el VIF
vif_resultado <- vif(modelo)
print(vif_resultado)
##    areaconst      estrato habitaciones parqueaderos       banios 
##     2.550425     1.745884     1.414488     1.489670     2.923405

Interpretación:

  • Mediana de los residuos (-1.81): El valor cercano a 0 sugiere que el modelo no presenta un sesgo significativo en la predicción del precio de las viviendas.
  • Significancia de los coeficientes: Todos los coeficientes tienen una significancia estadística muy alta (p-valor < 0.001), lo que indica que todas las variables predictoras contribuyen significativamente al modelo.
  • Área construida (areaconst): Por cada metro cuadrado adicional de área construida, se espera un aumento promedio de 2.06 unidades en el precio de la vivienda, manteniendo constantes las demás variables.
  • Estrato: Un aumento de una unidad en el estrato se asocia con un incremento promedio de 66.99 unidades en el precio, lo que sugiere que las viviendas en estratos más altos tienen precios considerablemente más elevados.
  • Habitaciones: Cada habitación adicional disminuye el precio en 33.70 unidades, lo que podría indicar que en este caso, un mayor número de habitaciones no siempre aumenta el valor de la vivienda.
  • Parqueaderos: Por cada parqueadero adicional, el precio de la vivienda aumenta en 72.23 unidades, mostrando un impacto positivo significativo.
  • Baños: Un baño adicional incrementa el precio de la vivienda en 53.70 unidades, indicando que esta variable es también relevante para aumentar el valor.
  • Error estándar residual: El error estándar residual es 132.4, lo que indica que las predicciones del modelo tienden a desviarse en promedio por esa cantidad del valor real del precio de la vivienda.
  • R-cuadrado (0.7907): El 79.07% de la variabilidad en el precio de la vivienda puede explicarse mediante las variables incluidas en el modelo, lo que indica un buen ajuste.
  • F-statistic (3848): Un valor F tan alto, acompañado de un p-valor extremadamente bajo (< 2.2e-16), indica que el modelo es altamente significativo en su conjunto.
  • Propuestas de ajuste del modelo:

    El modelo tiene un buen ajuste general, pero aún hay espacio para mejorar, especialmente si el𝑅2 R2 no captura toda la variabilidad o si hay residuos grandes.

    Mejoras posibles:

    • Revisar multicolinealidad: Se Verifica si existe multicolinealidad entre las variables ya que la presencia de multicolinealidad puede afectar la interpretación de los coeficientes. En este caso todos los valores de VIF son inferiores a 5, lo que significa que no hay un problema significativo de multicolinealidad entre las variables independientes en el modelo .
    • Agregar variables adicionales: Se procede a Incluir otras variables como piso y zona que podrían influir en el precio.
    # Estimación del modelo de regresión lineal múltiple agregando variables de piso y zona
    modeloI <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios + piso + zona, data = vivienda_apartamentos)
    
    # Resumen del modelo
    summary(modeloI)
    ## 
    ## Call:
    ## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
    ##     banios + piso + zona, data = vivienda_apartamentos)
    ## 
    ## Residuals:
    ##      Min       1Q   Median       3Q      Max 
    ## -1643.42   -55.95    -0.92    49.44   959.90 
    ## 
    ## Coefficients:
    ##                    Estimate Std. Error t value Pr(>|t|)    
    ## (Intercept)      -350.89432   29.00021 -12.100  < 2e-16 ***
    ## areaconst           1.94196    0.04247  45.730  < 2e-16 ***
    ## estrato            57.02914    2.57627  22.136  < 2e-16 ***
    ## habitaciones      -27.55957    3.20040  -8.611  < 2e-16 ***
    ## parqueaderos       66.30469    3.20225  20.706  < 2e-16 ***
    ## banios             52.26505    2.90253  18.007  < 2e-16 ***
    ## piso                4.00313    0.75284   5.317 1.10e-07 ***
    ## zonaZona Norte     35.64777   26.64681   1.338    0.181    
    ## zonaZona Oeste    114.53275   26.98405   4.244 2.23e-05 ***
    ## zonaZona Oriente    9.49238   31.04835   0.306    0.760    
    ## zonaZona Sur       29.81727   26.55910   1.123    0.262    
    ## ---
    ## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    ## 
    ## Residual standard error: 128.9 on 5089 degrees of freedom
    ## Multiple R-squared:  0.8016, Adjusted R-squared:  0.8013 
    ## F-statistic:  2057 on 10 and 5089 DF,  p-value: < 2.2e-16

    Se observa que el modelo es estadísticamente sólido, con un buen ajuste y significancia. Las variables de zona y piso aportan algo al modelo, pero no de forma importante

    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

    plot(modeloI$fitted.values, residuals(modeloI))
    abline(h = 0, col = "red")

    En la grafica se observa que los residuos se concentran con la línea horizontal y se van dispersando conforme aumenta los predictores, esto indica que el modelo tiene mayor dificultad para predecir con precisión en el rango más alto de los valores predichos

    Normalidad

    para verificar la normalidad se descarta Shapiro-Wilk ya que esta diseñada para funcionar con muestras cuyo tamaño esté entre 3 y 5000 observaciones, se usa la prueba de Anderson-Darling (AD Test) esta prueba es más flexible con el tamaño de muestra

    library(nortest)
    ad.test(residuals(modeloI))
    ## 
    ##  Anderson-Darling normality test
    ## 
    ## data:  residuals(modeloI)
    ## A = 164.42, p-value < 2.2e-16

    Se observa que el p-valor es menor a 0.05, esto indica que los residuos no siguen una distribución normal. lo que sugiere que el supuesto de normalidad de los errores no se cumple en este modelo de regresión.

    Para corregir y cumplir este supuesto seria necesario la transformación de algunas variables o aplicar otro tipo de modelo

    Homocedasticidad

    Objetivo: Verificar si la varianza de los errores es constante a lo largo de todas las observaciones (homocedasticidad).

    Prueba de Goldfeld-Quandt: Interpretación: Un p-valor bajo indica heterocedasticidad (varianza no constante), lo que podría afectar la eficiencia de las estimaciones de los coeficientes.

    library(lmtest)
    gqtest(modeloI)
    ## 
    ##  Goldfeld-Quandt test
    ## 
    ## data:  modeloI
    ## GQ = 1.6051, df1 = 2539, df2 = 2539, p-value < 2.2e-16
    ## alternative hypothesis: variance increases from segment 1 to 2
    plot(fitted(modeloI), residuals(modeloI))
    abline(h = 0, col = "red")

    Interpretación:

    • GQ = 1.6051: Este es el valor del estadístico de Goldfeld-Quandt. Un valor mayor a 1 significa heterocedasticidad (aumento de la varianza entre los segmentos).
    • p-value < 2.2e-16: El p-valor extremadamente bajo indica que hay evidencia fuerte para rechazar la hipótesis nula de homocedasticidad (varianza constante). Esto sugiere que hay heterocedasticidad, y específicamente que la varianza de los errores aumenta entre el primer y segundo segmento de los datos.
    • Hipótesis alternativa: variance increases from segment 1 to 2: La prueba confirma la hipótesis alternativa de que la varianza de los residuos aumenta entre los dos segmentos de los datos.

    Este resultado puede afectar la validez de las inferencias estadísticas del modelo, ya que uno de los supuestos clave de la regresión lineal (homocedasticidad) no se cumple

    como se menciona en la interpretación anterior para corregir y cumplir este supuesto seria necesario la transformación de algunas variables o aplicar otro tipo de modelo

    Independencia de los Errores

    Objetivo: Verificar si los errores son independientes entre sí (no autocorrelacionados).

    dwtest(modeloI)
    ## 
    ##  Durbin-Watson test
    ## 
    ## data:  modeloI
    ## DW = 1.7088, p-value < 2.2e-16
    ## alternative hypothesis: true autocorrelation is greater than 0

    Interpretación:

    • p-value < 2.2e-16: Un p-valor extremadamente bajo sugiere que hay evidencia suficiente para rechazar la hipótesis nula de que no existe autocorrelación. Esto implica que existe autocorrelación positiva en los residuos del modelo.
    • Hipótesis alternativa: true autocorrelation is greater than 0: El resultado indica que hay autocorrelación positiva significativa.

    El test de Durbin-Watson sugiere que hay autocorrelación positiva en los residuos del modelo. La presencia de autocorrelación puede afectar la validez de las inferencias del modelo, ya que uno de los supuestos clave de la regresión lineal, que es la independencia de los errores,no se cumple

    como se menciona en la interpretación anterior para corregir y cumplir este supuesto seria necesario la transformación de algunas variables o aplicar otro tipo de modelo

    # Calcular el VIF
    vif_resultado <- vif(modeloI)
    print(vif_resultado)
    ##                  GVIF Df GVIF^(1/(2*Df))
    ## areaconst    2.660926  1        1.631235
    ## estrato      1.944983  1        1.394626
    ## habitaciones 1.435459  1        1.198107
    ## parqueaderos 1.521779  1        1.233604
    ## banios       2.950996  1        1.717846
    ## piso         1.027727  1        1.013769
    ## zona         1.489283  4        1.051047

    Los valores ajustados de GVIF están todos por debajo de 2, lo que indica que no hay una colinealidad significativa entre las variables en el modelo.

    1. Realice una partición en los datos de forma aleatoria donde 70% sea un set para entrenar el modelo y 30% para prueba. Estime el modelo con la muestra del 70%. Muestre los resultados.

    # Configuración de semilla para reproducibilidad
    set.seed(123)
    
    
    split <- sample.split(vivienda_apartamentos$preciom, SplitRatio = 0.7)
    
    # Crear conjuntos de entrenamiento y prueba
    train_set <- subset(vivienda_apartamentos, split == TRUE)
    test_set <- subset(vivienda_apartamentos, split == FALSE)
    
    
    modelo_train <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios + piso + zona, data = train_set)
    
    
    summary(modelo_train)
    ## 
    ## Call:
    ## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
    ##     banios + piso + zona, data = train_set)
    ## 
    ## Residuals:
    ##      Min       1Q   Median       3Q      Max 
    ## -1185.84   -55.14    -1.12    49.66   889.03 
    ## 
    ## Coefficients:
    ##                    Estimate Std. Error t value Pr(>|t|)    
    ## (Intercept)      -334.71092   33.52068  -9.985  < 2e-16 ***
    ## areaconst           2.09989    0.05098  41.194  < 2e-16 ***
    ## estrato            57.11660    3.01773  18.927  < 2e-16 ***
    ## habitaciones      -30.90900    3.79146  -8.152 4.88e-16 ***
    ## parqueaderos       64.61842    3.82065  16.913  < 2e-16 ***
    ## banios             46.55074    3.41307  13.639  < 2e-16 ***
    ## piso                3.96782    0.87764   4.521 6.35e-06 ***
    ## zonaZona Norte     29.78142   30.58780   0.974 0.330302    
    ## zonaZona Oeste    106.14552   31.00785   3.423 0.000626 ***
    ## zonaZona Oriente   -7.12949   35.58396  -0.200 0.841213    
    ## zonaZona Sur       26.73005   30.47819   0.877 0.380533    
    ## ---
    ## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    ## 
    ## Residual standard error: 128.1 on 3606 degrees of freedom
    ## Multiple R-squared:  0.8077, Adjusted R-squared:  0.8072 
    ## F-statistic:  1514 on 10 and 3606 DF,  p-value: < 2.2e-16

    1. Realice predicciones con el modelo anterior usando los datos de prueba (30%).

    # Realizar predicciones sobre el conjunto de prueba
    predicciones <- predict(modelo_train, newdata = test_set)
    
    # Mostrar las primeras predicciones
    head(predicciones)
    ##        1        2        3        4        5        6 
    ## 115.2760 171.4056 392.2669 212.5839 349.9159 375.9907
    # Comparar predicciones con valores reales
    resultados <- data.frame(Real = test_set$preciom, Prediccion = predicciones)
    
    # Mostrar los primeros registros de la comparación
    head(resultados)
    ##   Real Prediccion
    ## 1  175   115.2760
    ## 2  170   171.4056
    ## 3  430   392.2669
    ## 4  130   212.5839
    ## 5  325   349.9159
    ## 6  370   375.9907

    1. Calcule el error cuadrático medio, el error absoluto medio y el R2, interprete

    # Calcular el Mean Squared Error (MSE)
    mse <- mean((resultados$Real - resultados$Prediccion)^2)
    mse
    ## [1] 17321.15
    # Calcular el Mean Absolute Error (MAE)
    mae <- mean(abs(resultados$Real - resultados$Prediccion))
    mae
    ## [1] 79.55846
    # Calcular el R-cuadrado
    sse <- sum((resultados$Prediccion - mean(resultados$Real))^2)
    sst <- sum((resultados$Real - mean(resultados$Real))^2)
    r_squared <- sse / sst
    r_squared
    ## [1] 0.848491
    # Mostrar las primeras filas de las predicciones junto a los valores reales
    print(head(resultados))
    ##   Real Prediccion
    ## 1  175   115.2760
    ## 2  170   171.4056
    ## 3  430   392.2669
    ## 4  130   212.5839
    ## 5  325   349.9159
    ## 6  370   375.9907
    # Imprimir las métricas de desempeño
    cat("MSE: ", mse, "\n")
    ## MSE:  17321.15
    cat("MAE: ", mae, "\n")
    ## MAE:  79.55846
    cat("R-cuadrado: ", r_squared, "\n")
    ## R-cuadrado:  0.848491

    Interpretación

    • El MAE de 79.55846, significa que, en promedio, las predicciones del modelo tienen un error de aproximadamente 79.55846 unidades respecto a los valores reales
    • El R² es de 0.848491, lo que significa que el modelo explica aproximadamente el 84.84 % de la variabilidad de los datos
      • MSE y MAE sugieren que el modelo tiene errores moderados, con un error promedio de alrededor de 79.55846 unidades (MAE)

        Predición para datos aportados en el ejercicio:

        • Tipo: Apartamento
        • área construida: 300
        • parqueaderos: 3
        • baños: 3
        • habitaciones: 5
        • estrato: estrato 5 o 6
        • zona: sur
        • crédito preaprobado: 850 millones
        # Crear un nuevo data frame con los valores específicos
        nuevo_apartamento <- data.frame(
          areaconst = 300,
          estrato = 6,  # Puedes usar estrato 5 o 6 dependiendo del caso
          habitaciones = 5,
          parqueaderos = 3,
          banios = 3,
          piso = 5,  # Ajustar según los valores posibles en tu dataset
          zona = "Zona Sur"  # Asegúrate de que "sur" sea una de las categorías válidas
        )
        
        # Realizar la predicción usando el modelo ajustado
        prediccion_precio <- predict(modeloI, nuevo_apartamento)
        prediccion_precio
        ##        1 
        ## 841.6143

        Conclusión:

        El resultado concluye que el precio del credito preaprobado es suficiente para adquirir la vivienda tipo apartamento con las caracteristicas solicitadas para el estrato mas alto (6)