Maria comenzó como agente de bienes raíces en Cali hace 10 años. Después de laborar dos años para una empresa nacional, se traslado a Bogotá y trabajó para otra agencia de bienes raíces. Sus amigos y familiares la convencieron de que con su experiencia y conocimientos del negocio debía abrir su propia agencia. Terminó por adquirir la licencia de intermediario y al poco tiempo fundó su propia compañía, C&A (Casas y Apartamentos) en Cali. Santiago y Lina, dos vendedores de la empresa anterior aceptaron trabajar en la nueva compaña. En la actualidad ocho agentes de bienes raíces colaboran con ella en C&A.
Actualmente las ventas de bienes raíces en Cali se han visto disminuidas de manera significativa en lo corrido del año. Durante este periodo muchas instituciones bancarias de ahorro y vivienda están prestando grandes sumas de dinero para la industria y la construcción comercial y residencial. Cuando el efecto producto de las tensiones políticas y sociales disminuya, se espera que la actividad económica de este sector se reactive.
Los datos de los tres últimos meses se adjuntan en la base que puede obtener con el siguiente código en R variable descripción
| Variable | Descripcion |
|---|---|
| zona | ubicación de la vivienda : Zona Centro, Zona Norte,… |
| piso | piso que ocupa la vivienda : primer piso, segundo piso… |
| estrato | estrato socio-económico : 3,4,5,6 |
| preciom | precio de la vivienda en millones de pesos |
| areaconst | área construida |
| parqueaderos | número de parqueaderos |
| banios | número de baños |
| habitaciones | número de habitaciones |
| tipo | tipo de vivienda : Casa, Apartamento |
| barrio | barrio de ubicación de la vivienda : 20 de Julio, alamos,.. |
| longitud | coordenada geográfica |
| latitud | coordenada geográfica |
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.
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.
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).
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).
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.
Realice predicciones con el modelo anterior usando los datos de prueba (30%).
Calcule el error cuadrático medio, el error absoluto medio y el R2, interprete.
Instalacion de librerias y carga de datos
library(tidyverse) #Paquete usado para el tratamiento de datos
library(stringi) #Paquete para tratamiento de acentuacion de caracteres
library(dplyr) #Paquete para sintaxis de codigo
library(magrittr) #Paquete para sintaxis de codigo
library(Amelia) #Paquete usado para el tratamiento de datos faltantes
library(plotly)
library(caret)
library(fastDummies)
library(car)
library(GGally)
library(summarytools)
library(Metrics)
library(paqueteMODELOS)
library(dplyr)
library(skimr)
library(lmtest)
library(ggplot2)
library(reshape2)
library(mice)
library(factoextra)
library(dendextend)
library(FactoMineR)
library(psych)
data(vivienda)
# Se verifican los valores en las columnas requeridas
unique(vivienda$zona)
## [1] "Zona Oriente" "Zona Sur" "Zona Norte" "Zona Oeste" "Zona Centro"
## [6] NA
unique(vivienda$tipo)
## [1] "Casa" "Apartamento" NA
# Se crea la base de datos filtrada a casa de la zona norte
db <- filter(vivienda, zona == "Zona Norte" & tipo == "Casa")
# Se verifican los resultados del filtro
head(db,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>
# Tabla con el conteo de propiedades por zona, tipo y numero de pisos
tabla <- db %>%
group_by(zona, tipo, piso) %>%
summarise(count = n()) %>%
ungroup()
## `summarise()` has grouped output by 'zona', 'tipo'. You can override using the
## `.groups` argument.
print(tabla)
## # A tibble: 6 × 4
## zona tipo piso count
## <chr> <chr> <chr> <int>
## 1 Zona Norte Casa 01 84
## 2 Zona Norte Casa 02 194
## 3 Zona Norte Casa 03 65
## 4 Zona Norte Casa 04 6
## 5 Zona Norte Casa 07 1
## 6 Zona Norte Casa <NA> 372
skim(db)
| Name | db |
| Number of rows | 722 |
| Number of columns | 13 |
| _______________________ | |
| Column type frequency: | |
| character | 4 |
| numeric | 9 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| zona | 0 | 1.00 | 10 | 10 | 0 | 1 | 0 |
| piso | 372 | 0.48 | 2 | 2 | 0 | 5 | 0 |
| tipo | 0 | 1.00 | 4 | 4 | 0 | 1 | 0 |
| barrio | 0 | 1.00 | 4 | 25 | 0 | 103 | 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| id | 0 | 1.0 | 2574.65 | 1986.26 | 58.00 | 766.25 | 2257.00 | 4225.00 | 8319.00 | ▇▃▃▂▁ |
| estrato | 0 | 1.0 | 4.20 | 0.98 | 3.00 | 3.00 | 4.00 | 5.00 | 6.00 | ▇▅▁▇▂ |
| preciom | 0 | 1.0 | 445.91 | 268.36 | 89.00 | 261.25 | 390.00 | 550.00 | 1940.00 | ▇▃▁▁▁ |
| areaconst | 0 | 1.0 | 264.85 | 167.17 | 30.00 | 140.00 | 240.00 | 336.75 | 1440.00 | ▇▃▁▁▁ |
| parqueaderos | 287 | 0.6 | 2.18 | 1.40 | 1.00 | 1.00 | 2.00 | 3.00 | 10.00 | ▇▂▁▁▁ |
| banios | 0 | 1.0 | 3.56 | 1.52 | 0.00 | 2.00 | 3.00 | 4.00 | 10.00 | ▅▇▃▁▁ |
| habitaciones | 0 | 1.0 | 4.51 | 1.83 | 0.00 | 3.00 | 4.00 | 5.00 | 10.00 | ▁▇▅▂▁ |
| longitud | 0 | 1.0 | -76.52 | 0.02 | -76.59 | -76.53 | -76.52 | -76.50 | -76.47 | ▁▁▇▆▂ |
| latitud | 0 | 1.0 | 3.46 | 0.03 | 3.33 | 3.45 | 3.47 | 3.48 | 3.50 | ▁▁▁▂▇ |
Como podemos observar, solo hay dos variables con valores faltantes (piso y parqueadero) por contexto se infiere que campos vacios en estos significa que la casa es de un solo piso y que no tiene parqueaderos, por lo que se reemplazaran con 1 y 0 respectivamente.
Adicionalmente es necesario corregir el tipo de variables para piso (de caracter a numerica) y el estrato a categorica ordinal. Para la variable estrato, se le aplicara encoding para crear columnas individuales para cada valor
# Reemplazo NA para piso y parqueadero
db$piso <- replace(db$piso, is.na(db$piso), 1)
db$parqueaderos <-
replace(db$parqueaderos, is.na(db$parqueaderos), 0)
# Correccion de tipo de variable
db$piso <- as.numeric(db$piso)
# copia de db antes de declarar estrato como categorica
df <- db
# Convertir variable estrato a categorica ordinal
db$estrato <- factor(db$estrato, levels = seq(min(db$estrato), max(db$estrato)))
skim(db)
| Name | db |
| Number of rows | 722 |
| Number of columns | 13 |
| _______________________ | |
| Column type frequency: | |
| character | 3 |
| factor | 1 |
| numeric | 9 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| zona | 0 | 1 | 10 | 10 | 0 | 1 | 0 |
| tipo | 0 | 1 | 4 | 4 | 0 | 1 | 0 |
| barrio | 0 | 1 | 4 | 25 | 0 | 103 | 0 |
Variable type: factor
| skim_variable | n_missing | complete_rate | ordered | n_unique | top_counts |
|---|---|---|---|---|---|
| estrato | 0 | 1 | FALSE | 4 | 5: 271, 3: 235, 4: 161, 6: 55 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| id | 0 | 1 | 2574.65 | 1986.26 | 58.00 | 766.25 | 2257.00 | 4225.00 | 8319.00 | ▇▃▃▂▁ |
| piso | 0 | 1 | 1.48 | 0.72 | 1.00 | 1.00 | 1.00 | 2.00 | 7.00 | ▇▁▁▁▁ |
| preciom | 0 | 1 | 445.91 | 268.36 | 89.00 | 261.25 | 390.00 | 550.00 | 1940.00 | ▇▃▁▁▁ |
| areaconst | 0 | 1 | 264.85 | 167.17 | 30.00 | 140.00 | 240.00 | 336.75 | 1440.00 | ▇▃▁▁▁ |
| parqueaderos | 0 | 1 | 1.31 | 1.53 | 0.00 | 0.00 | 1.00 | 2.00 | 10.00 | ▇▁▁▁▁ |
| banios | 0 | 1 | 3.56 | 1.52 | 0.00 | 2.00 | 3.00 | 4.00 | 10.00 | ▅▇▃▁▁ |
| habitaciones | 0 | 1 | 4.51 | 1.83 | 0.00 | 3.00 | 4.00 | 5.00 | 10.00 | ▁▇▅▂▁ |
| longitud | 0 | 1 | -76.52 | 0.02 | -76.59 | -76.53 | -76.52 | -76.50 | -76.47 | ▁▁▇▆▂ |
| latitud | 0 | 1 | 3.46 | 0.03 | 3.33 | 3.45 | 3.47 | 3.48 | 3.50 | ▁▁▁▂▇ |
Se consultan valores unicos de variables categoricas para identificar correcciones necesarias
columnas_categoricas = db %>% select_if(is.character)
valores_unicos = sapply(columnas_categoricas, unique)
print(valores_unicos)
## $zona
## [1] "Zona Norte"
##
## $tipo
## [1] "Casa"
##
## $barrio
## [1] "acopi" "alameda del río"
## [3] "alamos" "atanasio girardot"
## [5] "barranquilla" "barrio tranquilo y"
## [7] "base aérea" "berlin"
## [9] "brisas de los" "brisas del guabito"
## [11] "Cali" "calibella"
## [13] "calima" "calimio norte"
## [15] "cambulos" "centenario"
## [17] "chapinero" "chipichape"
## [19] "ciudad los álamos" "colinas del bosque"
## [21] "cristales" "el bosque"
## [23] "el cedro" "el gran limonar"
## [25] "el guabito" "el sena"
## [27] "el tr√©bol" "evaristo garcía"
## [29] "flora industrial" "floralia"
## [31] "gaitan" "granada"
## [33] "jorge eliecer gaitán" "juanamb√∫"
## [35] "la base" "la campiña"
## [37] "la esmeralda" "la flora"
## [39] "La Flora" "la floresta"
## [41] "la merced" "la rivera"
## [43] "la rivera i" "la rivera ii"
## [45] "la riviera" "la villa del"
## [47] "las acacias" "las américas"
## [49] "las ceibas" "las delicias"
## [51] "las granjas" "los andes"
## [53] "los guaduales" "los guayacanes"
## [55] "manzanares" "menga"
## [57] "metropolitano del norte" "nueva tequendama"
## [59] "oasis de comfandi" "occidente"
## [61] "pacara" "parque residencial el"
## [63] "paseo de los" "paso del comercio"
## [65] "poblado campestre" "popular"
## [67] "portada de comfandi" "portales de comfandi"
## [69] "porvenir" "prados del norte"
## [71] "quintas de salomia" "rozo la torre"
## [73] "salomia" "san luís"
## [75] "san luis" "san vicente"
## [77] "santa bárbara" "santa mónica"
## [79] "santa mónica residencial" "Santa Monica"
## [81] "santa monica" "santa monica norte"
## [83] "santa monica residencial" "santander"
## [85] "tejares de san" "torres de comfandi"
## [87] "unión de vivienda" "urbanización barranquilla"
## [89] "urbanización la flora" "urbanización la merced"
## [91] "urbanización la nueva" "valle del lili"
## [93] "versalles" "villa colombia"
## [95] "villa de veracruz" "villa del prado"
## [97] "Villa Del Prado" "villa del sol"
## [99] "Villas De Veracruz" "villas de veracruz"
## [101] "vipasa" "zona norte"
## [103] "zona oriente"
skim(df)
| Name | df |
| Number of rows | 722 |
| Number of columns | 13 |
| _______________________ | |
| Column type frequency: | |
| character | 3 |
| numeric | 10 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| zona | 0 | 1 | 10 | 10 | 0 | 1 | 0 |
| tipo | 0 | 1 | 4 | 4 | 0 | 1 | 0 |
| barrio | 0 | 1 | 4 | 25 | 0 | 103 | 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| id | 0 | 1 | 2574.65 | 1986.26 | 58.00 | 766.25 | 2257.00 | 4225.00 | 8319.00 | ▇▃▃▂▁ |
| piso | 0 | 1 | 1.48 | 0.72 | 1.00 | 1.00 | 1.00 | 2.00 | 7.00 | ▇▁▁▁▁ |
| estrato | 0 | 1 | 4.20 | 0.98 | 3.00 | 3.00 | 4.00 | 5.00 | 6.00 | ▇▅▁▇▂ |
| preciom | 0 | 1 | 445.91 | 268.36 | 89.00 | 261.25 | 390.00 | 550.00 | 1940.00 | ▇▃▁▁▁ |
| areaconst | 0 | 1 | 264.85 | 167.17 | 30.00 | 140.00 | 240.00 | 336.75 | 1440.00 | ▇▃▁▁▁ |
| parqueaderos | 0 | 1 | 1.31 | 1.53 | 0.00 | 0.00 | 1.00 | 2.00 | 10.00 | ▇▁▁▁▁ |
| banios | 0 | 1 | 3.56 | 1.52 | 0.00 | 2.00 | 3.00 | 4.00 | 10.00 | ▅▇▃▁▁ |
| habitaciones | 0 | 1 | 4.51 | 1.83 | 0.00 | 3.00 | 4.00 | 5.00 | 10.00 | ▁▇▅▂▁ |
| longitud | 0 | 1 | -76.52 | 0.02 | -76.59 | -76.53 | -76.52 | -76.50 | -76.47 | ▁▁▇▆▂ |
| latitud | 0 | 1 | 3.46 | 0.03 | 3.33 | 3.45 | 3.47 | 3.48 | 3.50 | ▁▁▁▂▇ |
shapiro.test(db$preciom)
##
## Shapiro-Wilk normality test
##
## data: db$preciom
## W = 0.86297, p-value < 2.2e-16
plot_ly(db, x = ~preciom, type = "histogram")%>%
layout(title = "Distribucion de preciom")
Como se puede deducir por los resultados del test de shapiro, la variable preciom no tiene una distribucion normal
# precio vs Estrato
plot_ly(data = db, x = ~preciom, y = ~estrato, type = 'box', orientation = 'h') %>%
layout(title = 'Precio vs Estrato')
# precio vs piso
plot_ly(data = db, x = ~preciom, y = ~piso, type = 'box', orientation = 'h') %>%
layout(title = 'Precio vs Piso')
# precio vs habitaciones
plot_ly(db, x = ~preciom, y = ~habitaciones, type = "box", orientation = 'h')%>%
layout(title = "Precio vs habitaciones")
# precio vs banios
plot_ly(db, x = ~preciom, y = ~banios, type = "box", orientation = 'h')%>%
layout(title = "Precio vs banios")
# precio vs banios
plot_ly(db, x = ~preciom, y = ~parqueaderos, type = "box", orientation = 'h')%>%
layout(title = "Precio vs banios")
#precio vs area
plot_ly(db, x = ~preciom, y = ~areaconst, color = ~estrato, type = )%>%layout(title = "Precio vs area")
Basados en un analisis graficio inicial, podemos inferir que el estrato y el area tienen una correlacion positiva con el precio, mientras que variables como banios, piso, habitaciones o parqueaderos, tienen una relacion mucho mas leve o casi nula respectivamente. Se requerira realizar un analisis de correlacion para ver el impacto real de cada variable
La correlacion se calculara con el dataset df en lugar de db para poder calcular la correlacion con la variable estrato de manera mas sencilla
corr=df[,c("preciom","areaconst","estrato","banios","habitaciones", "parqueaderos")]
(ggpairs(corr))
La grafica de correlaciones verifica las inferencias que se habian hecho con las graficas, hay una fuerte correlacion entre preciom y areaconst y estrato, banios tiene una correlacion positiva y habitaciones/parqueadero tienen una correlacion mucho mas baja.
Antes de construir el modelo, se realizara la normalizacion de las variables continuas para que todas queden en escalas similares.
nm = preProcess(db, method = "range")
db_nm = predict(nm,db)
head(db_nm)
## # A tibble: 6 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <dbl> <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0.139 Zona N… 0.167 5 0.125 0.0851 0.2 0.4 0.6
## 2 0.186 Zona N… 0.167 5 0.373 0.248 0.2 0.3 0.3
## 3 0.484 Zona N… 0.167 6 0.357 0.294 0 0.7 0.6
## 4 0.533 Zona N… 0.167 4 0.290 0.230 0.3 0.5 0.5
## 5 0.729 Zona N… 0.167 5 0.357 0.147 0.2 0.6 0.6
## 6 0.940 Zona N… 0.167 4 0.276 0.0922 0.1 0.4 0.5
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
Ahora se procede a construir el modelo con la base de datos normalizada con estimacion paso a paso
# se define el modelo ingenuo y= b0
modelo_b0 <- lm(preciom ~ 1, data = db_nm)
#define model with all predictors
modelo_all <- lm(preciom ~ areaconst + estrato + habitaciones + banios, data = db_nm)
# 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 15.155592 -2787.559
## 2 + areaconst -1 8.1062698 720 7.049322 -3338.206
## 3 + estrato -3 1.6524931 717 5.396829 -3525.066
## 4 + banios -1 0.2596723 716 5.137157 -3558.669
summary(forward)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios, data = db_nm)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.52338 -0.03951 -0.00883 0.02446 0.57754
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.016267 0.008280 -1.964 0.0499 *
## areaconst 0.632884 0.031820 19.889 < 2e-16 ***
## estrato4 0.045537 0.009129 4.988 7.66e-07 ***
## estrato5 0.074512 0.008500 8.766 < 2e-16 ***
## estrato6 0.177094 0.013953 12.693 < 2e-16 ***
## banios 0.146421 0.024339 6.016 2.85e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.0847 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
Como podemos ver, el modelo explica un 66% de los datos, adicionalmente el p-value siendo altamente significativo en contra de la hipotesis nula, nos permite afirmar que al menos uno de los valores tiene impacto en el precio.
A pesar de que 66% de la variabilidad es un numero aceptable, se podria mejorar agregando variables adicionales como el numero de pisos o el barrio. De contar con mas informacion como si es una vivienda independiente o parte de un conjunto cerrado, instalaciones adicionales como parques, piscinas, etc. se podria obtener una R2 mas elevada.
Lamentablemente al haber normalizado los valores, se pierde interpretabilidad en cuanto al incremento/impacto de cada variable en unidades “reales”.
par(mfrow = c(2, 2))
plot(forward)
La dispersion aleatoria alrededor de 0 en el grafico de Residuals vs Fitted, nos indica que no hay problemas con la linealidad del modelo.
shapiro.test(forward$residuals)
##
## Shapiro-Wilk normality test
##
## data: forward$residuals
## W = 0.83045, p-value < 2.2e-16
El resultado del test shapiro indica una evidencia extremadamente fuerte en contra de la hipótesis nula y sugiere que los datos no siguen una distribución normal. Esto en cierta forma es esperado puesto que al observar al inicio del ejercicio se observo que el precio no tiene una distribucion normal.
Dado que no tenemos mas variables disponibles para ussar, una alternativa podria ser realizar transformaciones sobre las variables
bptest(forward)
##
## studentized Breusch-Pagan test
##
## data: forward
## BP = 132.54, df = 5, p-value < 2.2e-16
Este resultado en la prueba de Breush-Pagan, indica que hay una fuerte evidencia en contra de la homocedasticidad en el modelo. En otras palabras, la varianza de los errores no es constante a lo largo del rango de los valores ajustados. Para intentar solucionarlo, se deben considerar técnicas de corrección o modelos alternativos que puedan manejar la variación no constante de la varianza.
Para evaluar la multicolinealidad se utilizara el Factor de Inflación de la Varianza o VIF
vif(forward)
## GVIF Df GVIF^(1/(2*Df))
## areaconst 1.430202 1 1.195910
## estrato 1.376739 3 1.054732
## banios 1.382317 1 1.175720
Como podemos ver, las variables presentan un VIF de entre 1 y 5, este rango se considera aceptable y no se presentarian problemas significativos por lo que no es necesario realizar ninguna correccion
set.seed(1)
train_db <- createDataPartition(y = db_nm$preciom,
p = 0.7,
list = FALSE)
train <- db_nm[train_db,]
test <- db_nm[-train_db,]
# Validacion de particion para el df de training
nrow(train)/nrow(db_nm)*100
## [1] 70.22161
# se define el modelo ingenuo y= b0
modelo_b0_train <- lm(preciom ~ 1, data = train)
#define model with all predictors
modelo_all_train <- lm(preciom ~ areaconst + estrato + habitaciones + banios, data = train)
# Se aplica el proceso forward stepwise regression
forward_train <-
step(
modelo_b0_train,
direction = 'forward',
scope = formula(modelo_all_train),
trace = 0
)
# Visualización de los resultados
forward_train$anova
## Step Df Deviance Resid. Df Resid. Dev AIC
## 1 NA NA 506 11.295638 -1926.676
## 2 + areaconst -1 5.9059935 505 5.389645 -2299.824
## 3 + estrato -3 1.2813812 502 4.108263 -2431.464
## 4 + banios -1 0.1849877 501 3.923276 -2452.823
summary(forward_train)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + banios, data = train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.52156 -0.04043 -0.00759 0.02562 0.57968
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.01613 0.01030 -1.566 0.117981
## areaconst 0.62957 0.03804 16.550 < 2e-16 ***
## estrato4 0.04325 0.01125 3.846 0.000136 ***
## estrato5 0.07605 0.01068 7.119 3.78e-12 ***
## estrato6 0.18317 0.01715 10.680 < 2e-16 ***
## banios 0.14981 0.03082 4.860 1.57e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.08849 on 501 degrees of freedom
## Multiple R-squared: 0.6527, Adjusted R-squared: 0.6492
## F-statistic: 188.3 on 5 and 501 DF, p-value: < 2.2e-16
Como podemos ver, el R2 baja en un 1% con respecto a entrenamiento con el dataset completo
prediccion <- predict(forward_train, newdata = test, type = "response")
db_predict <- data.frame(test$preciom, prediccion)
head(db_predict)
## test.preciom prediccion
## 1 0.12479741 0.17343104
## 2 0.05456510 0.16470926
## 3 0.04916261 0.06900372
## 4 0.11669368 0.11091171
## 5 0.15721232 0.25538833
## 6 0.09778498 0.16277006
plot_ly(db_predict, x=~test.preciom, y=~prediccion) %>% layout(title="test.preciom vs prediccion - Normalizado")
## No trace type specified:
## Based on info supplied, a 'scatter' trace seems appropriate.
## Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
## Setting the mode to markers
## Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
# Calcular el error cuadrático medio (MSE)
mse <- mean((test$preciom-prediccion)^2)
# Calcular el error absoluto medio (MAE)
mae <- mae(test$preciom, prediccion)
# Calcular R^2
r_squared <- cor(test$preciom, prediccion)^2
# Imprimir los resultados
print(paste("variable respuesta promedio - test:", mean(test$preciom)))
## [1] "variable respuesta promedio - test: 0.189793072255098"
print(paste("prediccion promedio:", mean(prediccion)))
## [1] "prediccion promedio: 0.194245294367316"
print(paste("Error cuadrático medio (MSE):", mse))
## [1] "Error cuadrático medio (MSE): 0.00566793128112028"
print(paste("Error absoluto medio (MAE):", mae))
## [1] "Error absoluto medio (MAE): 0.0493990005971985"
print(paste("R^2:", r_squared))
## [1] "R^2: 0.685974287234246"
Teniendo en cuenta que el valor promedio de la variable respuesta, el MSE y MAE calculados tienen un resultado considerablemente bajo, esto en combinacion con un R^2 de 0.68 nos dice que el modelo tiene un buen ajuste a los datos y explica una buena porcion de la variabilidad en la variable respuesta.