La actividad 2, busca implementar métodos de regresión lineal múltiple a través del uso del software R para la explicación y predicción del precio de las casas ubicadas en la zona norte de la ciudad de Santiago de Cali, a partir de una serie de caracteristicas como el estrato, área construida, número de baños, habitaciones, parqueaderos, entre otros. Para ello, se propone hacer una limpieza y exploración de la base, ajustar un modelo de regresión lineal multiple con las variables más significativas (elegidas a través de métodos de selección de variables) y validación del modelo a través de una partición train-test, donde se podrá evaluar las métricas de desempeño del mismo.

Carga de librerías a utilizar

########################### Paquetes ###########################

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
# install.packages("plotly")
library(plotly)
## Loading required package: ggplot2
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
library(corrplot)
## corrplot 0.92 loaded
# install.packages("ggcorrplot")
library(ggcorrplot)

Carga de datos

########################### Carga de datos ############################

# install.packages("devtools") # solo la primera vez
# devtools::install_github("dgonxalex80/paqueteMODELOS", force =TRUE)
library(paqueteMODELOS)
## Loading required package: boot
## Loading required package: broom
## Loading required package: GGally
## Registered S3 method overwritten by 'GGally':
##   method from   
##   +.gg   ggplot2
## Loading required package: gridExtra
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
## Loading required package: knitr
## Loading required package: summarytools
data("vivienda")

La base de datos, contiene información de la zona de ubicación, piso, estrato socioeconómico, precio, area construída, número de parqueadero, número de baños, número de habitaciones, tipo, barrio, longitud y latitud de 8.322 viviendas de la ciudad de Cali. El objetivo, es realizar un modelo que permita predecir el precio de la vivienda dada algunas caracteristicas especiales, teniendo en cuenta que sólo se analizarán las viviendas de tipo casa de la zona norte de la ciudad. Para esto, se desarrollarán 6 puntos propuestos en la actividad.

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

table(vivienda$tipo) # Validamos si "Casa" solo está escrito una vez
## 
## Apartamento        Casa 
##        5100        3219
table(vivienda$zona) # Validamos las opciones de zona
## 
##  Zona Centro   Zona Norte   Zona Oeste Zona Oriente     Zona Sur 
##          124         1920         1198          351         4726
# Filtro de casas para la zona norte de la ciudad


base1  <- filter(vivienda, vivienda$zona == "Zona Norte" & vivienda$tipo == "Casa")
head(base1, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1209 Zona N… 02          5     320       150            2      4            6
## 2  1592 Zona N… 02          5     780       380            2      3            3
## 3  4057 Zona N… 02          6     750       445           NA      7            6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
## Comprobamos con las tablas que solo tengamos zona = norte y tipo = casa

table(base1$tipo) 
## 
## Casa 
##  722
table(base1$zona) 
## 
## Zona Norte 
##        722

Para realizar el filtro mencionado, primero se validan las opciones de respuesta que trae las variables zona y tipo. Una vez se realiza la verificación, se procede a filtrar las casas de la zona norte, reduciendo el DataSet a 722 observaciones y 13 columnas.

Finalmente, se comprueba que esta nueva base solo contenga las caracteristicas deseadas en cuanto a tipo y zona, obteniendo como resultado que el filtro fue aplicado exitosamente.

Punto 2

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.

## Análisis de datos faltantes:
colSums(is.na(base1)) # Número de datos faltantes por variable
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0          372            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##          287            0            0            0            0            0 
##      latitud 
##            0

La variable piso y parqueaderos tienen un gran número de datos faltantes, por lo que se propone eliminar “piso” del dataset (para efectos prácticos) pero en el caso de parqueaderos, notamos que el valor minimo que toma es 1, por lo tanto se puede asumir que los datos faltantes en esta variable corresponden a las viviendas que no tienen parqueaderos y por tanto se puede imputar por cero.

Por otro lado, eliminamos la variable ID ya que es una llave que no es necesaria para el modelamiento y las variables zona y tipo, ya que son solo casas de la zona norte. Adicionalmente se eliminan el barrio, longitud y latitud ya que tampoco son relevantes en el estudio

base1 <- base1[,c(-1, -2, -3, -10, -11, -12, -13)]
head(base1, 3)
## # A tibble: 3 × 6
##   estrato preciom areaconst parqueaderos banios habitaciones
##     <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1       5     320       150            2      4            6
## 2       5     780       380            2      3            3
## 3       6     750       445           NA      7            6
base1$parqueaderos[is.na(base1$parqueaderos)] <-0 #se imputa por cero
colSums(is.na(base1))
##      estrato      preciom    areaconst parqueaderos       banios habitaciones 
##            0            0            0            0            0            0
str(base1) # Evaluamos el tipo de dato de cada variable
## spc_tbl_ [722 × 6] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ estrato     : num [1:722] 5 5 6 4 5 4 5 5 3 3 ...
##  $ preciom     : num [1:722] 320 780 750 625 750 600 420 490 230 190 ...
##  $ areaconst   : num [1:722] 150 380 445 355 237 160 200 118 160 435 ...
##  $ parqueaderos: num [1:722] 2 2 0 3 2 1 4 2 0 0 ...
##  $ banios      : num [1:722] 4 3 7 5 6 4 4 4 2 0 ...
##  $ habitaciones: num [1:722] 6 3 6 5 6 5 5 4 3 0 ...
##  - 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>
base1$estrato <- as.character(base1$estrato) # Corregimos la variable estrato como categorica
summary(base1) # Descriptivas de las variables numéricas
##    estrato             preciom         areaconst       parqueaderos   
##  Length:722         Min.   :  89.0   Min.   :  30.0   Min.   : 0.000  
##  Class :character   1st Qu.: 261.2   1st Qu.: 140.0   1st Qu.: 0.000  
##  Mode  :character   Median : 390.0   Median : 240.0   Median : 1.000  
##                     Mean   : 445.9   Mean   : 264.9   Mean   : 1.314  
##                     3rd Qu.: 550.0   3rd Qu.: 336.8   3rd Qu.: 2.000  
##                     Max.   :1940.0   Max.   :1440.0   Max.   :10.000  
##      banios        habitaciones   
##  Min.   : 0.000   Min.   : 0.000  
##  1st Qu.: 2.000   1st Qu.: 3.000  
##  Median : 3.000   Median : 4.000  
##  Mean   : 3.555   Mean   : 4.507  
##  3rd Qu.: 4.000   3rd Qu.: 5.000  
##  Max.   :10.000   Max.   :10.000

Las casas de la zona norte de la ciudad, en promedio valen 261 millones de pesos, tienen un área construída promedio de 265 metros cuadrados, el \(75\%\) pueden tener hasta 2 parqueaderos, 4 baños y 5 habitaciones.

### Relación entre variables de interés vs el precio de la vivienda:
library(plotly)
plot_ly(base1,x=~preciom,y=~areaconst,type="scatter")
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
plot_ly(ggplot2::diamonds, x=~base1$preciom,y=~base1$estrato, type = "box")
plot_ly(base1,x=~preciom,y=~parqueaderos,type="scatter")
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
plot_ly(base1,x=~preciom,y=~banios,type="scatter")
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
plot_ly(base1,x=~preciom,y=~habitaciones,type="scatter")
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

Es evidente que existe una relación casi lineal entre el precio de la vivienda y el area construida, lo que índica que a medida que aumenta el tamaño (en metros cuadrados) de la vivienda, mayor será su precio, lo cual es lógico bajo la mirada de negocio. No obstante encontramos algunas casas cuyo valor es alto, sin embargo tiene pocos metros cuadrados.

El estrato es otro factor que parece ser influyente en el precio de las casas en la zona norte, ya que las casas de estratos medios (3 y 4) tienen menor precio que las casas ubicadas en estratos 5 y 6, lo cual mantiene completamente la lógica de negocio.

Por otro lado, el número de parqueaderos, habitaciones y baños no tienen un comportamiento claro frente al precio, ya que hay muchas casas que tienen pocas habitaciones, baños y no tienen parqueaderos, sin embargo tienen precios mayores a algunas casas que tienen mas de 2 habitaciones, 2 baños y 1 parqueadero; y viceversa.

Dado lo anterior, tambien se realiza un análisis de correlación de pearson, para determinar númericamente la relación existente entre el precio de la vivienda y las características de interés:

num <- base1[,c(-1)]
str(num)
## spc_tbl_ [722 × 5] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ preciom     : num [1:722] 320 780 750 625 750 600 420 490 230 190 ...
##  $ areaconst   : num [1:722] 150 380 445 355 237 160 200 118 160 435 ...
##  $ parqueaderos: num [1:722] 2 2 0 3 2 1 4 2 0 0 ...
##  $ banios      : num [1:722] 4 3 7 5 6 4 4 4 2 0 ...
##  $ habitaciones: num [1:722] 6 3 6 5 6 5 5 4 3 0 ...
##  - 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>
r<-cor(num, method="spearman")

p<-ggcorrplot(r,type="full", method = "square",
              title="Correlaciones entre variables",
              colors = c("red","gray","blue"),
              outline.color="black", ggtheme = theme_test() + theme(text = element_text(size = 7)))


plotly::ggplotly(p)

Con el gráfico, se confirma que el área tiene una incidencia importante en el precio de la casa, y el número de baños tiene un coeficiente de relación de 0.62 con el precio, por lo que se puede concluir que tambien puede influir en la predicción del precio.

Punto 3

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

Se busca estimar un modelo que permita predecir el precio de las viviendas de tipo casa en la zona norte de la ciudad, sin embargo, buscamos mantener el principio de parsimonia en el modelo, por lo que se propone hacer una selección de variables para solo estimar el modelo con las variables que tengan influencia en el precio, y descartar aquellas que no aporten en la predicción del precio de la vivienda. Para ello, se propone una selección paso a paso a través del proceso forward stepwise regression. Cabe resaltar que se trabajará con las variables x estandarizadas:

### Estandarización de la matríz x

x_num <- base1[,c(-1, -2)] #sacamos precio y estrato
x_cat <- base1[,c(1)] #dejamos la variable categorica
y <- base1[,c(2)] # dejamos la variable y

## Estandarizamos las x
## Estandarizamos los datos de tal modo que quedan con media cero y sd 1

x_numS <- x_num %>% mutate_all(~(scale(.) %>% as.vector))
summarytools::descr(x_numS)
## Descriptive Statistics  
## x_numS  
## N: 722  
## 
##                                 areaconst                 banios          habitaciones
## ----------------- ----------------------- ---------------------- ---------------------
##              Mean                    0.00                   0.00                  0.00
##           Std.Dev                    1.00                   1.00                  1.00
##               Min                   -1.40                  -2.33                 -2.47
##                Q1                   -0.75                  -1.02                 -0.82
##            Median                   -0.15                  -0.36                 -0.28
##                Q3                    0.43                   0.29                  0.27
##               Max                    7.03                   4.23                  3.01
##               MAD                    0.88                   0.97                  0.81
##               IQR                    1.18                   1.31                  1.09
##                CV   -18267409724502792.00   15632687168084156.00   9343675088969812.00
##          Skewness                    1.85                   0.67                  0.64
##       SE.Skewness                    0.09                   0.09                  0.09
##          Kurtosis                    6.24                   1.00                  1.18
##           N.Valid                  722.00                 722.00                722.00
##         Pct.Valid                  100.00                 100.00                100.00
## 
## Table: Table continues below
## 
##  
## 
##                             parqueaderos
## ----------------- ----------------------
##              Mean                   0.00
##           Std.Dev                   1.00
##               Min                  -0.86
##                Q1                  -0.86
##            Median                  -0.21
##                Q3                   0.45
##               Max                   5.69
##               MAD                   0.97
##               IQR                   1.31
##                CV   -2139209823000979.25
##          Skewness                   1.60
##       SE.Skewness                   0.09
##          Kurtosis                   3.55
##           N.Valid                 722.00
##         Pct.Valid                 100.00
new_df <- data.frame(y,x_cat, x_numS)
head(new_df)
##   preciom estrato  areaconst parqueaderos     banios habitaciones
## 1     320       5 -0.6870409    0.4491887  0.2917567    0.8169190
## 2     780       5  0.6888301    0.4491887 -0.3644687   -0.8244971
## 3     750       6  1.0776632   -0.8611718  2.2604331    0.8169190
## 4     625       4  0.5392789    1.1043689  0.9479822    0.2697803
## 5     750       5 -0.1666028    0.4491887  1.6042077    0.8169190
## 6     600       4 -0.6272205   -0.2059916  0.2917567    0.2697803
str(new_df)
## 'data.frame':    722 obs. of  6 variables:
##  $ preciom     : num  320 780 750 625 750 600 420 490 230 190 ...
##  $ estrato     : chr  "5" "5" "6" "4" ...
##  $ areaconst   : num  -0.687 0.689 1.078 0.539 -0.167 ...
##  $ parqueaderos: num  0.449 0.449 -0.861 1.104 0.449 ...
##  $ banios      : num  0.292 -0.364 2.26 0.948 1.604 ...
##  $ habitaciones: num  0.817 -0.824 0.817 0.27 0.817 ...
### Selección de variables

modelo_b0<- lm(preciom ~ 1, data=new_df) # se define el modelo  ingenuo  y= b0

#define model with all predictors
modelo_all <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = new_df)

# Se aplica el proceso forward stepwise regression
forward <- step(modelo_b0, direction='forward', scope=formula(modelo_all), trace=0)

# Visualización de los resultados 
forward$anova
##          Step Df   Deviance Resid. Df Resid. Dev      AIC
## 1             NA         NA       721   51926104 8076.348
## 2 + areaconst -1 27773709.6       720   24152394 7525.701
## 3   + estrato -3  5661773.6       717   18490620 7338.841
## 4    + banios -1   889689.5       716   17600931 7305.238
summary(forward) # se descartan parqueaderos y habita (hablar de correlacion)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios, data = new_df)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -968.77  -73.13  -16.35   45.27 1069.02 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  350.371     11.251  31.142  < 2e-16 ***
## areaconst    138.887      6.983  19.889  < 2e-16 ***
## estrato4      84.289     16.898   4.988 7.66e-07 ***
## estrato5     137.921     15.733   8.766  < 2e-16 ***
## estrato6     327.801     25.826  12.693  < 2e-16 ***
## banios        41.301      6.865   6.016 2.85e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 156.8 on 716 degrees of freedom
## Multiple R-squared:  0.661,  Adjusted R-squared:  0.6587 
## F-statistic: 279.3 on 5 and 716 DF,  p-value: < 2.2e-16

Con el resultado obtenido en el proceso forward stepwise regression, se ajusta finalmente el modelo:

# Definimos el modelo con las variables importantes
model <- lm(preciom ~ areaconst + estrato + banios, data = new_df)
summary(model)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios, data = new_df)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -968.77  -73.13  -16.35   45.27 1069.02 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  350.371     11.251  31.142  < 2e-16 ***
## areaconst    138.887      6.983  19.889  < 2e-16 ***
## estrato4      84.289     16.898   4.988 7.66e-07 ***
## estrato5     137.921     15.733   8.766  < 2e-16 ***
## estrato6     327.801     25.826  12.693  < 2e-16 ***
## banios        41.301      6.865   6.016 2.85e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 156.8 on 716 degrees of freedom
## Multiple R-squared:  0.661,  Adjusted R-squared:  0.6587 
## F-statistic: 279.3 on 5 and 716 DF,  p-value: < 2.2e-16

El modelo ajustado es capaz de explicar el \(66\%\) de la varianza del precio de las casas de la zona norte de la ciudad usando las variables are, estrato y número de baños. Además, todas las variables son significativas dentro del modelo, es decir, que todas tienen un impacto en el precio de la casa.

Punto 4

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

Los supuestos a validar son:

  1. Los errores son variables aleatorias normales. \(e∼normal\)
  2. Los errores tienen media cero. \(E[e]=0\)
  3. Los errores tienen varianza constante. \(V[e]=σ2\)
  4. Los errores son mutuamente independientes. \(E[ei,ej]=0\)
#Los errores son variables aleatorias normales. e∼normal
par(mfrow=c(2,2))
plot(model)

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

Se determina que los errores no se distribuyen normal, por lo que se recomienda hacer un análisis de puntos atípicos y descartar aquellos que generen ruído y volver a ajustar el modelo, evaluando nuevamente este supuesto.

#Los errores tienen media cero. E[e]=0
round(mean(model$residuals), 3)
## [1] 0

la esperanza de los errores del modelo si tienen media cero, por lo tanto, si se cumple este supuesto.

#Los errores tienen varianza constante. V[e]=σ2

library(lmtest)
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
bptest(model)
## 
##  studentized Breusch-Pagan test
## 
## data:  model
## BP = 132.54, df = 5, p-value < 2.2e-16
plot(model$fitted.values, model$residuals, ylab="Residuales", xlab="Estimados", abline(h=0, col="red"))

No se cumple el supuesto de que los errores tienen varianza constante.

#Los errores son mutuamente independientes. E[ei,ej]=0

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

Los errores no cumplen con el supuesto de independencia, es decir, existe una autocorrelación entre ellos. Se recomienda hacer alguna transformación que permita corregir y cumplir este supuesto.

Punto 5

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.

# Partición
# install.packages("caret")
library(caret)
## Loading required package: lattice
## 
## Attaching package: 'lattice'
## The following object is masked from 'package:boot':
## 
##     melanoma
set.seed(1995)
training <- createDataPartition(new_df$preciom, p = 0.7, list = FALSE)
df_train <- new_df[ training,]
df_test  <- new_df[-training,]
head(df_train)
##    preciom estrato  areaconst parqueaderos     banios habitaciones
## 2      780       5  0.6888301    0.4491887 -0.3644687   -0.8244971
## 4      625       4  0.5392789    1.1043689  0.9479822    0.2697803
## 5      750       5 -0.1666028    0.4491887  1.6042077    0.8169190
## 7      420       5 -0.3879385    1.7595492  0.2917567    0.2697803
## 8      490       5 -0.8784665    0.4491887  0.2917567   -0.2773584
## 10     190       3  1.0178427   -0.8611718 -2.3331451   -2.4659132
head(df_test)
##    preciom estrato  areaconst parqueaderos     banios habitaciones
## 1      320       5 -0.6870409    0.4491887  0.2917567    0.8169190
## 3      750       6  1.0776632   -0.8611718  2.2604331    0.8169190
## 6      600       4 -0.6272205   -0.2059916  0.2917567    0.2697803
## 9      230       3 -0.6272205   -0.8611718 -1.0206942   -0.8244971
## 11     180       3 -0.8665024   -0.8611718 -0.3644687   -0.8244971
## 14     380       3  0.2102662   -0.8611718  0.9479822    1.9111964
nrow(df_train)
## [1] 507
nrow(df_test)
## [1] 215

Usando la librería “caret”, realiza la partición de la base en \(70\%\) para entrenamiento y \(30\%\) para test, con lo que se obtiene que el número de filas para el conjunto de entrenamiento es de 507 y para tes 215.

# Estimación del modelo con los datos de train
mod_train <- train(preciom ~ areaconst + estrato  + banios, data = df_train, method = "lm")

summary(mod_train)
## 
## Call:
## lm(formula = .outcome ~ ., data = dat)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -929.42  -76.85  -17.74   43.55 1077.58 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  345.145     13.899  24.832  < 2e-16 ***
## areaconst    134.205      8.672  15.476  < 2e-16 ***
## estrato4      91.748     20.659   4.441 1.10e-05 ***
## estrato5     140.295     19.560   7.172 2.66e-12 ***
## estrato6     316.667     31.901   9.927  < 2e-16 ***
## banios        37.176      8.558   4.344 1.70e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 163.7 on 501 degrees of freedom
## Multiple R-squared:  0.6243, Adjusted R-squared:  0.6205 
## F-statistic: 166.5 on 5 and 501 DF,  p-value: < 2.2e-16
mod_train$results
##   intercept     RMSE  Rsquared      MAE   RMSESD RsquaredSD    MAESD
## 1      TRUE 170.5478 0.6138089 103.8398 21.16156 0.06143865 8.606123

El modelo con los datos de entrenamiento, obtiene un \(R^2 = 0.61\) que es muy similar al obtenido con los datos completos, además, el error absoluto medio es de 104 millones y el RMSE de 170 millones.

Punto 6

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

pred <- predict(mod_train, df_test)
summary(pred)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   134.4   263.0   412.1   438.6   550.5  1198.6

El valor predicho de las viviendas de test oscila entre 134 y 1198 millones de pesos, obteniendo como promedio 439 millones.

Punto 7

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

# Calcula MAE
mae <- mean(abs(pred - df_test$preciom))
mae
## [1] 90.24893
# Calcula R^2
r_squared <- cor(pred, df_test$preciom)^2
r_squared
## [1] 0.748948
# Calcula el MSE
mse <- mean((pred - df_test$preciom)^2)
mse
## [1] 19753.39

En los datos de test, el error absoluto medio (MAE) es de 90 millones de pesos, lo cual es bastante alto considerando que un error de estimación en esa proporción conlleva a tomar medidas erroneas frente al valor real de la vivienda. Por otro lado, el error cuadratico medio es 19753, lo que permite deducir que el modelo no tiene unas buenas predicciones a pesar de tener un \(R^2\) de 0.75.

En conclusión, las métricas de test son mejores que las de entrenamiento, sin embargo, a pesar de que el \(R^2\) es aceptable en el modelo, la estimación para el precio de las casas de la zona norte no es tan acertado tomando como base solo el estrato, area construida y número de baños, por lo que se recomienda evaluar la inclusión de otras variables que permitan mejorar la predicción del modelo.