##Cargue de datos y librerias
#Cargue de datos
data("vivienda")
summary (vivienda)
## 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
Se identifica que la base de datos presenta valores faltantes, por tanto se procede realizar la identificación de la proporción de faltantes.
porcentaje_faltantes <- colSums(is.na(vivienda)) / nrow(vivienda) * 100
df_faltantes <- data.frame(
Variable = names(porcentaje_faltantes),
Porcentaje = porcentaje_faltantes
)
ggplot(df_faltantes, aes(x = reorder(Variable, -Porcentaje), y = Porcentaje)) +
geom_bar(stat = "identity", fill = "steelblue") +
coord_flip() +
labs(
title = "Porcentaje de Datos Faltantes por Variable",
x = "Variable",
y = "Porcentaje de Datos Faltantes"
) +
theme_minimal()
Se logra identificar que existe un porcentaje alto de datos faltantes
para las variables piso con más del 30% de datos faltantes, teniendo en
cuenta que esta variable no es necesaria para nuestro analisis o
construcción de nuestro modelo, procedemos a retirarla de la base de
datos.
#Quitar variable piso
vivienda_sin_piso <- vivienda %>% dplyr::select(-piso)
# Mostrar las primeras 5 filas del nuevo data frame 'vivienda_sin_piso'
head(vivienda_sin_piso, 5)
## # A tibble: 5 × 12
## id zona estrato preciom areaconst parqueaderos banios habitaciones tipo
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 1147 Zona O… 3 250 70 1 3 6 Casa
## 2 1169 Zona O… 3 320 120 1 2 3 Casa
## 3 1350 Zona O… 3 350 220 2 2 4 Casa
## 4 5992 Zona S… 4 400 280 3 5 3 Casa
## 5 1212 Zona N… 5 260 90 1 2 3 Apar…
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
La variable parqueadero cuenta con con cerca del 20% de datos faltantes, se asume que si la variable se encuentra en blanco es debido a que no tiene parqueadero,esto teniendo en cuenta que las propiedades inician con el valor 1, por tanto se procede a imputar en donde las variables N.A corresponden a 0.
# Crear un nuevo data frame 'viviendaimp' a partir de 'vivienda_sin_piso'
viviendaimp <- vivienda_sin_piso
# Imputar los NA de la variable 'parqueaderos' con 0 en el nuevo data frame 'viviendaimp'
viviendaimp$parqueaderos <- ifelse(is.na(viviendaimp$parqueaderos), 0, viviendaimp$parqueaderos)
# Mostrar las primeras 5 filas del data frame 'viviendaimp' para verificar la imputación
head(viviendaimp, 5)
## # A tibble: 5 × 12
## id zona estrato preciom areaconst parqueaderos banios habitaciones tipo
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 1147 Zona O… 3 250 70 1 3 6 Casa
## 2 1169 Zona O… 3 320 120 1 2 3 Casa
## 3 1350 Zona O… 3 350 220 2 2 4 Casa
## 4 5992 Zona S… 4 400 280 3 5 3 Casa
## 5 1212 Zona N… 5 260 90 1 2 3 Apar…
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
Por ultimo se retiran de la base las tres filas que cuentan con datos faltantes.
# Retirar las filas cuyo 'id' es NA del data frame 'viviendaimp'
vivienda2 <- viviendaimp[!is.na(viviendaimp$id), ]
# Mostrar las últimas 5 filas del nuevo data frame 'vivienda2'
tail(vivienda2, 5)
## # A tibble: 5 × 12
## id zona estrato preciom areaconst parqueaderos banios habitaciones tipo
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 4328 Zona S… 6 1650 460 2 6 4 Casa
## 2 4865 Zona S… 3 360 182 1 3 9 Casa
## 3 6417 Zona S… 6 1800 400 3 6 5 Casa
## 4 6998 Zona S… 6 1000 189 3 5 4 Apar…
## 5 8139 Zona S… 5 530 142 2 4 4 Casa
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
Verificamos que no existan datos faltantes
# Verificar si hay algún valor NA en el data frame 'vivienda'
any(is.na(vivienda2))
## [1] FALSE
##FILTRO A LA BASE DE DATOS
# Filtrar las ofertas de casas de la zona norte y guardar en 'Viviendanorte'
Viviendanorte <- vivienda2 %>%
filter(tipo == "Casa" & zona == "Zona Norte")
# Mostrar los primeros 3 registros de la base filtrada 'Viviendanorte'
head(Viviendanorte, 3)
## # A tibble: 3 × 12
## id zona estrato preciom areaconst parqueaderos banios habitaciones tipo
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 1209 Zona N… 5 320 150 2 4 6 Casa
## 2 1592 Zona N… 5 780 380 2 3 3 Casa
## 3 4057 Zona N… 6 750 445 0 7 6 Casa
## # ℹ 3 more variables: barrio <chr>, longitud <dbl>, latitud <dbl>
# Resumen estadístico de algunas variables relevantes
summary(Viviendanorte)
## id zona estrato preciom
## Min. : 58.0 Length:722 Min. :3.000 Min. : 89.0
## 1st Qu.: 766.2 Class :character 1st Qu.:3.000 1st Qu.: 261.2
## Median :2257.0 Mode :character Median :4.000 Median : 390.0
## Mean :2574.6 Mean :4.202 Mean : 445.9
## 3rd Qu.:4225.0 3rd Qu.:5.000 3rd Qu.: 550.0
## Max. :8319.0 Max. :6.000 Max. :1940.0
## areaconst parqueaderos banios habitaciones
## Min. : 30.0 Min. : 0.000 Min. : 0.000 Min. : 0.000
## 1st Qu.: 140.0 1st Qu.: 0.000 1st Qu.: 2.000 1st Qu.: 3.000
## Median : 240.0 Median : 1.000 Median : 3.000 Median : 4.000
## Mean : 264.9 Mean : 1.314 Mean : 3.555 Mean : 4.507
## 3rd Qu.: 336.8 3rd Qu.: 2.000 3rd Qu.: 4.000 3rd Qu.: 5.000
## Max. :1440.0 Max. :10.000 Max. :10.000 Max. :10.000
## tipo barrio longitud latitud
## Length:722 Length:722 Min. :-76.59 Min. :3.333
## Class :character Class :character 1st Qu.:-76.53 1st Qu.:3.452
## Mode :character Mode :character Median :-76.52 Median :3.468
## Mean :-76.52 Mean :3.460
## 3rd Qu.:-76.50 3rd Qu.:3.482
## Max. :-76.47 Max. :3.496
# Crear el data frame para el mapa con las coordenadas de 'Viviendanorte'
Viviendanorte_mapa <- cbind(Viviendanorte[, c("longitud", "latitud")])
# Verificar que no haya NA en longitud y latitud antes de crear el mapa
Viviendanorte_mapa <- Viviendanorte_mapa[!is.na(Viviendanorte_mapa$longitud) & !is.na(Viviendanorte_mapa$latitud), ]
# Crear una paleta de colores específica para las propiedades
# Si se desea agrupar por una categoría, agregar una columna de factor para diferenciar (opcional)
pal <- colorFactor(palette = c("red", "blue", "green"), domain = NULL) # Usamos NULL para no especificar dominios, o puedes definir un factor si hay categorías
# Crear el mapa
leaflet(Viviendanorte_mapa) %>%
addTiles() %>% # Agregar el fondo del mapa
addCircleMarkers(
~longitud, ~latitud,
color = ~pal(1), # Usamos un color fijo para todos, o puedes usar una variable categórica en lugar de 1
popup = ~paste("Longitud:", longitud, "<br>", "Latitud:", latitud), # Información emergente al hacer clic
radius = 5, # Tamaño de los puntos
stroke = FALSE, fillOpacity = 0.8
) %>%
addLegend("bottomright", pal = pal,
values = ~1, title = "Viviendas Zona Norte", opacity = 1)
De aqui se logra observar se presentan valores en otras zonas, por tanto existe problemas con la variable zona, para realizar la correción correspondiente , se realizó un cruce de las viviendas con un archivo que contiene las comunas a partir de los datos de longitud y latitud, se creo una nueva columna “zonacomuna” asumiendo que las comunas de la zona norte son las comunas 6, 5, 4 y 2, de una vez se identificaron las comunas de la zona sur asumiendolas como las 10,16,17,18,19 y 22.
# Leer el shapefile de las comunas
comunas <- st_read("C:/Users/giova/Downloads/Comunas.shp")
## Reading layer `Comunas' from data source `C:\Users\giova\Downloads\Comunas.shp' using driver `ESRI Shapefile'
## Simple feature collection with 22 features and 4 fields
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: -76.59076 ymin: 3.331819 xmax: -76.46125 ymax: 3.505871
## Geodetic CRS: WGS 84
# Convertir el data frame 'vivienda' a un objeto sf (simple features)
vivienda_sf <- st_as_sf(vivienda2, coords = c("longitud", "latitud"), crs = st_crs(comunas))
# Realizar la unión espacial para obtener la comuna correspondiente para cada vivienda
vivienda_sf <- st_join(vivienda_sf, comunas, left = FALSE)
# Crear la columna 'zonacomuna' para verificar si la vivienda está en la zona norte o sur
vivienda_sf <- vivienda_sf %>%
mutate(zonacomuna = case_when(
comuna %in% c(6, 5, 4, 2) ~ "Zona Norte",
comuna %in% c(16,17,18,22) ~ "Zona Sur",
TRUE ~ "Otra Zona"
))
# Convertir el objeto sf de nuevo a un data frame, si es necesario
viviendacomunas <- as.data.frame(vivienda_sf)
# Mostrar los primeros 5 registros para verificar la nueva columna 'zonacomuna'
head(viviendacomunas, 5)
## id zona estrato preciom areaconst parqueaderos banios habitaciones
## 1 1147 Zona Oriente 3 250 70 1 3 6
## 2 1169 Zona Oriente 3 320 120 1 2 3
## 3 1350 Zona Oriente 3 350 220 2 2 4
## 4 5992 Zona Sur 4 400 280 3 5 3
## 5 1212 Zona Norte 5 260 90 1 2 3
## tipo barrio geometry comuna nombre shape_leng
## 1 Casa 20 de julio POINT (-76.51168 3.43382) 11 Comuna 11 9668
## 2 Casa 20 de julio POINT (-76.51237 3.43369) 11 Comuna 11 9668
## 3 Casa 20 de julio POINT (-76.51537 3.43566) 11 Comuna 11 9668
## 4 Casa 3 de julio POINT (-76.54 3.435) 19 Comuna 19 24055
## 5 Apartamento acopi POINT (-76.5135 3.45891) 4 Comuna 4 11375
## shape_area zonacomuna
## 1 3713816 Otra Zona
## 2 3713816 Otra Zona
## 3 3713816 Otra Zona
## 4 10820091 Otra Zona
## 5 4519035 Zona Norte
Se realiza nuevamente el filtrado de la base de datos para la zona norte
# Filtrar el data frame 'viviendacomunas' para incluir solo las viviendas en la "Zona Norte" y de tipo "Casa"
vivienda_nortecomunas <- viviendacomunas %>%
filter(zonacomuna == "Zona Norte" & tipo == "Casa")
# Mostrar los primeros 3 registros del data frame filtrado
head(vivienda_nortecomunas, 3)
## id zona estrato preciom areaconst parqueaderos banios habitaciones
## 1 1209 Zona Norte 5 320 150 2 4 6
## 2 1592 Zona Norte 5 780 380 2 3 3
## 3 504 Zona Norte 3 180 120 0 3 3
## tipo barrio geometry comuna nombre shape_leng shape_area
## 1 Casa acopi POINT (-76.51341 3.47968) 2 Comuna 2 27825 10859503
## 2 Casa acopi POINT (-76.51674 3.48721) 2 Comuna 2 27825 10859503
## 3 Casa acopi POINT (-76.49768 3.4706) 5 Comuna 5 8438 4199641
## zonacomuna
## 1 Zona Norte
## 2 Zona Norte
## 3 Zona Norte
Se realiza nuevamente el filtrado de la base de datos para la zona sur
# Filtrar el data frame 'viviendacomunas' para incluir solo las viviendas en la "Zona Norte" y de tipo "Casa"
vivienda_surcomunas <- viviendacomunas %>%
filter(zonacomuna == "Zona Sur" & tipo == "Apartamento")
# Mostrar los primeros 3 registros del data frame filtrado
head(vivienda_surcomunas, 3)
## id zona estrato preciom areaconst parqueaderos banios habitaciones
## 1 1724 Zona Norte 5 240 87 1 3 3
## 2 4386 Zona Norte 5 310 137 2 3 4
## 3 5424 Zona Norte 4 320 108 2 3 3
## tipo barrio geometry comuna nombre shape_leng
## 1 Apartamento acopi POINT (-76.517 3.36971) 17 Comuna 17 17335
## 2 Apartamento acopi POINT (-76.53105 3.38296) 17 Comuna 17 17335
## 3 Apartamento acopi POINT (-76.53638 3.4077) 17 Comuna 17 17335
## shape_area zonacomuna
## 1 12677841 Zona Sur
## 2 12677841 Zona Sur
## 3 12677841 Zona Sur
Se procede a graficar el mapa de las viviendas por zona a partir de la columna creada zonacoumna, para validar que efectivamente se hayan filtrado de forma correcta
# Verificar si 'vivienda_nortecomunas' es un objeto sf
if (!inherits(vivienda_nortecomunas, "sf")) {
# Convertir 'vivienda_nortecomunas' a un objeto sf usando la columna de geometría existente
vivienda_nortecomunas <- st_as_sf(vivienda_nortecomunas)
}
# Extraer las coordenadas de longitud y latitud del objeto 'sf'
coords <- st_coordinates(vivienda_nortecomunas)
# Añadir las coordenadas extraídas como columnas al data frame 'vivienda_nortecomunas'
vivienda_nortecomunas$longitud <- coords[, 1]
vivienda_nortecomunas$latitud <- coords[, 2]
# Crear un data frame solo con las coordenadas para el mapa
vivienda_nortecomunas_mapa <- vivienda_nortecomunas[, c("longitud", "latitud")]
# Verificar que no haya NA en longitud y latitud antes de crear el mapa
vivienda_nortecomunas_mapa <- vivienda_nortecomunas_mapa[!is.na(vivienda_nortecomunas_mapa$longitud) & !is.na(vivienda_nortecomunas_mapa$latitud), ]
# Crear una paleta de colores específica para las propiedades
pal <- colorFactor(palette = c("blue"), domain = NULL) # Usamos un color fijo
# Crear el mapa
leaflet(vivienda_nortecomunas_mapa) %>%
addTiles() %>% # Agregar el fondo del mapa
addCircleMarkers(
~longitud, ~latitud,
color = ~pal(1), # Usamos un color fijo para todos
popup = ~paste("Longitud:", longitud, "<br>", "Latitud:", latitud), # Información emergente al hacer clic
radius = 5, # Tamaño de los puntos
stroke = FALSE, fillOpacity = 0.8
) %>%
addLegend("bottomright", pal = pal,
values = ~1, title = "Viviendas Zona Norte", opacity = 1)
# Verificar si 'vivienda_surcomunas' es un objeto sf
if (!inherits(vivienda_surcomunas, "sf")) {
# Convertir 'vivienda_surcomunas' a un objeto sf usando la columna de geometría existente
vivienda_surcomunas <- st_as_sf(vivienda_surcomunas)
}
# Extraer las coordenadas de longitud y latitud del objeto 'sf'
coords <- st_coordinates(vivienda_surcomunas)
# Añadir las coordenadas extraídas como columnas al data frame 'vivienda_surcomunas'
vivienda_surcomunas$longitud <- coords[, 1]
vivienda_surcomunas$latitud <- coords[, 2]
# Crear un data frame solo con las coordenadas para el mapa
vivienda_surcomunas_mapa <- vivienda_surcomunas[, c("longitud", "latitud")]
# Verificar que no haya NA en longitud y latitud antes de crear el mapa
vivienda_surcomunas_mapa <- vivienda_surcomunas_mapa[!is.na(vivienda_surcomunas_mapa$longitud) & !is.na(vivienda_surcomunas_mapa$latitud), ]
# Crear una paleta de colores específica para las propiedades
pal <- colorFactor(palette = c("red"), domain = NULL) # Usamos color rojo para las viviendas de la Zona Sur
# Crear el mapa
leaflet(vivienda_surcomunas_mapa) %>%
addTiles() %>% # Agregar el fondo del mapa
addCircleMarkers(
~longitud, ~latitud,
color = ~pal(1), # Usamos un color fijo (rojo) para todas las viviendas de la Zona Sur
popup = ~paste("Longitud:", longitud, "<br>", "Latitud:", latitud), # Información emergente al hacer clic
radius = 5, # Tamaño de los puntos
stroke = FALSE, fillOpacity = 0.8
) %>%
addLegend("bottomright", pal = pal,
values = ~1, title = "Viviendas Zona Sur", opacity = 1)
De aqui se logra observar que las viviendas filtradas corresponden a las zonas norte y sur, el error correspondia a que la zona inicial de la base de datos vivienda cuenta con inconsistencias, posiblemente debido a que son datos cuyo origen es una pagina web en la cual el usuario selecciona manualmente la zona, por tanto el dato de georeferenciación, latitud y longitud es más confiable al cruzarlo con el archivo que identifica las coumnas de Cali.
2.1 analisis exploratorio vivienda zona norte tipo casa
# Seleccionar solo las columnas necesarias
datos_interes <- vivienda_nortecomunas %>%
st_drop_geometry() %>% # Eliminar la columna de geometría
dplyr::select(preciom, areaconst, banios, habitaciones,parqueaderos)
# Crear el gráfico de correlación usando GGally
pair_plot <- ggpairs(datos_interes,
title = "Matriz de Correlación de Viviendas (Zona Norte - Tipo Casa)",
upper = list(continuous = wrap("cor", size = 5)), # Mostrar la correlación en la parte superior
diag = list(continuous = wrap("densityDiag")), # Mostrar la densidad en la diagonal
lower = list(continuous = wrap("points"))) # Mostrar puntos en la parte inferior
# Mostrar el gráfico
print(pair_plot)
Las relaciones más fuertes entre las variables se observan entre el precio de la vivienda y el área construida, el número de baños y el número de parqueaderos,esto es coherente teniendo en cuenta que comunmente factores como el tamaño de la casa y la cantidad de baños o parqueaderos deberian tienen un impacto significativo en el precio de la vivienda.
El grafico de dispersión refuerza lo observado previamente
# Convertir el objeto 'sf' a un data frame regular eliminando la geometría
vivienda_nortecomunas_df <- vivienda_nortecomunas %>%
st_drop_geometry() %>%
as.data.frame()
# Crear el gráfico de dispersión interactivo
fig <- plot_ly(
data = vivienda_nortecomunas_df,
x = ~areaconst, # Eje x: Área construida
y = ~preciom, # Eje y: Precio en millones
type = 'scatter', # Tipo de gráfico: scatter plot (dispersión)
mode = 'markers', # Modo: solo puntos
marker = list(size = 8, opacity = 0.7), # Tamaño y opacidad de los puntos
text = ~paste('Precio:', preciom, 'millones', '<br>Área:', areaconst, 'm²') # Texto emergente al hacer hover
) %>%
layout(
title = "Gráfico de Dispersión: Precio vs Área Construida (Zona Norte)",
xaxis = list(title = "Área Construida (m²)"),
yaxis = list(title = "Precio (Millones de Pesos)")
)
# Mostrar el gráfico
fig
Se observa que en la medida en que incrementa el área tambien se incrementa el precio de forma mas o menos consistente.
2.2 analisis exploratorio vivienda zona sur tipo apartamento
# Instalar GGally si no está instalado
if (!require(GGally)) install.packages("GGally")
# Cargar las librerías necesarias
library(GGally)
library(ggplot2)
library(dplyr)
# Seleccionar solo las columnas necesarias
datos_interes2 <- vivienda_surcomunas %>%
st_drop_geometry() %>% # Eliminar la columna de geometría
as.data.frame() %>% # Convertir a data frame
dplyr::select(preciom, areaconst, banios, habitaciones, parqueaderos)
# Crear el gráfico de correlación usando GGally
pair_plot2 <- ggpairs(datos_interes2,
title = "Matriz de Correlación de Viviendas (Zona Sur - Tipo Apartamento)",
upper = list(continuous = wrap("cor", size = 5)), # Mostrar la correlación en la parte superior
diag = list(continuous = wrap("densityDiag")), # Mostrar la densidad en la diagonal
lower = list(continuous = wrap("points"))) # Mostrar puntos en la parte inferior
# Mostrar el gráfico
print(pair_plot2)
Las características que parecen tener un mayor impacto en el precio incluyen el área construida, el número de baños y el número de parqueaderos en comparación con la “Zona Norte” para casas muestra que algunas características son más relevantes en una zona que en otra como los baños, probablemente debido a las diferencias en el tipo de las propiedades.
el grafico de dispersión refuerza lo observado previamente
# Convertir el objeto 'sf' a un data frame regular eliminando la geometría
vivienda_surcomunas_df <- vivienda_surcomunas %>%
st_drop_geometry() %>%
as.data.frame()
# Crear el gráfico de dispersión interactivo
fig2 <- plot_ly(
data = vivienda_surcomunas_df,
x = ~areaconst, # Eje x: Área construida
y = ~preciom, # Eje y: Precio en millones
type = 'scatter', # Tipo de gráfico: scatter plot (dispersión)
mode = 'markers', # Modo: solo puntos
marker = list(size = 8, opacity = 0.7), # Tamaño y opacidad de los puntos
text = ~paste('Precio:', preciom, 'millones', '<br>Área:', areaconst, 'm²') # Texto emergente al hacer hover
) %>%
layout(
title = "Gráfico de Dispersión: Precio vs Área Construida (Zona Sur)",
xaxis = list(title = "Área Construida (m²)"),
yaxis = list(title = "Precio (Millones de Pesos)")
)
# Mostrar el gráfico
fig2
Tambien Se observa que en la medida en que incrementa el área se incrementa el precio de forma más marcada.
# Convertir el objeto 'sf' a un data frame regular eliminando la geometría
vivienda_modelo <- vivienda_nortecomunas %>%
st_drop_geometry() %>% # Eliminar la columna de geometría para trabajar con un data frame regular
as.data.frame() # Asegurarnos de que el objeto sea un data frame regular
# Verificar que el objeto sea un data frame
class(vivienda_modelo) # Debe devolver "data.frame"
## [1] "data.frame"
# Seleccionar solo las columnas necesarias utilizando dplyr::select()
vivienda_modelo <- dplyr::select(vivienda_modelo, preciom, areaconst, parqueaderos, estrato, banios, habitaciones)
# Ajustar el modelo de regresión lineal múltiple
modelo_precio <- lm(preciom ~ areaconst + parqueaderos + estrato + banios + habitaciones, data = vivienda_modelo)
# Resumen del modelo
summary(modelo_precio)
##
## Call:
## lm(formula = preciom ~ areaconst + parqueaderos + estrato + banios +
## habitaciones, data = vivienda_modelo)
##
## Residuals:
## Min 1Q Median 3Q Max
## -930.94 -86.00 -15.49 41.94 1152.11
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -195.08755 37.57761 -5.192 2.86e-07 ***
## areaconst 0.83537 0.05146 16.232 < 2e-16 ***
## parqueaderos 20.92241 5.04807 4.145 3.90e-05 ***
## estrato 82.31305 9.09597 9.049 < 2e-16 ***
## banios 19.39137 7.01045 2.766 0.00585 **
## habitaciones -5.23238 5.32398 -0.983 0.32611
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 171.2 on 596 degrees of freedom
## Multiple R-squared: 0.6486, Adjusted R-squared: 0.6456
## F-statistic: 220 on 5 and 596 DF, p-value: < 2.2e-16
Intercepto: Coeficiente: -195.088, el coeficiente del intercepto indica el valor esperado del precio de una vivienda cuando todas las variables explicativas (área construida, parqueaderos, estrato, baños y habitaciones) son iguales a cero, este valor no tiene una interpretación práctica, ya que una vivienda con un área construida de 0 metros cuadrados, sin parqueaderos, de estrato 0, sin baños y sin habitaciones no existe en la realidad. Por lo tanto, el intercepto solo sirve como un punto de referencia en el modelo.
Área Construida (areaconst): Coeficiente: 0.835, manteniendo todas las demás variables constantes, un aumento de una unidad (1 metro cuadrado) en el área construida de la vivienda se asocia, en promedio, con un incremento de 0.835 millones de pesos en el precio de la casa. Este coeficiente es altamente significativo (valor p < 2e-16), lo que indica que el área construida es un predictor importante del precio de la vivienda en la zona norte de Cali.
Número de Parqueaderos (parqueaderos): Coeficiente: 20.922, manteniendo todas las demás variables constantes, un incremento de 1 en la cantidad de parqueaderos se asocia, en promedio, con un aumento de 20.922 millones de pesos en el precio de la vivienda. Este coeficiente es estadísticamente significativo (valor p = 3.90e-05), lo que indica que el número de parqueaderos es un factor importante para determinar el precio de las casas en esta área.
Estrato (estrato): Coeficiente: 82.313, manteniendo todas las demás variables constantes, un incremento de 1 unidad en el estrato se asocia, en promedio, con un aumento de 82.313 millones de pesos en el precio de la vivienda. Este resultado es estadísticamente significativo (valor p < 2e-16), lo que sugiere que el nivel socioeconómico del área (representado por el estrato) tiene un impacto considerable en el precio de las casas en la zona norte.
Número de Baños (baños): Coeficiente: 19.391,manteniendo todas las demás variables constantes, un incremento de 1 en el número de baños se asocia, en promedio, con un aumento de 19.391 millones de pesos en el precio de la vivienda. Este coeficiente es significativo (valor p = 0.00585), indicando que el número de baños es una variable relevante en el modelo.
Número de Habitaciones (habitaciones): Coeficiente: -5.232,manteniendo todas las demás variables constantes, un incremento de 1 en el número de habitaciones se asocia con una disminución de 5.232 millones de pesos en el precio de la vivienda. Sin embargo, este coeficiente no es estadísticamente significativo (valor p = 0.32611), lo que indica que no hay suficiente evidencia para afirmar que el número de habitaciones afecta el precio de la vivienda de manera significativa. Este resultado podría ser contraintuitivo y sugiere que esta variable no aporta mucha información al modelo. Evaluación del Modelo
R-cuadrado (R²): El valor del R-cuadrado es 0.6486, lo que indica que aproximadamente el 64.86% de la variabilidad en el precio de las casas en la región norte se explica por las variables independientes incluidas en el modelo (área construida, parqueaderos, estrato, baños y habitaciones). Esto sugiere que el modelo tiene un ajuste moderado a bueno.
Error estándar residual: El error estándar de los residuos es 171.2, lo cual nos indica la dispersión de los datos alrededor de la línea de regresión ajustada. Cuanto menor sea este valor, mejor será el ajuste del modelo.
##Recomendaciones para Mejorar el Modelo zona norte
Incluir Variables Adicionales:
Para mejorar la capacidad predictiva del modelo, se podrían considerar variables adicionales que puedan afectar el precio de las viviendas, como la Ubicación específica, la Antigüedad de la propiedad: Casas más nuevas tienden a ser más caras, tambien se puede eliminar variables no significativas, dado que el número de habitaciones no es un predictor significativo en este modelo (valor p = 0.32611), podríamos considerar eliminar esta variable para simplificar el modelo y mejorar su precisión. Transformar Variables:
# Graficar residuos vs valores ajustados para verificar la linealidad
plot(modelo_precio$fitted.values, resid(modelo_precio),
xlab = "Valores Ajustados", ylab = "Residuos",
main = "Gráfico de Residuos vs Valores Ajustados")
abline(h = 0, col = "red", lwd = 2)
El gráfico de residuos vs valores ajustados muestra que los residuos no
están distribuidos de manera completamente aleatoria alrededor de la
línea horizontal en cero. Hay un ligero patrón curvilíneo, especialmente
en los extremos, indica que la relación entre las variables
independientes y la variable dependiente no es completamente lineal.
# Prueba de Durbin-Watson
dwtest(modelo_precio)
##
## Durbin-Watson test
##
## data: modelo_precio
## DW = 1.8124, p-value = 0.009455
## alternative hypothesis: true autocorrelation is greater than 0
Un valor de Durbin-Watson cercano a 2 indica poca o ninguna autocorrelación en los residuos, sin embargo, el valor p bajo sugiere que hay una evidencia de autocorrelación positiva
# Graficar residuos estandarizados vs valores ajustados para verificar la homoscedasticidad
plot(modelo_precio$fitted.values, rstandard(modelo_precio),
xlab = "Valores Ajustados", ylab = "Residuos Estandarizados",
main = "Gráfico de Residuos Estandarizados vs Valores Ajustados")
abline(h = 0, col = "red", lwd = 2)
El gráfico de residuos estandarizados vs valores ajustados muestra una
cierta dispersión en forma de embudo, donde los residuos tienden a
dispersarse más a medida que aumentan los valores ajustados, indicando
heteroscedasticidad.
# Gráfico Q-Q para verificar la normalidad de los errores
qqnorm(resid(modelo_precio), main = "Gráfico Q-Q de los Residuos")
qqline(resid(modelo_precio), col = "red", lwd = 2)
# Prueba de Shapiro-Wilk para la normalidad de los residuos
shapiro.test(resid(modelo_precio))
##
## Shapiro-Wilk normality test
##
## data: resid(modelo_precio)
## W = 0.81553, p-value < 2.2e-16
el gráfico Q-Q muestra que los residuos no se ajustan perfectamente a la línea de normalidad. Hay desviaciones notables en ambos extremos del gráfico.
# Calcular VIF para evaluar la colinealidad
vif(modelo_precio)
## areaconst parqueaderos estrato banios habitaciones
## 1.692205 1.337130 1.690403 2.157940 1.825203
Los valores de VIF están por debajo de 5, lo que indica que no hay una multicolinealidad significativa entre las variables independientes en el modelo.
El modelo de regresión lineal múltiple presenta algunos problemas con los supuestos de linealidad, homoscedasticidad y normalidad de los errores para mejorarlo se podrian considerar las siguientes acciones:
Transformación de Variables: Transformar las variables independientes o la variable dependiente para mejorar la linealidad, la homoscedasticidad y la normalidad de los errores.
Manejo de Outliers: Revisar posibles outliers que afecten los resultados y considerar su eliminación o ajuste
# Convertir el objeto 'sf' a un data frame regular eliminando la geometría
vivienda_modelo <- vivienda_nortecomunas %>%
st_drop_geometry() %>%
as.data.frame()
# Fijar una semilla para la reproducibilidad
set.seed(123)
# Crear una columna de índice de muestra aleatoria (70% entrenamiento, 30% prueba)
sample_split <- sample.split(vivienda_modelo$preciom, SplitRatio = 0.7)
# Crear conjuntos de entrenamiento y prueba
train_set <- subset(vivienda_modelo, sample_split == TRUE)
test_set <- subset(vivienda_modelo, sample_split == FALSE)
# Comprobar el tamaño de los conjuntos
nrow(train_set)
## [1] 436
nrow(test_set)
## [1] 166
Se ajusta el modelo usando el conjunto de entrenamiento
# Ajustar el modelo de regresión lineal
modelo_precio_train <- lm(preciom ~ areaconst + parqueaderos + estrato + banios + habitaciones, data = train_set)
# Mostrar el resumen del modelo ajustado
summary(modelo_precio_train)
##
## Call:
## lm(formula = preciom ~ areaconst + parqueaderos + estrato + banios +
## habitaciones, data = train_set)
##
## Residuals:
## Min 1Q Median 3Q Max
## -861.14 -91.76 -16.35 47.82 1151.90
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -209.0744 45.3487 -4.610 5.31e-06 ***
## areaconst 0.8131 0.0611 13.309 < 2e-16 ***
## parqueaderos 21.5411 6.0565 3.557 0.000417 ***
## estrato 94.8037 11.1477 8.504 3.05e-16 ***
## banios 17.1181 8.4591 2.024 0.043626 *
## habitaciones -10.5088 6.6485 -1.581 0.114696
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 177.8 on 430 degrees of freedom
## Multiple R-squared: 0.6307, Adjusted R-squared: 0.6264
## F-statistic: 146.9 on 5 and 430 DF, p-value: < 2.2e-16
# Realizar predicciones con el modelo ajustado usando el conjunto de prueba
predicciones <- predict(modelo_precio_train, newdata = test_set)
# Ver los primeros valores predichos
head(predicciones)
## 11 17 27 29 33 34
## 666.8731 284.2246 195.5772 190.3598 189.0295 137.3418
# Calcular el Error Cuadrático Medio (MSE)
mse <- mean((test_set$preciom - predicciones)^2)
# Calcular el Error Absoluto Medio (MAE)
mae <- mean(abs(test_set$preciom - predicciones))
# Calcular el RMSE (Raíz del Error Cuadrático Medio)
rmse <- sqrt(mse)
# Calcular el MAPE (Error Porcentual Absoluto Medio)
mape <- mean(abs((test_set$preciom - predicciones) / test_set$preciom)) * 100
# Mostrar las métricas de rendimiento
cat("MSE:", mse, "\n")
## MSE: 24238.4
cat("MAE:", mae, "\n")
## MAE: 105.6264
cat("RMSE:", rmse, "\n")
## RMSE: 155.6869
cat("MAPE:", mape, "%\n")
## MAPE: 23.21534 %
MSE (Error Cuadrático Medio): 24238.4 indica que el modelo está haciendo buenas predicciones, pero el valor que tienes es relativamente alto, lo que sugiere que hay una cantidad considerable de error en las predicciones del modelo.
MAE (Error Absoluto Medio): 105.6264 el MAE sugiere que, en promedio, el modelo se desvía en alrededor de 105.6 millones de pesos del valor real de las viviendas. Esto también es una desviación significativa, lo que implica que las predicciones pueden no ser muy precisas.
RMSE (Raíz del Error Cuadrático Medio): 155.6869 significa que, en promedio, las predicciones del modelo tienen un error de aproximadamente 155.7 millones de pesos. Al igual que el MSE y el MAE, este valor también indica que hay errores significativos en las predicciones del modelo.
El valor de R-cuadrado (R²) de 0.6307 significa que el modelo de regresión puede explicar el 63.07% de la variabilidad en el precio de las viviendas a partir de las variables predictoras incluidas en el modelo.
tambien se hizo una predicción sobre el precio de la vivienda con las características de la primera solicitud.
# Predicción
data2 <- data.frame(
areaconst = 200,
parqueaderos = 1,
estrato = c(4, 5),
banios = 2,
habitaciones = 4
)
# Realizar la predicción
predict(modelo_precio, newdata = data2)
## 1 2
## 340.0138 422.3268
la predicción indica que el precio para una vivienda estrato 4 tipo casa con las caracteristicas requeridas tendria un valor de 340 millones, mientras que la misma vivienda en estrato 5 costaria al rededor de los 422 millones.
vivienda_nortecomunas <- st_drop_geometry(vivienda_nortecomunas)
# Filtrar las propiedades que cumplen con los criterios
ofertas_potenciales <- vivienda_nortecomunas %>%
filter(
estrato %in% c(4, 5), # Incluir tanto estrato 4 como 5
areaconst >= 190 & areaconst <= 210, # Rango cercano a 200 m²
parqueaderos == 1,
banios == 2,
habitaciones == 4,
preciom <= 350 # Precio dentro del límite de crédito
) %>%
arrange(preciom) # Ordenar por precio para priorizar las ofertas más económicas
# Verificar las 5 primeras ofertas
head(ofertas_potenciales, 5)
## [1] id zona estrato preciom areaconst
## [6] parqueaderos banios habitaciones tipo barrio
## [11] comuna nombre shape_leng shape_area zonacomuna
## [16] longitud latitud
## <0 rows> (or 0-length row.names)
No se cuenta con viviendas con estas caracteristicas exactas, por tanto se presentan algunos ajustes en los parametros de busqueda, en donde se busca un rango superior a 190 metros, con más de un parqueadero, considerando que más de estas atributos pueden ser condiciones deseables potencialmente.
Con estos nuevos criterios se logran identificar tres prospectos potenciales.
vivienda_nortecomunas <- st_drop_geometry(vivienda_nortecomunas)
# Filtrar las propiedades que cumplen con los criterios
ofertas_potenciales <- vivienda_nortecomunas %>%
filter(
estrato %in% c(4, 5),
areaconst >= 190 , # Rango superior a 200 m²
parqueaderos >= 1,
banios == 2,
habitaciones == 4,
preciom <= 350 # Precio dentro del límite de crédito
) %>%
arrange(preciom) # Ordenar por precio para priorizar las ofertas más económicas
# Verificar las 5 primeras ofertas
head(ofertas_potenciales, 5)
## id zona estrato preciom areaconst parqueaderos banios habitaciones
## 1 1822 Zona Norte 4 340 295 2 2 4
## 2 1163 Zona Norte 5 350 216 2 2 4
## 3 1943 Zona Norte 5 350 346 1 2 4
## tipo barrio comuna nombre shape_leng shape_area zonacomuna longitud
## 1 Casa vipasa 2 Comuna 2 27825 10859503 Zona Norte -76.51777
## 2 Casa la merced 2 Comuna 2 27825 10859503 Zona Norte -76.51218
## 3 Casa vipasa 2 Comuna 2 27825 10859503 Zona Norte -76.51847
## latitud
## 1 3.48060
## 2 3.48181
## 3 3.47503
Se encontraron tres propiedades que cumplen en gran medida con las caracteristicas requeridas, una de estrato 4 y dos de estrato 5.
# Asegurarse de que el dataframe esté en un formato adecuado
vivienda_nortecomunas_df <- vivienda_nortecomunas %>%
st_drop_geometry() %>%
as.data.frame()
# Filtrar el dataset para incluir solo los IDs específicos
oferta_potencial <- vivienda_nortecomunas_df %>%
filter(id %in% c(1822, 1163, 1943))
# Verificar que los datos tengan las columnas de longitud y latitud
if (!all(c("longitud", "latitud") %in% colnames(oferta_potencial))) {
stop("Las columnas 'longitud' y 'latitud' son necesarias para el mapa.")
}
# Crear el mapa interactivo
mapa_oferta <- leaflet(oferta_potencial) %>%
addTiles() %>% # Agregar fondo de mapa
addCircleMarkers(
~longitud, ~latitud,
radius = 8, # Tamaño de los puntos
color = "red", # Color de los puntos
stroke = FALSE, fillOpacity = 0.8,
popup = ~paste(
"ID:", id, "<br>",
"Precio:", preciom, "millones", "<br>",
"Área construida:", areaconst, "m²", "<br>",
"Estrato:", estrato, "<br>",
"Parqueaderos:", parqueaderos, "<br>",
"Baños:", banios, "<br>",
"Habitaciones:", habitaciones
) # Información emergente al hacer clic
)
# Mostrar el mapa
mapa_oferta
Aplicar los mismos pasos para la vivienda tipo apartamento zona sur
# Convertir el objeto 'sf' a un data frame regular eliminando la geometría
vivienda_modelo_sur <- vivienda_surcomunas %>%
st_drop_geometry() %>% # Eliminar la columna de geometría
as.data.frame() # Convertir a data frame
# Verificar que el objeto sea un data frame
class(vivienda_modelo_sur) # Debe devolver "data.frame"
## [1] "data.frame"
# Seleccionar solo las columnas necesarias utilizando dplyr::select()
vivienda_modelo_sur <- dplyr::select(vivienda_modelo_sur, preciom, areaconst, parqueaderos, estrato, banios, habitaciones)
# Ajustar el modelo de regresión lineal múltiple
modelo_precio_sur <- lm(preciom ~ areaconst + parqueaderos + estrato + banios + habitaciones, data = vivienda_modelo_sur)
# Resumen del modelo
summary(modelo_precio_sur)
##
## Call:
## lm(formula = preciom ~ areaconst + parqueaderos + estrato + banios +
## habitaciones, data = vivienda_modelo_sur)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1295.13 -42.28 -2.17 34.47 906.70
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -232.33868 16.66591 -13.941 < 2e-16 ***
## areaconst 1.50079 0.05715 26.261 < 2e-16 ***
## parqueaderos 50.35258 3.60535 13.966 < 2e-16 ***
## estrato 53.68143 3.49194 15.373 < 2e-16 ***
## banios 58.28287 3.73059 15.623 < 2e-16 ***
## habitaciones -21.95747 4.18467 -5.247 1.7e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 101.4 on 2098 degrees of freedom
## Multiple R-squared: 0.7634, Adjusted R-squared: 0.7629
## F-statistic: 1354 on 5 and 2098 DF, p-value: < 2.2e-16
Coeficientes del Modelo
Intercepto (Intercept): -232.34, este es el valor estimado del precio de la vivienda cuando todas las variables independientes son 0. Aunque no tiene una interpretación práctica directa
Área Construida (areaconst): 1.50,manteniendo todas las demás variables constantes, un aumento de 1 m² en el área construida se asocia, en promedio, con un aumento de 1.50 millones de pesos en el precio de la vivienda. Este coeficiente es altamente significativo (valor p < 2e-16), lo que indica que el área construida es un predictor importante del precio de la vivienda en la zona sur de Cali.
Número de Parqueaderos (parqueaderos): 50.35, manteniendo todas las demás variables constantes, un incremento de 1 parqueadero se asocia, en promedio, con un aumento de 50.35 millones de pesos en el precio de la vivienda. Este coeficiente es estadísticamente significativo (valor p < 2e-16), indicando que el número de parqueaderos es un factor relevante en la determinación del precio.
Estrato (estrato): 53.68, manteniendo todas las demás variables constantes, un aumento de 1 unidad en el estrato se asocia, en promedio, con un incremento de 53.68 millones de pesos en el precio de la vivienda. Este resultado es estadísticamente significativo (valor p < 2e-16), sugiriendo que el nivel socioeconómico del área tiene un impacto considerable en el precio de las casas en la zona sur.
Número de Baños (banios): 58.28 manteniendo todas las demás variables constantes, un aumento de 1 baño se asocia, en promedio, con un incremento de 58.28 millones de pesos en el precio de la vivienda. Este coeficiente también es significativo (valor p < 2e-16), lo que indica que el número de baños es una variable importante en el modelo.
Número de Habitaciones (habitaciones): -21.96,Manteniendo todas las demás variables constantes, un aumento de 1 en el número de habitaciones se asocia con una disminución de 21.96 millones de pesos en el precio de la vivienda. Este coeficiente es estadísticamente significativo (valor p = 1.7e-07). Este resultado puede parecer contraintuitivo y sugiere que el número de habitaciones podría estar relacionado negativamente con el precio en esta muestra, quizás debido a otros factores no capturados por el modelo. Evaluación del Modelo
El valor de R² de 0.7634 sugiere que aproximadamente el 76.34% de la variabilidad en el precio de las viviendas en la zona sur de Cali se explica por las variables independientes incluidas en el modelo. Esto indica que el modelo tiene un buen ajuste.
# Graficar residuos vs valores ajustados para verificar la linealidad
plot(modelo_precio_sur$fitted.values, resid(modelo_precio_sur),
xlab = "Valores Ajustados", ylab = "Residuos",
main = "Gráfico de Residuos vs Valores Ajustados (Zona Sur)")
abline(h = 0, col = "red", lwd = 2)
# Prueba de Durbin-Watson
library(lmtest)
dwtest(modelo_precio_sur)
##
## Durbin-Watson test
##
## data: modelo_precio_sur
## DW = 1.5934, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0
# Graficar residuos estandarizados vs valores ajustados para verificar la homoscedasticidad
plot(modelo_precio_sur$fitted.values, rstandard(modelo_precio_sur),
xlab = "Valores Ajustados", ylab = "Residuos Estandarizados",
main = "Gráfico de Residuos Estandarizados vs Valores Ajustados (Zona Sur)")
abline(h = 0, col = "red", lwd = 2)
# Gráfico Q-Q para verificar la normalidad de los errores
qqnorm(resid(modelo_precio_sur), main = "Gráfico Q-Q de los Residuos (Zona Sur)")
qqline(resid(modelo_precio_sur), col = "red", lwd = 2)
# Prueba de Shapiro-Wilk para la normalidad de los residuos
shapiro.test(resid(modelo_precio_sur))
##
## Shapiro-Wilk normality test
##
## data: resid(modelo_precio_sur)
## W = 0.75949, p-value < 2.2e-16
# Calcular VIF para evaluar la colinealidad
library(car)
vif(modelo_precio_sur)
## areaconst parqueaderos estrato banios habitaciones
## 2.019007 1.774856 1.807051 2.529172 1.328700
En el gráfico de residuos vs. valores ajustados, los residuos no están distribuidos completamente de manera aleatoria alrededor de la línea horizontal en cero. Hay una concentración de puntos cerca de la línea en los valores ajustados bajos, pero se observa mayor dispersión a medida que los valores ajustados aumentan, este patrón sugiere que puede haber una relación no lineal entre las variables predictoras y la variable de respuesta o que el modelo no captura completamente la estructura de los datos.
El gráfico Q-Q muestra que los residuos no siguen una distribución normal perfectamente. Hay desviaciones significativas en ambos extremos del gráfico (colas más gruesas), esto indica que los residuos tienen una distribución más sesgada o con colas más pesadas que la normal.
El gráfico de residuos estandarizados vs. valores ajustados también muestra una dispersión mayor a medida que los valores ajustados aumentan. Esto sugiere heteroscedasticidad
El valor de Durbin-Watson (1.5934) está por debajo de 2, lo que indica la presencia de autocorrelación positiva en los residuos. El p-valor extremadamente bajo (< 2.2e-16) confirma la significancia de esta autocorrelación.
Prueba de Normalidad de Shapiro-Wilk, un valor W de 0.75949 y un p-valor extremadamente bajo indican que los residuos no siguen una distribución normal.
# Calcular VIF para evaluar la colinealidad
vif(modelo_precio_sur)
## areaconst parqueaderos estrato banios habitaciones
## 2.019007 1.774856 1.807051 2.529172 1.328700
Los valores de VIF están por debajo de 5, lo que indica que no hay una multicolinealidad significativa entre las variables independientes en el modelo.
Recomendaciones: El modelo de regresión lineal múltiple para vivienda_surcomunas muestra algunos problemas con los supuestos de normalidad, homoscedasticidad, independencia de los errores y linealidad, se pueden realizar la transformación de Variables , tambien se recomienda revisar posibles outliers que afecten los resultados y considera su eliminación o ajuste.
Dividir los datos en 70% entrenamiento y 30% prueba para el dataset de apartamentos sur
# Convertir el objeto 'sf' a un data frame regular eliminando la geometría
vivienda_modelo_sur <- vivienda_surcomunas %>%
st_drop_geometry() %>%
as.data.frame()
# Fijar una semilla para la reproducibilidad
set.seed(123)
# Crear una columna de índice de muestra aleatoria (70% entrenamiento, 30% prueba)
library(caTools)
sample_split <- sample.split(vivienda_modelo_sur$preciom, SplitRatio = 0.7)
# Crear conjuntos de entrenamiento y prueba
train_set_sur <- subset(vivienda_modelo_sur, sample_split == TRUE)
test_set_sur <- subset(vivienda_modelo_sur, sample_split == FALSE)
# Comprobar el tamaño de los conjuntos
nrow(train_set_sur)
## [1] 1500
nrow(test_set_sur)
## [1] 604
# Ajustar el modelo de regresión lineal múltiple usando el conjunto de entrenamiento
modelo_precio_train_sur <- lm(preciom ~ areaconst + parqueaderos + estrato + banios + habitaciones, data = train_set_sur)
# Mostrar el resumen del modelo ajustado
summary(modelo_precio_train_sur)
##
## Call:
## lm(formula = preciom ~ areaconst + parqueaderos + estrato + banios +
## habitaciones, data = train_set_sur)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1162.83 -45.09 -2.20 35.31 920.51
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -234.06440 20.30971 -11.53 < 2e-16 ***
## areaconst 1.34183 0.06512 20.61 < 2e-16 ***
## parqueaderos 57.12732 4.29696 13.29 < 2e-16 ***
## estrato 54.56354 4.28318 12.74 < 2e-16 ***
## banios 60.28988 4.55577 13.23 < 2e-16 ***
## habitaciones -21.83439 5.04280 -4.33 1.59e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 105.4 on 1494 degrees of freedom
## Multiple R-squared: 0.7532, Adjusted R-squared: 0.7523
## F-statistic: 911.7 on 5 and 1494 DF, p-value: < 2.2e-16
Realice predicciones con el modelo anterior usando los datos de prueba (30%)
# Realizar predicciones con el modelo ajustado usando el conjunto de prueba
predicciones_sur <- predict(modelo_precio_train_sur, newdata = test_set_sur)
# Ver los primeros valores predichos
head(predicciones_sur)
## 7 8 11 15 24 25
## 139.9035 119.7761 237.4056 139.9035 138.5617 219.9618
# Calcular el Error Cuadrático Medio (MSE)
mse_sur <- mean((test_set_sur$preciom - predicciones_sur)^2)
# Calcular el Error Absoluto Medio (MAE)
mae_sur <- mean(abs(test_set_sur$preciom - predicciones_sur))
# Calcular el RMSE (Raíz del Error Cuadrático Medio)
rmse_sur <- sqrt(mse_sur)
# Calcular el MAPE (Error Porcentual Absoluto Medio)
mape_sur <- mean(abs((test_set_sur$preciom - predicciones_sur) / test_set_sur$preciom)) * 100
# Mostrar las métricas de rendimiento
cat("MSE:", mse_sur, "\n")
## MSE: 8374.708
cat("MAE:", mae_sur, "\n")
## MAE: 58.02957
cat("RMSE:", rmse_sur, "\n")
## RMSE: 91.51343
cat("MAPE:", mape_sur, "%\n")
## MAPE: 20.74411 %
Análisis de las Métricas de Rendimiento
MSE (Error Cuadrático Medio): 8374.708, Hay una cantidad significativa de error en las predicciones, pero comparado con el modelo anterior (vivienda_nortecomunas), este es mucho menor, lo que indica un mejor rendimiento.
MAE (Error Absoluto Medio): 58.02957, En promedio, el modelo se desvía por 58.03 millones de pesos del valor real de las viviendas. Este valor es bastante razonable para modelos de predicción de precios de viviendas, y muestra una mejora significativa en comparación con el modelo para vivienda_nortecomunas. RMSE (Raíz del Error Cuadrático Medio): 91.51343
Un RMSE de 91.51 millones de pesos significa que, en promedio, las predicciones del modelo tienen un error de aproximadamente 91.51 millones de pesos. Este es un error más bajo en comparación con el modelo para vivienda_nortecomunas, lo que indica un mejor rendimiento en la zona sur. MAPE (Error Porcentual Absoluto Medio): 20.74411%
El valor de R-cuadrado (R²) de 0.75 : Este valor sugiere que el modelo tiene un ajuste alto. Un R² de 0.75 significa que el modelo de regresión puede explicar el 75% de la variabilidad en el precio de las viviendas a partir de las variables predictoras incluidas en el modelo.
Predecir el precio con el modelo inicial para una vivienda tipo apartamento en el sur
# Crear el data frame con las características de la vivienda para la predicción
nueva_vivienda <- data.frame(
areaconst = 300, # Área construida de 300 m²
parqueaderos = 3, # 3 parqueaderos
estrato = c(5, 6), # Estrato 5 y 6 para hacer dos predicciones
banios = 3, # 3 baños
habitaciones = 5 # 5 habitaciones
)
# Realizar la predicción con el modelo inicial
predicciones_nueva_vivienda <- predict(modelo_precio_sur, newdata = nueva_vivienda)
# Mostrar los resultados de las predicciones
predicciones_nueva_vivienda
## 1 2
## 702.4245 756.1060
6.Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 1. Tenga encuentra que la empresa tiene crédito pre-aprobado de máximo 850 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.
vivienda_surcomunas <- st_drop_geometry(vivienda_surcomunas)
# Filtrar las propiedades que cumplen con los criterios
ofertas_potenciales2 <- vivienda_surcomunas %>%
filter(
estrato %in% c(5, 6), # Incluir tanto estrato 5 como 6
areaconst >= 300 & areaconst <= 310, # Rango cercano a 200 m²
parqueaderos == 3,
banios == 3,
habitaciones == 5,
preciom <= 850 # Precio dentro del límite de crédito
) %>%
arrange(preciom) # Ordenar por precio para priorizar las ofertas más económicas
# Verificar las 5 primeras ofertas
head(ofertas_potenciales2, 5)
## [1] id zona estrato preciom areaconst
## [6] parqueaderos banios habitaciones tipo barrio
## [11] comuna nombre shape_leng shape_area zonacomuna
## [16] longitud latitud
## <0 rows> (or 0-length row.names)
Teniendo en cuenta que no se identifican viviendas con estas caracteristicas exactas se procede a filtrar con algunos ajustes en los parametros de busqueda, en donde se busca un rango superior a 300 metros, con más de tres parqueaderos, baños y habitaciones, considerando que más de estas atributos pueden ser condiciones deseables potencialmente.
Con estos nuevos criterios tampoco se logran identificar prospectos potenciales.
vivienda_surcomunas <- st_drop_geometry(vivienda_surcomunas)
# Filtrar las propiedades que cumplen con los criterios
ofertas_potenciales3 <- vivienda_surcomunas %>%
filter(
estrato %in% c(5, 6), # Incluir tanto estrato 5 como 6
areaconst >= 300 , # Rango superior a 300 m²
parqueaderos >= 3,
banios >= 3,
habitaciones >=5,
preciom <= 850 # Precio dentro del límite de crédito
) %>%
arrange(preciom) # Ordenar por precio para priorizar las ofertas más económicas
head(ofertas_potenciales3, 5)
## [1] id zona estrato preciom areaconst
## [6] parqueaderos banios habitaciones tipo barrio
## [11] comuna nombre shape_leng shape_area zonacomuna
## [16] longitud latitud
## <0 rows> (or 0-length row.names)
# Verificar las 5 primeras ofertas