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.
########################### 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 ############################
# 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.
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.
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.
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.
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:
#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.
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.
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.
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.