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