María 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.
Hace dos días, María recibió una carta solicitando asesoría para la compra de dos viviendas por parte de una compañía internacional que desea ubicar a dos de sus empleados con sus familias en la ciudad. Las solicitudes incluyen las siguientes condiciones:
# Creacion un data frame con los datos de la tabla
tabla_viviendas <- data.frame(
Características = c("Tipo", "Área Construida", "Parqueaderos", "Baños",
"Habitaciones", "Estrato", "Zona", "Crédito Preaprobado"),
Vivienda1 = c("Casa", "200", "1", "2", "4", "4 o 5", "Norte", "350 millones"),
Vivienda2 = c("Apartamento", "300", "3", "3", "5", "5 o 6", "Sur", "850 millones"),
stringsAsFactors = FALSE
)
# Mostrar en consola
print(tabla_viviendas)
Características Vivienda1 Vivienda2
1 Tipo Casa Apartamento
2 Área Construida 200 300
3 Parqueaderos 1 3
4 Baños 2 3
5 Habitaciones 4 5
6 Estrato 4 o 5 5 o 6
7 Zona Norte Sur
8 Crédito Preaprobado 350 millones 850 millones
Ayude a María a responder la solicitud, mediante técnicas modelación que usted conoce. Ella requiere le envíe un informe ejecutivo donde analice los dos casos y sus recomendaciones (Informe). Como soporte del informe debe anexar las estimaciones, validaciones y comparación de modelos requeridos (Anexos).
El alcance del presente informe fue el análisis de las condiciones de
la Vivienda 1 en la cual se requiere localizar para la compra una
vivienda del tipo Casa con un área de 200 m2, con 2 baños, 4
habitaciones, estrato 4 y en la zona Norte, para esto se tiene un
préstamo preaprobado de 350 millones de pesos.
Se procede a realizar exploración del dataset en donde se evidenció
errores en las etiqueas de los datos de geolocalización, como parte del
preprosesamiento se procede a reclasificar geograficamente los puntos de
acuerdo a las zonas de la ciudad de cali.
Se realiza el modelado mediante regresión lineal múltiple realizando
las validaciones del modelo indentificando que la hipótesis de No
autocorrelación no se cumple, razón por la cual se realizan modelos
transformados comprobando los parámetros de P-valor y R2 ajustado con el
fin de validar el mejor modelo.
Como resultado el mejor modelo fue el logaritmico sobre el cual se
realizaron predicciones para estratos 4 y 5 según los requerimientos del
cliente.
Con base a los datos ya preprocesados y teniendo en cuenta el modelo
final se realiza un filtrado de posibles alternativas para presentar al
cliente.
Debido a la generación del mapa interactivo final es posible para el
cliente y para el vendedor tomar una rápida decisión ya que visualiza la
ubicación, el el estrato, el área construida, el numero de parqueaderos,
el número de habitaciones y el barrio.
Es importante mencionar que el ejercicio es completamente escalable a
otros tipos de variables que permitan aumentar la predicción del
modelo.
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.
Adicional un mapa con los puntos de las bases, discutir si todoslos
puntos se ubican en la zona correspondiente o se presentan valores en
otras zonas, por que?).
1.1 Carga y exploración del Dataset:
Realizamos las respectiva carga de datos para análisis y preprocesamiento.
library(paqueteMODELOS)
data("vivienda")
head(vivienda)
# A tibble: 6 × 13
id zona piso estrato preciom areaconst parqueaderos banios habitaciones
<dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1147 Zona O… <NA> 3 250 70 1 3 6
2 1169 Zona O… <NA> 3 320 120 1 2 3
3 1350 Zona O… <NA> 3 350 220 2 2 4
4 5992 Zona S… 02 4 400 280 3 5 3
5 1212 Zona N… 01 5 260 90 1 2 3
6 1724 Zona N… 01 5 240 87 1 3 3
# ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
1.2 Limpieza y preprosesamiento del dataset:
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
Revisión tipos de variables:
Revisamos lo tipos de variables presentes en el dataset.
clase <- sapply(vivienda, class)
clase
id zona piso estrato preciom areaconst
"numeric" "character" "character" "numeric" "numeric" "numeric"
parqueaderos banios habitaciones tipo barrio longitud
"numeric" "numeric" "numeric" "character" "character" "numeric"
latitud
"numeric"
Imputación de variables:
Procedemos a realizar imputación de variables.
library(mice)
# Convertir el atributo "piso" a numérico y reemplazar valores faltantes con 1
vivienda$piso <- as.numeric(vivienda$piso)
vivienda$piso[is.na(vivienda$piso)] <- 1
# Eliminar filas donde "preciom" tenga valores faltantes
vivienda<- vivienda %>% filter(!is.na(preciom))
# Imputar valores faltantes en "parqueaderos" con 1
vivienda$parqueaderos[is.na(vivienda$parqueaderos) | vivienda$parqueaderos == 0] <- 1
# Eliminar filas donde "habitaciones" tenga valores faltantes
vivienda <- vivienda %>% filter(!is.na(habitaciones) & habitaciones != 0)
# Aplicar la imputación con la librería mice
imputed_data <- mice(vivienda, m=1, method='pmm', maxit=5)
iter imp variable
1 1
2 1
3 1
4 1
5 1
vivienda <- complete(imputed_data)
Verificamos que no tengamos valores faltantes:
summary(vivienda)
id zona piso estrato
Min. : 1 Length:8253 Min. : 1.000 Min. :3.000
1st Qu.:2081 Class :character 1st Qu.: 1.000 1st Qu.:4.000
Median :4165 Mode :character Median : 2.000 Median :5.000
Mean :4162 Mean : 2.897 Mean :4.638
3rd Qu.:6245 3rd Qu.: 4.000 3rd Qu.:5.000
Max. :8319 Max. :12.000 Max. :6.000
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 : 122.0 Median : 1.000 Median : 3.000
Mean : 433.4 Mean : 174.2 Mean : 1.676 Mean : 3.124
3rd Qu.: 540.0 3rd Qu.: 227.0 3rd Qu.: 2.000 3rd Qu.: 4.000
Max. :1999.0 Max. :1745.0 Max. :10.000 Max. :10.000
habitaciones tipo barrio longitud
Min. : 1.000 Length:8253 Length:8253 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.634 Mean :-76.53
3rd Qu.: 4.000 3rd Qu.:-76.52
Max. :10.000 Max. :-76.46
latitud
Min. :3.333
1st Qu.:3.381
Median :3.416
Mean :3.418
3rd Qu.:3.452
Max. :3.498
1.3 Filtrado por tipo de vivienda y Zona:
Filtramos del dataset por tipo de vivienda = Casa y Zona = Zona Norte.
# Filtrar base de datos
library(dplyr)
base1 <- vivienda %>% filter(tipo == "Casa", zona == "Zona Norte")
head(base1, 3)
id zona piso estrato preciom areaconst parqueaderos banios
1 1209 Zona Norte 2 5 320 150 2 4
2 1592 Zona Norte 2 5 780 380 2 3
3 4057 Zona Norte 2 6 750 445 1 7
habitaciones tipo barrio longitud latitud
1 6 Casa acopi -76.51341 3.47968
2 3 Casa acopi -76.51674 3.48721
3 6 Casa acopi -76.52950 3.38527
1.4 Generación del mapa para Casas de la Zona Norte:
Con el fin de determinar las zonas de la ciudad de Cali, se buscó en la página de la Alcaldía de Cali la distribución geografica de las Zonas, se encontro en el sitio web: https://datos.cali.gov.co/es/dataset/servicio-wms-comunas-de-cali/resource/98aabf95-b972-4677-a215-474a33a78eb5 los zonas correspondientes a las comunas, se descarga el archivo tipo Sh (Shapefile) el cual tiene los poligonos correspondientes a las comunas, identificandose las comunas, en base a las comunas se determinan y definen las zonas.
library(sf)
library(leaflet)
library(dplyr)
# Leer el shapefile y transformar a WGS84
comunas <- st_read("C:/Users/ORAM/Desktop/mc_comunas/mc_comunas.shp") %>%
st_transform(crs = 4326)
Reading layer `mc_comunas' from data source
`C:\Users\ORAM\Desktop\mc_comunas\mc_comunas.shp' using driver `ESRI Shapefile'
Simple feature collection with 22 features and 4 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 1054753 ymin: 860192.1 xmax: 1068492 ymax: 879441.5
Projected CRS: MAGNA-SIRGAS / Cali urban grid
# Asignar zonas según el valor de la columna 'comuna'
comunas <- comunas %>%
mutate(Zona = case_when(
comuna %in% c(2, 4, 5, 6) ~ "Zona Norte",
comuna %in% c(7, 13, 14, 15, 16, 21) ~ "Zona Oriente",
comuna %in% c(22, 17) ~ "Zona Sur",
comuna %in% c(18, 19, 20) ~ "Zona Oeste",
comuna %in% c(3, 9, 10, 11, 12, 8) ~ "Zona Centro",
TRUE ~ NA_character_
)) %>%
filter(!is.na(Zona)) # Conserva solo las comunas con zona definida
# Crear una paleta de colores para las zonas
pal <- colorFactor(
palette = c("blue", "red", "green", "orange", "purple"),
domain = comunas$Zona
)
# Crear el mapa base con los polígonos de comunas y leyenda
m <- leaflet(comunas) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(Zona),
fillOpacity = 0.5,
color = "black",
weight = 1,
popup = ~paste("Comuna:", comuna, "<br>Zona:", Zona)
) %>%
addLegend("bottomright", pal = pal, values = ~Zona, title = "Zonas")
# Agregar los puntos de base1
m <- m %>%
addCircleMarkers(
data = base1,
lng = ~longitud,
lat = ~latitud,
color = "black",
fillColor = ~pal(zona),
fillOpacity = 1,
radius = 5,
popup = ~paste("Zona:", zona)
)
# Visualizar el mapa
m
1.5 Analisis datos geograficos para Casas de la Zona Norte:
Se observa que algunos los puntos en color rojo (Zona Norte) en el dataset se encuentran mal clasificados ya que se observan puntos etiquetados y no corresponden a la Zona Norte, por lo tanto se procede a realizar una reclasificación geográfica en base a las Zonas reales definidas por los archivos shapefile de la Alcaldía de Cali.
# Leer el shapefile y transformarlo a WGS84
comunas <- st_read("C:/Users/ORAM/Desktop/mc_comunas/mc_comunas.shp") %>%
st_transform(crs = 4326)
Reading layer `mc_comunas' from data source
`C:\Users\ORAM\Desktop\mc_comunas\mc_comunas.shp' using driver `ESRI Shapefile'
Simple feature collection with 22 features and 4 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 1054753 ymin: 860192.1 xmax: 1068492 ymax: 879441.5
Projected CRS: MAGNA-SIRGAS / Cali urban grid
# Asignar la zona a cada comuna según su valor
comunas <- comunas %>%
mutate(Zona = case_when(
comuna %in% c(2, 4, 5, 6) ~ "Zona Norte",
comuna %in% c(7, 13, 14, 15, 16, 21) ~ "Zona Oriente",
comuna %in% c(22, 17) ~ "Zona Sur",
comuna %in% c(18, 19, 20) ~ "Zona Oeste",
comuna %in% c(3, 9, 10, 11, 12, 8) ~ "Zona Centro",
TRUE ~ NA_character_
)) %>%
filter(!is.na(Zona)) # Se conservan solo las comunas con zona definida
# Crear una paleta de colores para las zonas
pal <- colorFactor(
palette = c("blue", "red", "green", "orange", "purple"),
domain = comunas$Zona
)
# Convertir base1 en objeto espacial (sf)
base1_sf <- st_as_sf(base1, coords = c("longitud", "latitud"), crs = 4326)
# Realizar join espacial con comunas para asignar la zona correcta a cada punto
base2 <- st_join(base1_sf, comunas[, "Zona"], left = TRUE)
# Actualizar (reclasificar) el atributo 'zona' con la zona determinada geográficamente
base2 <- base2 %>%
mutate(zona = Zona) %>% # asigna la zona correcta
select(-Zona) # elimina la columna redundante
# Extraer coordenadas en columnas para facilitar la visualización en leaflet
base2 <- base2 %>%
mutate(longitud = st_coordinates(geometry)[,1],
latitud = st_coordinates(geometry)[,2])
# Crear el mapa base con los polígonos de comunas y leyenda
m <- leaflet(comunas) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(Zona),
fillOpacity = 0.5,
color = "black",
weight = 1,
popup = ~paste("Comuna:", comuna, "<br>Zona:", Zona)
) %>%
addLegend("bottomright", pal = pal, values = ~Zona, title = "Zonas")
# Agregar los puntos de base2 ya reclasificados, utilizando el color correspondiente a cada zona
m <- m %>%
addCircleMarkers(
data = base2,
lng = ~longitud,
lat = ~latitud,
color = "black",
fillColor = ~pal(zona),
fillOpacity = 1,
radius = 5,
popup = ~paste("Zona:", zona)
)
# Visualizar el mapa
m
1.6 Filtramos nuevamente por Casa y Zona Norte:
base3 <- base2 %>% filter(tipo == "Casa", zona == "Zona Norte")
library(sf)
library(leaflet)
library(dplyr)
# Leer el shapefile y transformar a WGS84
comunas <- st_read("C:/Users/ORAM/Desktop/mc_comunas/mc_comunas.shp") %>%
st_transform(crs = 4326)
Reading layer `mc_comunas' from data source
`C:\Users\ORAM\Desktop\mc_comunas\mc_comunas.shp' using driver `ESRI Shapefile'
Simple feature collection with 22 features and 4 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 1054753 ymin: 860192.1 xmax: 1068492 ymax: 879441.5
Projected CRS: MAGNA-SIRGAS / Cali urban grid
# Asignar zonas según el valor de la columna 'comuna'
comunas <- comunas %>%
mutate(Zona = case_when(
comuna %in% c(2, 4, 5, 6) ~ "Zona Norte",
comuna %in% c(7, 13, 14, 15, 16, 21) ~ "Zona Oriente",
comuna %in% c(22, 17) ~ "Zona Sur",
comuna %in% c(18, 19, 20) ~ "Zona Oeste",
comuna %in% c(3, 9, 10, 11, 12, 8) ~ "Zona Centro",
TRUE ~ NA_character_
)) %>%
filter(!is.na(Zona)) # Conserva solo las comunas con zona definida
# Crear una paleta de colores para las zonas
pal <- colorFactor(
palette = c("blue", "red", "green", "orange", "purple"),
domain = comunas$Zona
)
# Crear el mapa base con los polígonos de comunas y leyenda
m <- leaflet(comunas) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(Zona),
fillOpacity = 0.5,
color = "black",
weight = 1,
popup = ~paste("Comuna:", comuna, "<br>Zona:", Zona)
) %>%
addLegend("bottomright", pal = pal, values = ~Zona, title = "Zonas")
# Agregar los puntos de base3
m <- m %>%
addCircleMarkers(
data = base3,
lng = ~longitud,
lat = ~latitud,
color = "black",
fillColor = ~pal(zona),
fillOpacity = 1,
radius = 5,
popup = ~paste("Zona:", zona)
)
# Visualizar el mapa
m
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.
2.1 Matriz de correlaciòn de las variables
Realizamos exploración de las variables
library(ggplot2)
library(plotly)
library(dplyr)
library(corrplot)
head(base3)
Simple feature collection with 6 features and 13 fields
Geometry type: POINT
Dimension: XY
Bounding box: xmin: -76.51797 ymin: 3.46284 xmax: -76.49768 ymax: 3.48721
Geodetic CRS: WGS 84
id zona piso estrato preciom areaconst parqueaderos banios
1 1209 Zona Norte 2 5 320 150 2 4
2 1592 Zona Norte 2 5 780 380 2 3
3 504 Zona Norte 1 3 180 120 1 3
4 604 Zona Norte 1 5 520 455 1 5
5 1003 Zona Norte 1 3 380 300 1 5
6 1840 Zona Norte 1 5 395 165 1 4
habitaciones tipo barrio geometry longitud latitud
1 6 Casa acopi POINT (-76.51341 3.47968) -76.51341 3.47968
2 3 Casa acopi POINT (-76.51674 3.48721) -76.51674 3.48721
3 3 Casa acopi POINT (-76.49768 3.4706) -76.49768 3.47060
4 4 Casa acopi POINT (-76.49966 3.46284) -76.49966 3.46284
5 8 Casa acopi POINT (-76.50743 3.46566) -76.50743 3.46566
6 4 Casa acopi POINT (-76.51797 3.47651) -76.51797 3.47651
summary(base3)
id zona piso estrato
Min. : 88 Length:522 Min. :1.00 Min. :3.000
1st Qu.: 620 Class :character 1st Qu.:1.00 1st Qu.:3.000
Median :1412 Mode :character Median :1.00 Median :4.000
Mean :2033 Mean :1.55 Mean :4.192
3rd Qu.:3222 3rd Qu.:2.00 3rd Qu.:5.000
Max. :7226 Max. :4.00 Max. :6.000
preciom areaconst parqueaderos banios
Min. : 110.0 Min. : 30.0 Min. : 1.000 Min. : 0.000
1st Qu.: 240.8 1st Qu.: 135.0 1st Qu.: 1.000 1st Qu.: 2.000
Median : 375.0 Median : 233.0 Median : 1.000 Median : 3.000
Mean : 422.2 Mean : 254.6 Mean : 1.828 Mean : 3.525
3rd Qu.: 530.0 3rd Qu.: 333.8 3rd Qu.: 2.000 3rd Qu.: 4.000
Max. :1800.0 Max. :1440.0 Max. :10.000 Max. :10.000
habitaciones tipo barrio geometry
Min. : 2.00 Length:522 Length:522 POINT :522
1st Qu.: 3.00 Class :character Class :character epsg:4326 : 0
Median : 4.00 Mode :character Mode :character +proj=long...: 0
Mean : 4.63
3rd Qu.: 5.00
Max. :10.00
longitud latitud
Min. :-76.55 Min. :3.453
1st Qu.:-76.52 1st Qu.:3.468
Median :-76.52 Median :3.476
Mean :-76.51 Mean :3.476
3rd Qu.:-76.50 3rd Qu.:3.484
Max. :-76.48 Max. :3.496
col_var <- c("preciom", "areaconst", "estrato", "parqueaderos","banios","habitaciones")
num_vars1 <- base3[, intersect(names(base3), col_var)]
library(sf)
# Elimina la columna de geometría y convierte a data.frame
num_vars <- st_drop_geometry(num_vars1)
# Selecciona solo las columnas deseadas
num_vars <- num_vars[, c( "preciom","areaconst","estrato", "parqueaderos", "banios", "habitaciones")]
cor_matrix <- cor(num_vars, use = "complete.obs")
# Visualizar la matriz de correlación
corrplot(cor_matrix, method = "color", addCoef.col = "black", tl.cex = 0.8)
2.2 Relaciòn entre el Precio y el Area construida
p1 <- ggplot(base3, aes(x = areaconst, y = preciom)) +
geom_point(alpha = 0.5, color = "blue") +
labs(title = "Relación Precio y Área Construida",
x = "Área Construida (m²)", y = "Precio (millones)") +
theme_minimal()
ggplotly(p1)
Existe una relación positiva debil de 0,74, puede evidenciarse en el
gráfico que a mayor área construida mayor es el precio.
2.3 Relaciòn Precio y el Estrato
p2 <- ggplot(base3, aes(x = factor(estrato), y = preciom)) +
geom_boxplot(fill = "purple") +
labs(title = "Distribución del Precio por Estrato",
x = "Estrato", y = "Precio (millones)") +
theme_minimal()
ggplotly(p2)
Existe una relación positiva debil de 0,61, puede evidenciarse en el
gráfico que a mayor es el estrato mayor es el precio.
2.4 Realaciòn entre el Precio y el nùmero de parqueaderos
p3 <- ggplot(base3, aes(x = factor(parqueaderos), y = preciom)) +
geom_boxplot(fill = "lightgreen") +
labs(title = "Relación Precio por Número de Parqueaderos",
x = "Número de Parqueaderos", y = "Precio (millones)") +
theme_minimal()
ggplotly(p3)
Existe una relación positiva debil de 0,43, puede evidenciarse en el
gráfico que a mayor es el número de parqueaderos mayor es el
precio.
2.5 Relaciòn Precio y el Número de baños
p4 <- ggplot(base3, aes(x = factor(banios), y = preciom)) +
geom_boxplot(fill = "lightcoral") +
labs(title = "Relación Precio por Número de Baños",
x = "Número de Baños", y = "Precio (millones)") +
theme_minimal()
ggplotly(p4)
Existe una relación positiva debil de 0,55, puede evidenciarse en el
gráfico que a mayor es el número de baños mayor es el precio.
2.6 Relaciòn Precio y el Número de habitaciones
p5 <- ggplot(base3, aes(x = factor(habitaciones), y = preciom)) +
geom_boxplot(fill = "orange") +
labs(title = "Relación Precio por Número de Habitaciones",
x = "Número de Habitaciones", y = "Precio (millones)") +
theme_minimal()
ggplotly(p5)
Existe una relación positiva debil de 0,42, puede evidenciarse en el
gráfico que a mayor es el número de habitaciones mayor es el
precio.
Estime un modelo de regresión lineal múltiple con las variables del
punto anterior (precio = f(área construida, estrato, número de cuartos,
número de parqueaderos, número de baños ) ) e interprete los
coeficientes si son estadísticamente significativos. Las
interpretaciones deber están contextualizadas y discutir si los
resultados son lógicos. Adicionalmente interprete el coeficiente R2 y
discuta el ajuste del modelo e implicaciones (que podrían hacer para
mejorarlo).
Con el fin de evaluar el impacto de las variables en el modelo se
aplicará la técnica de eliminación hacia atrás en donde evaluaremos el
P-valor y el R2 de los modelos.
Modelo 1: Implementación con todas las variables
modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = base3)
# Resumen del modelo
summary(modelo1)
Call:
lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
banios, data = base3)
Residuals:
Min 1Q Median 3Q Max
-888.17 -63.76 -16.13 34.36 1107.19
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -204.71275 34.86450 -5.872 7.73e-09 ***
areaconst 0.74557 0.05323 14.008 < 2e-16 ***
estrato 73.67848 8.48534 8.683 < 2e-16 ***
habitaciones 8.99057 5.18120 1.735 0.08330 .
parqueaderos 18.60321 5.46768 3.402 0.00072 ***
banios 14.92826 6.49415 2.299 0.02192 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 146.8 on 516 degrees of freedom
Multiple R-squared: 0.6528, Adjusted R-squared: 0.6495
F-statistic: 194.1 on 5 and 516 DF, p-value: < 2.2e-16
Observamos que el P-Valor de la variable habitaciones supera el 5%,
luego procedemos a eliminarla ya que no es estadisticamente
significativa, calculamos el siguiente modelo:
Modelo 2: Implementación eliminando la variable habitaciones
modelo2 <- lm(preciom ~ areaconst + estrato + parqueaderos + banios, data = base3)
# Resumen del modelo
summary(modelo2)
Call:
lm(formula = preciom ~ areaconst + estrato + parqueaderos + banios,
data = base3)
Residuals:
Min 1Q Median 3Q Max
-883.88 -64.45 -16.97 36.74 1123.30
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -173.61668 29.96450 -5.794 1.19e-08 ***
areaconst 0.77615 0.05032 15.423 < 2e-16 ***
estrato 69.35294 8.12668 8.534 < 2e-16 ***
parqueaderos 18.81243 5.47697 3.435 0.000641 ***
banios 20.74336 5.57350 3.722 0.000220 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 147.1 on 517 degrees of freedom
Multiple R-squared: 0.6508, Adjusted R-squared: 0.6481
F-statistic: 240.9 on 4 and 517 DF, p-value: < 2.2e-16
Observamos que el P-valor para areaconst, estrato, parqueaderos,
banios son significativas, el R2 ajustado paso de 64,95% a 64,81% lo
cual indica que eliminar la variable habitaciones redujo una cantidad
mínima la capacidad explicativa del modelo.
a continuación evaluaremos el R2 ajustado para modeos transformados:
Modelo 3: Transformación logaritmica
modelo_log <- lm(log(preciom) ~ log(areaconst) + estrato + parqueaderos + banios, data = base3)
summary(modelo_log)
Call:
lm(formula = log(preciom) ~ log(areaconst) + estrato + parqueaderos +
banios, data = base3)
Residuals:
Min 1Q Median 3Q Max
-0.72796 -0.16071 -0.01485 0.14577 1.11496
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.274141 0.105591 21.537 < 2e-16 ***
log(areaconst) 0.496238 0.025709 19.302 < 2e-16 ***
estrato 0.167807 0.015038 11.159 < 2e-16 ***
parqueaderos 0.033123 0.009553 3.467 0.000569 ***
banios 0.055483 0.009920 5.593 3.62e-08 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.2562 on 517 degrees of freedom
Multiple R-squared: 0.7918, Adjusted R-squared: 0.7902
F-statistic: 491.7 on 4 and 517 DF, p-value: < 2.2e-16
Modelo 4: Transformación cuadratica
modelo_quad <- lm(preciom ~ areaconst + I(areaconst^2) + estrato + parqueaderos + banios, data = base3)
summary(modelo_quad)
Call:
lm(formula = preciom ~ areaconst + I(areaconst^2) + estrato +
parqueaderos + banios, data = base3)
Residuals:
Min 1Q Median 3Q Max
-388.49 -69.40 -13.09 41.41 1076.67
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.715e+02 2.903e+01 -5.907 6.34e-09 ***
areaconst 1.402e+00 1.164e-01 12.040 < 2e-16 ***
I(areaconst^2) -6.340e-04 1.071e-04 -5.918 5.95e-09 ***
estrato 5.151e+01 8.429e+00 6.111 1.95e-09 ***
parqueaderos 1.656e+01 5.319e+00 3.113 0.00195 **
banios 1.371e+01 5.528e+00 2.480 0.01346 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 142.5 on 516 degrees of freedom
Multiple R-squared: 0.673, Adjusted R-squared: 0.6698
F-statistic: 212.4 on 5 and 516 DF, p-value: < 2.2e-16
Modelo 5: Transformación raiz-cuadrada
modelo_sqrt <- lm(sqrt(preciom) ~ sqrt(areaconst) + estrato + parqueaderos + banios, data = base3)
summary(modelo_sqrt)
Call:
lm(formula = sqrt(preciom) ~ sqrt(areaconst) + estrato + parqueaderos +
banios, data = base3)
Residuals:
Min 1Q Median 3Q Max
-13.2407 -1.4939 -0.3028 1.1703 16.9603
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.69646 0.56780 1.227 0.22054
sqrt(areaconst) 0.64789 0.03602 17.986 < 2e-16 ***
estrato 1.61346 0.16112 10.014 < 2e-16 ***
parqueaderos 0.38108 0.10494 3.632 0.00031 ***
banios 0.49308 0.10847 4.546 6.82e-06 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 2.815 on 517 degrees of freedom
Multiple R-squared: 0.7472, Adjusted R-squared: 0.7453
F-statistic: 382.1 on 4 and 517 DF, p-value: < 2.2e-16
Conclusión modelos transformados:
En base al R2 ajustado se determinó que el modelo logaritmico (modelo
5) es el que presenta un R2 ajustado del 79.02% siendo superior al
modelo 1 en el cual se empleaban todos los atributos, por lo tanto el
modelo 2 es posible mejorarlo haciendo esta transformación.
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).
4.1 Normalidad de los residuos
A continuación evaluaremos los supuestos para el modelo 2:
modelo2 <- lm(preciom ~ areaconst + estrato + parqueaderos + banios, data = base3)
# Histograma de residuos
hist(modelo2$residuals, main = "Histograma de residuos", xlab = "Residuos", col = "lightblue")
# Gráfico Q-Q
qqnorm(modelo2$residuals, main = "Gráfico Q-Q de residuos")
qqline(modelo2$residuals, col = "red")
Este supuesto indica que los residuos (errores) deben seguir una
distribución normal,Esto es fundamental para la validez de los
intervalos de confianza y pruebas de hipótesis sobre los coeficientes,
los puntos e alinean aproximadamente a una linea recta por lo tanto
la hipótesis se cumple.
4.2 Homocedasticidad
# Gráfico de residuos vs valores ajustados
plot(modelo2$fitted.values, modelo2$residuals,
main = "Residuos vs Valores ajustados",
xlab = "Valores ajustados",
ylab = "Residuos",
pch = 20, col = "blue")
abline(h = 0, col = "red", lwd = 2)
La homocedasticidad significa que la varianza de los errores es
constante a lo largo de todos los niveles de las variables
independientes, si la dispersión varía (heterocedasticidad), los
estimadores pueden ser ineficientes y los intervalos de confianza pueden
estar sesgados, los residuos se distribuyen aleatoriamente al rededor de
cero, por lo tanto la hipótesis se cumple.
4.3 No autocorrelación
# Gráfico de residuos a lo largo del orden de las observaciones
plot(modelo2$residuals, type = "l",
main = "Residuos en orden de observaciones",
xlab = "Índice de observación",
ylab = "Residuos")
# Test de Durbin-Watson
library(lmtest)
dwtest_result <- dwtest(modelo2)
print(dwtest_result)
Durbin-Watson test
data: modelo2
DW = 1.8281, p-value = 0.02201
alternative hypothesis: true autocorrelation is greater than 0
Los errores deben ser independientes entre sí. La
autocorrelación ocurre, por ejemplo, en datos de series temporales,
cuando el error de una observación está correlacionado con el error de
otra. La presencia de autocorrelación puede invalidar las inferencias
del modelo.
El test de Durbin-Watson tiene como hipótesis nula que no existe
autocorrelación de primer orden en los residuos. Un valor de DW igual a
2 indicaría ausencia de autocorrelación, mientras que valores menores a
2 sugieren autocorrelación positiva.
En este caso, DW = 1.8281 se acerca a 2, pero lo importante es el
p-value. Al ser p-value (0.02201) menor que el nivel de significancia
típico de 0.05, se rechaza la hipótesis nula. Esto indica evidencia
estadísticamente significativa de que existe autocorrelación positiva en
los residuos, por lo tanto la hipótesis no se
cumple.
4.4 Multicolinealidad
# Matriz de dispersión para las variables predictoras
pairs(num_vars[, c("areaconst", "estrato", "parqueaderos", "banios")],
main = "Scatterplot Matrix de variables predictoras")
# Matriz de correlación
cor_matrix <- cor(num_vars[, c("areaconst", "estrato", "parqueaderos", "banios")])
print(cor_matrix)
areaconst estrato parqueaderos banios
areaconst 1.0000000 0.5037465 0.3540357 0.5269484
estrato 0.5037465 1.0000000 0.3675210 0.4376173
parqueaderos 0.3540357 0.3675210 1.0000000 0.3979139
banios 0.5269484 0.4376173 0.3979139 1.0000000
# Calcular VIF
library(car)
vif_values <- vif(modelo2)
print(vif_values)
areaconst estrato parqueaderos banios
1.607215 1.467350 1.273080 1.541828
La multicolinealidad se presenta cuando dos o más variables
independientes están altamente correlacionadas entre sí, lo que puede
dificultar la estimación precisa de los coeficientes y aumentar la
varianza de los estimadores.
La multicolinealidad se evalúa tanto mediante la matriz de
correlación como con el Factor de Inflación de la Varianza
(VIF).
Matriz de correlación: Los valores entre las variables predictoras
son moderados (alrededor de 0.35 a 0.53), lo cual sugiere que si bien
existe cierta relación, no es tan alta como para generar problemas
graves en la estimación.
VIF: Los valores de VIF son todos inferiores a 2, y generalmente se
considera que un VIF mayor a 5 (o en algunos contextos mayor a 10)
indicaría un problema serio de multicolinealidad. En este caso, los VIF
bajos indican que la varianza de los coeficientes no se ve excesivamente
inflada por correlaciones entre las variables, por lo tanto la
hipotesis se cumple.
Con el modelo identificado debe predecir el precio de la vivienda con
las características de la primera solicitud.
Debido a que el modelo 2 no cumplió con el supuesto de la no
autocorrelación, empleamos el modelo 5 (modelo logaritmico) el cual
obtuvo un mayor R2 ajustado.
Para una casa con 200 m2, estrato = 4, parqueaderos =1 y baños =
2:
nuevo <- data.frame(areaconst = 200,
estrato = 4,
parqueaderos = 1,
banios = 2)
# Realiza la predicción en escala logarítmica
pred_log <- predict(modelo_log, newdata = nuevo)
# Transforma la predicción a la escala original
prediccion <- exp(pred_log)
prediccion
1
304.5045
Para una casa con 200 m2, estrato = 5, parqueaderos = 1 y baños =
2:
nuevo <- data.frame(areaconst = 200,
estrato = 5,
parqueaderos = 1,
banios = 2)
# Realiza la predicción en escala logarítmica
pred_log <- predict(modelo_log, newdata = nuevo)
# Transforma la predicción a la escala original
prediccion <- exp(pred_log)
prediccion
1
360.1401
Conclusiones prediccion del modelo
Con la información entregada se tiene como primera opción una casa
con un costo de 304.5 millones de pesos lo cual está dentro del credito
aprobado, como segundaopción se tiene 360.14 millones de pesos en
estrato 5 sin embrago supera el valor del crédito establecido.
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 350 millones de pesos. Realice un
análisis y presente en un mapa al menos 5 ofertas potenciales que debe
discutir.
# Aplicar los filtros solicitados
base4= base3
base4$geometry <- NULL # Opción 1
base4 <- subset(base4,
preciom <= 350 &
estrato >= 4 &
areaconst >= 200 &
parqueaderos >= 1 &
banios >= 2 &
habitaciones >= 4)
6.1 Visualizacion alternativas de compra
Se presentan 31 alternativas de compra, se procede a ordenar de mayor
a menor precio.
library(DT)
datatable(base4)
library(sf)
library(leaflet)
library(dplyr)
# Leer el shapefile y transformar a WGS84
comunas <- st_read("C:/Users/ORAM/Desktop/mc_comunas/mc_comunas.shp") %>%
st_transform(crs = 4326)
Reading layer `mc_comunas' from data source
`C:\Users\ORAM\Desktop\mc_comunas\mc_comunas.shp' using driver `ESRI Shapefile'
Simple feature collection with 22 features and 4 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 1054753 ymin: 860192.1 xmax: 1068492 ymax: 879441.5
Projected CRS: MAGNA-SIRGAS / Cali urban grid
# Asignar zonas según el valor de la columna 'comuna'
comunas <- comunas %>%
mutate(Zona = case_when(
comuna %in% c(2, 4, 5, 6) ~ "Zona Norte",
comuna %in% c(7, 13, 14, 15, 16, 21) ~ "Zona Oriente",
comuna %in% c(22, 17) ~ "Zona Sur",
comuna %in% c(18, 19, 20) ~ "Zona Oeste",
comuna %in% c(3, 9, 10, 11, 12, 8) ~ "Zona Centro",
TRUE ~ NA_character_
)) %>%
filter(!is.na(Zona)) # Conserva solo las comunas con zona definida
# Crear una paleta de colores para las zonas
pal <- colorFactor(
palette = c("blue", "red", "green", "orange", "purple"),
domain = comunas$Zona
)
# Crear el mapa base con los polígonos de comunas y leyenda
m <- leaflet(comunas) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(Zona),
fillOpacity = 0.5,
color = "black",
weight = 1,
popup = ~paste("Comuna:", comuna, "<br>Zona:", Zona)
) %>%
addLegend("bottomright", pal = pal, values = ~Zona, title = "Zonas")
# Agregar los puntos de base4
# Crear popup con detalles de cada propiedad
popup_info <- ~paste0(
"<b>ID:</b> ", id, "<br>",
"<b>Barrio:</b> ", barrio, "<br>",
"<b>Estrato:</b> ", estrato, "<br>",
"<b>Precio:</b> ", format(preciom, big.mark = ","), " Millones COP<br>",
"<b>Área Construida:</b> ", areaconst, " m²<br>",
"<b>Piso:</b> ", piso, "<br>",
"<b>Parqueaderos:</b> ", parqueaderos, "<br>",
"<b>Baños:</b> ", banios, "<br>",
"<b>Habitaciones:</b> ", habitaciones, "<br>",
"<b>Zona:</b> ", zona
)
# Agregar los puntos con ID y detalles en el popup
m <- m %>%
addCircleMarkers(
data = base4,
lng = ~longitud,
lat = ~latitud,
color = "black",
fillColor = ~pal(zona),
fillOpacity = 1,
radius = 5,
popup = popup_info, # Popup con toda la info
label = ~as.character(id), # Muestra el ID como etiqueta visible
labelOptions = labelOptions(
noHide = TRUE, # Hace que la etiqueta siempre sea visible
direction = "top",
textOnly = TRUE,
style = list(
"color" = "black",
"font-weight" = "bold",
"font-size" = "12px"
)
)
)
# Visualizar el mapa
m
En el mapa interactivo se presentan las 31 alternativas presentes, al
dar click en el punto se puede mostrar información complemetaria como es
el id, el precio, el barrio, el estrato, el número de parqueaderos, el
número de habitaciones, lo cual facilita la negociación a los asesores.