Maria comenzó como agente de bienes raíces en Cali hace 10 años. Después de laborar dos años para una empresa nacional, se traslado a Bogotá y trabajó para otra agencia de bienes raíces. Sus amigos y familiares la convencieron de que con su experiencia y conocimientos del negocio debía abrir su propia agencia. Terminó por adquirir la licencia de intermediario y al poco tiempo fundó su propia compañía, C&A (Casas y Apartamentos) en Cali. Santiago y Lina, dos vendedores de la empresa anterior aceptaron trabajar en la nueva compaña. En la actualidad ocho agentes de bienes raíces colaboran con ella en C&A.
Actualmente las ventas de bienes raíces en Cali se han visto disminuidas de manera significativa en lo corrido del año. Durante este periodo muchas instituciones bancarias de ahorro y vivienda están prestando grandes sumas de dinero para la industria y la construcción comercial y residencial. Cuando el efecto producto de las tensiones políticas y sociales disminuya, se espera que la actividad económica de este sector se reactive.
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:
Características Vivienda 1 - Vivienda 2
Tipo Casa - Apartamento
área construida 200 - 300
parqueaderos 1 - 3
baños 2 - 3
habitaciones 4 - 5
estrato 4 o 5 - 5 o 6
zona Norte - Sur
crédito preaprobado 350 millones - 850 millones
-Carga de los datos y Caracteristicas de los datos.
# Ver las primeras filas del dataset
head(vivienda)
# Ver resumen de cada columna
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
# Ver estructura del dataset
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>
-Tratamiento de NA.
# Ver la cantidad de valores NA en cada columna
colSums(is.na(vivienda))
## id zona piso estrato preciom areaconst
## 3 3 2638 3 2 3
## parqueaderos banios habitaciones tipo barrio longitud
## 1605 3 3 3 3 3
## latitud
## 3
missing_rows_column <- which(is.na(vivienda$zona))
vivienda[missing_rows_column, ]
viviendaR = vivienda ####se hace una copia de la base de datos
# 1. Eliminar filas con valores faltantes
viviendaR <- subset(viviendaR, !is.na(zona))
missing_rows_column <- which(is.na(viviendaR$zona))
viviendaR[missing_rows_column, ]
# Ver la cantidad de valores NA en cada columna
colSums(is.na(viviendaR))
## id zona piso estrato preciom areaconst
## 0 0 2635 0 0 0
## parqueaderos banios habitaciones tipo barrio longitud
## 1602 0 0 0 0 0
## latitud
## 0
unique(viviendaR$piso)
## [1] NA "02" "01" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12"
unique(viviendaR$parqueaderos)
## [1] 1 2 3 NA 4 7 5 8 6 9 10
# Función para calcular la moda sin considerar NA
get_mode <- function(x) {
x <- na.omit(x) # Elimina los NA
ux <- unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
# Calcular la moda para el campo 'piso'
moda_piso <- get_mode(viviendaR$piso)
# Calcular la moda para el campo 'baños'
moda_parqueaderos <- get_mode(viviendaR$parqueaderos)
# Reemplazar los valores NA con la moda en 'piso'
viviendaR$piso <- ifelse(is.na(viviendaR$piso), moda_piso, viviendaR$piso)
# Reemplazar los valores NA con la moda en 'parqueaderos'
viviendaR$parqueaderos <- ifelse(is.na(viviendaR$parqueaderos), moda_parqueaderos, viviendaR$parqueaderos)
# Ver la cantidad de valores NA en cada columna
colSums(is.na(viviendaR))
## id zona piso estrato preciom areaconst
## 0 0 0 0 0 0
## parqueaderos banios habitaciones tipo barrio longitud
## 0 0 0 0 0 0
## latitud
## 0
-Analisis de valores unicos para las demas columnas.
#analizamos los valores unicos para cada columna, validar ajustes extras antes de analisis completo
cat ("Los valores únicos en zona son:", unique(viviendaR$zona), "\n")
## Los valores únicos en zona son: Zona Oriente Zona Sur Zona Norte Zona Oeste Zona Centro
cat ("Los valores únicos en zona son:", unique(viviendaR$piso), "\n")
## Los valores únicos en zona son: 02 01 03 04 05 06 07 08 09 10 11 12
cat ("Los valores únicos en zona son:", unique(viviendaR$estrato), "\n")
## Los valores únicos en zona son: 3 4 5 6
cat ("Los valores únicos en zona son:", unique(viviendaR$parqueaderos), "\n")
## Los valores únicos en zona son: 1 2 3 4 7 5 8 6 9 10
cat ("Los valores únicos en zona son:", unique(viviendaR$banios), "\n")
## Los valores únicos en zona son: 3 2 5 4 7 6 1 0 8 10 9
cat ("Los valores únicos en zona son:", unique(viviendaR$habitaciones), "\n")
## Los valores únicos en zona son: 6 3 4 5 2 0 1 8 7 10 9
cat ("Los valores únicos en zona son:", unique(viviendaR$tipo), "\n")
## Los valores únicos en zona son: Casa Apartamento
-Convertimos las variables piso y estrato a numerico y categorico respectivamente.
# Convertir 'piso' a numérico
viviendaR$piso <- as.numeric(viviendaR$piso)
# Convierte el campo 'estrato' de numérico a categórico
viviendaR$estrato <- as.factor(viviendaR$estrato)
# Verifica la conversión
str(viviendaR$estrato)
## Factor w/ 4 levels "3","4","5","6": 1 1 1 2 3 3 2 3 3 3 ...
# Verificar la conversión
summary(viviendaR$piso)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 2.00 2.00 3.21 4.00 12.00
str(viviendaR$piso)
## num [1:8319] 2 2 2 2 1 1 1 1 2 2 ...
-Ahora verificamos la columna longitud y latitud si todos los separadores son puntos o comas.
# Verifica si hay algún valor que contenga una coma
latitud_con_coma <- any(grepl(",", vivienda$latitud))
longitud_con_coma <- any(grepl(",", vivienda$longitud))
# Muestra los resultados
if (latitud_con_coma | longitud_con_coma) {
cat("Existen valores en latitud y/o longitud con comas en lugar de puntos.\n")
} else {
cat("Todos los valores en latitud y longitud están correctamente separados por puntos.\n")
}
## Todos los valores en latitud y longitud están correctamente separados por puntos.
Se realiza preparacion de la data, ahora estamos preparados para empezar a trabajar la base de datos ya arreglada.
-Se filtra la base de datos por la zona Norte y tipo casa.
# Filtra la base de datos para incluir solo casas en la zona norte
viviendaR1 <- subset(viviendaR, tipo == "Casa" & zona == "Zona Norte")
# Muestra los primeros 3 registros de la base filtrada
head(viviendaR1, 3)
# Tabla de frecuencia para 'tipo_vivienda'
table(viviendaR1$tipo)
##
## Casa
## 722
# Tabla de frecuencia para 'zona'
table(viviendaR1$zona)
##
## Zona Norte
## 722
# Convertir la variable 'estrato' en factor para la visualización
viviendaR1$estrato <- as.factor(viviendaR1$estrato)
fig1 <- plot_ly(viviendaR1, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(color = 'rgba(255, 182, 193, .9)', size = 10),
text = ~paste('Precio:', preciom, '<br>Área Construida:', areaconst)) %>%
layout(title = "Precio vs Área Construida",
xaxis = list(title = "Área Construida"),
yaxis = list(title = "Precio"))
fig1
Se evidencia una concordancia en la teoria, porque a mayor area construida mas vale la vivienda, teniendo datos atipicos pero no necesariamente son erroneos, ya que son precios no establecidos por la misma persona.
# Crear un gráfico interactivo para 'precio' vs 'estrato'
fig2 <- plot_ly(viviendaR1, x = ~estrato, y = ~preciom, type = 'box',
boxmean = "sd") %>%
layout(title = "Precio por Estrato",
xaxis = list(title = "Estrato"),
yaxis = list(title = "Precio"))
fig2
Aca se evidencia una distribución de mayor estrato mayor es el precio de la vivienda, y que se tienen datos acordes entre si.
# Crear un gráfico interactivo para 'precio' vs 'número de baños'
fig3 <- plot_ly(viviendaR1, x = ~banios, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(color = 'rgba(255, 182, 193, .9)', size = 10),
text = ~paste('Precio:', preciom, '<br>Baños:', banios)) %>%
layout(title = "Precio vs Número de Baños",
xaxis = list(title = "Número de Baños"),
yaxis = list(title = "Precio"))
fig3
En esta comparación si vemos que hay viviendas con muchos o pocos baños y el precio varia desde el mas economico hasta la vivienda mas costosa, no se evidencia una distribución que sea creciente lineal.
# Crear un gráfico interactivo para 'precio' vs 'número de habitaciones'
fig4 <- plot_ly(viviendaR1, x = ~habitaciones, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(color = 'rgba(255, 182, 193, .9)', size = 10),
text = ~paste('Precio:', preciom, '<br>Habitaciones:', habitaciones)) %>%
layout(title = "Precio vs Número de Habitaciones",
xaxis = list(title = "Número de Habitaciones"),
yaxis = list(title = "Precio"))
fig4
Con el numero de habitaciones pasa algo parecido que con los baños, aunque se concentran la mayoria de los datos en una lectura clave y es que a menos numero de habitaciones la mayoria de viviendas son mas economicas que las que tienen mas habitaciones.
# Crear un gráfico interactivo para 'precio' vs 'zona' (si tienes la variable 'zona')
fig5 <- plot_ly(viviendaR1, x = ~zona, y = ~preciom, type = 'box',
boxmean = "sd") %>%
layout(title = "Precio por Zona",
xaxis = list(title = "Zona"),
yaxis = list(title = "Precio"))
fig5
como es una sola zona pues podemos ver un diagrama de cajas que muestra la media del precio de 390, con datos atipicos mayores en precio a 950 millones.
Se hace un poligono que representa el norte de la ciudad de Cali.
library(ggplot2)
library(sf)
## Warning: package 'sf' was built under R version 4.3.3
## Linking to GEOS 3.11.2, GDAL 3.8.2, PROJ 9.3.1; sf_use_s2() is TRUE
# Crear un dataframe con los puntos clave
puntos_clave <- data.frame(
punto = c("Noroeste", "Noreste", "Sureste", "Suroeste", "Noroeste"),
latitud = c(3.482, 3.482, 3.448, 3.448, 3.482),
longitud = c(-76.545, -76.501, -76.545, -76.501, -76.545)
)
# DataFrame con las coordenadas de los 6 puntos
puntos_area <- data.frame(
punto = c(1, 2, 3, 4, 5, 6),
longitud = c(-76.492267, -76.53279888, -76.54114877, -76.52125592, -76.51829294, -76.4662556),
latitud = c(3.50586231, 3.50235088, 3.45104121, 3.46020761, 3.45328482, 3.47101177)
)
# Dibujar el mapa con los puntos de vivienda y agregar el polígono
ggplot(viviendaR1) +
geom_point(aes(x = longitud, y = latitud), color = "blue", size = 2) +
geom_polygon(data = puntos_area, aes(x = longitud, y = latitud),
fill = "red", alpha = 0.3, color = "black", size = 1) +
ggtitle("Ubicación de las casas y área específica en la zona norte de la ciudad") +
theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
Se hace un area que representa la zona norte de Cali y se proyectan los puntos dados por la data, sin embargo encontramos que estos puntos que dicen estar en la Zona norte no es verdad si miramos las coordenadas dadas, por eso debemos trabajar solo con los puntos que estan en esta zona norte marcada por nosotros.
por eso vamos a tomar la base inicial y vamos a dejar las casas que caen dentro de nuestro poligono sin importar que zona diga en la varieble ZONA.
# Crear un objeto sf con los puntos clave
puntos_clave_sf <- st_as_sf(puntos_area, coords = c("longitud", "latitud"), crs = 4326)
# Convertir los puntos clave en un polígono
poligono <- st_convex_hull(st_union(puntos_clave_sf))
# Filtra la base de datos para incluir solo casas
viviendaR1 <- subset(viviendaR, tipo == "Casa")
# Convertir las casas en un objeto sf
vivienda_sf <- st_as_sf(viviendaR1, coords = c("longitud", "latitud"), crs = 4326)
# Filtrar las casas que están dentro del polígono
ViviendaR1C_ <- vivienda_sf[st_within(vivienda_sf, poligono, sparse = FALSE), ]
# Supongamos que `viviendas_filtradas` tiene una columna llamada `ID`
ids_filtrados <- ViviendaR1C_$id
# Filtrar las viviendas en el data frame
viviendaR1C <- ViviendaR1C_ %>%
filter(id %in% ids_filtrados)
# Mostrar los primeros registros de las casas dentro de la zona norte
head(viviendaR1C)
ggplot() +
geom_sf(data = poligono, fill = NA, color = "red") + # Dibujar el polígono
geom_sf(data = viviendaR1C, color = "blue", size = 2) + # Casas dentro del polígono
ggtitle("Casas en la zona norte de Cali") +
theme_minimal()
Con la data ahora si comprobada que son las casas de la zona norte, se repite el analisis de las variables
# Crear un gráfico interactivo para 'precio' vs 'área construida'
fig1 <- plot_ly(viviendaR1C, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(color = 'rgba(255, 182, 193, .9)', size = 10),
text = ~paste('Precio:', preciom, '<br>Área Construida:', areaconst)) %>%
layout(title = "Precio vs Área Construida",
xaxis = list(title = "Área Construida"),
yaxis = list(title = "Precio"))
fig1
Se evidencia un cambio leve en la grafica pero mantiene la estructura mayor area mayor el precio de la vivienda.
# Crear un gráfico interactivo para 'precio' vs 'estrato'
fig2 <- plot_ly(viviendaR1C, x = ~estrato, y = ~preciom, type = 'box',
boxmean = "sd") %>%
layout(title = "Precio por Estrato",
xaxis = list(title = "Estrato"),
yaxis = list(title = "Precio"))
fig2
## Warning: 'box' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'alignmentgroup', 'boxmean', 'boxpoints', 'customdata', 'customdatasrc', 'dx', 'dy', 'fillcolor', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hoveron', 'hovertemplate', 'hovertemplatesrc', 'hovertext', 'hovertextsrc', 'ids', 'idssrc', 'jitter', 'legendgroup', 'legendgrouptitle', 'legendrank', 'line', 'lowerfence', 'lowerfencesrc', 'marker', 'mean', 'meansrc', 'median', 'mediansrc', 'meta', 'metasrc', 'name', 'notched', 'notchspan', 'notchspansrc', 'notchwidth', 'offsetgroup', 'opacity', 'orientation', 'pointpos', 'q1', 'q1src', 'q3', 'q3src', 'quartilemethod', 'sd', 'sdsrc', 'selected', 'selectedpoints', 'showlegend', 'stream', 'text', 'textsrc', 'transforms', 'type', 'uid', 'uirevision', 'unselected', 'upperfence', 'upperfencesrc', 'visible', 'whiskerwidth', 'width', 'x', 'x0', 'xaxis', 'xcalendar', 'xhoverformat', 'xperiod', 'xperiod0', 'xperiodalignment', 'xsrc', 'y', 'y0', 'yaxis', 'ycalendar', 'yhoverformat', 'yperiod', 'yperiod0', 'yperiodalignment', 'ysrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'
Al igual que la anterior se evidencia un cambio, pero matiene la norma de mayor estrato mayor es el costo, sin embargo, evidenciamos que los estratos 3 y 5 tienen mass datos atipicos.
# Crear un gráfico interactivo para 'precio' vs 'número de baños'
fig3 <- plot_ly(viviendaR1C, x = ~banios, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(color = 'rgba(255, 182, 193, .9)', size = 10),
text = ~paste('Precio:', preciom, '<br>Baños:', banios)) %>%
layout(title = "Precio vs Número de Baños",
xaxis = list(title = "Número de Baños"),
yaxis = list(title = "Precio"))
fig3
ahora hay una grafica conjunta de los baños, se consolidan y se ve que no sigue una regla general ya que la vivienda mas costosa tiene 8 baños con un precio de 1940 millones pero encontramos una vivienda de 10 baños con valor de 1400 millones, no se evidencia con esta grafica una norma predictiva.
# Crear un gráfico interactivo para 'precio' vs 'número de habitaciones'
fig4 <- plot_ly(viviendaR1C, x = ~habitaciones, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(color = 'rgba(255, 182, 193, .9)', size = 10),
text = ~paste('Precio:', preciom, '<br>Habitaciones:', habitaciones)) %>%
layout(title = "Precio vs Número de Habitaciones",
xaxis = list(title = "Número de Habitaciones"),
yaxis = list(title = "Precio"))
fig4
Al igual que la grafica anterior no se evidencia una regla general, sin embargo en este caso la vivienda mas costosa tiene el mayor numero de habitaciones posibles entonces tiene logica, pero no es que evidenciemos una norma general.
# Crear un gráfico interactivo para 'precio' vs 'zona' (si tienes la variable 'zona')
fig5 <- plot_ly(viviendaR1C, x = ~zona, y = ~preciom, type = 'box',
boxmean = "sd") %>%
layout(title = "Precio por Zona",
xaxis = list(title = "Zona"),
yaxis = list(title = "Precio"))
fig5
## Warning: 'box' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'alignmentgroup', 'boxmean', 'boxpoints', 'customdata', 'customdatasrc', 'dx', 'dy', 'fillcolor', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hoveron', 'hovertemplate', 'hovertemplatesrc', 'hovertext', 'hovertextsrc', 'ids', 'idssrc', 'jitter', 'legendgroup', 'legendgrouptitle', 'legendrank', 'line', 'lowerfence', 'lowerfencesrc', 'marker', 'mean', 'meansrc', 'median', 'mediansrc', 'meta', 'metasrc', 'name', 'notched', 'notchspan', 'notchspansrc', 'notchwidth', 'offsetgroup', 'opacity', 'orientation', 'pointpos', 'q1', 'q1src', 'q3', 'q3src', 'quartilemethod', 'sd', 'sdsrc', 'selected', 'selectedpoints', 'showlegend', 'stream', 'text', 'textsrc', 'transforms', 'type', 'uid', 'uirevision', 'unselected', 'upperfence', 'upperfencesrc', 'visible', 'whiskerwidth', 'width', 'x', 'x0', 'xaxis', 'xcalendar', 'xhoverformat', 'xperiod', 'xperiod0', 'xperiodalignment', 'xsrc', 'y', 'y0', 'yaxis', 'ycalendar', 'yhoverformat', 'yperiod', 'yperiod0', 'yperiodalignment', 'ysrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'
Aca encontramos algo interesante y es que si analizamos por la variable zona, vemos que dentro de nuestro poligono de la ciudad hay viviendas que en su variable zona tiene zona diferente al norte, evidenciamos viviendas que realmente estan en el norte de la ciudad pero tienen en su variable zona, una diferente.
# Seleccionar las variables a usar en el modelo, excluyendo 'zona'
viviendaR1CF <- viviendaR1C %>%
select(-zona) # Excluir la variable 'zona'
# Revisar las primeras filas para asegurarse de que las variables están presentes
head(viviendaR1CF, 3)
# Estimar el modelo de regresión lineal múltiple
modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = viviendaR1CF)
# Resumen del modelo
summary(modelo1)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = viviendaR1CF)
##
## Residuals:
## Min 1Q Median 3Q Max
## -892.74 -71.31 -20.68 34.69 1115.24
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 26.73179 21.83884 1.224 0.221405
## areaconst 0.79127 0.05261 15.041 < 2e-16 ***
## estrato4 74.17903 21.25435 3.490 0.000518 ***
## estrato5 106.64668 20.06362 5.315 1.49e-07 ***
## estrato6 395.21762 33.03857 11.962 < 2e-16 ***
## habitaciones -3.48051 5.49291 -0.634 0.526554
## parqueaderos 29.13257 5.88291 4.952 9.51e-07 ***
## banios 25.56520 7.03195 3.636 0.000301 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 176.4 on 612 degrees of freedom
## Multiple R-squared: 0.6599, Adjusted R-squared: 0.656
## F-statistic: 169.7 on 7 and 612 DF, p-value: < 2.2e-16
Con este modelo, se ven resultados como que por cada metro cuadrado de mas son 791.270 pesos de mas en el costo de la vivienda, se ve cuanto aumenta el costo de una vivienda si aumenta el estrato, un estrato 4 vale 74 millones mas que un estrato 3 y ahi se evidencia para cada estrato vs el estrato 3 si tienen las mismas condiciones. ahora en la variable habitaciones evidenciamos que una habitacion mas en la vivienda reduce el costo de la vivienda pero esto es un resultado poco intuitivo suponiendo desde ya que el modelo lineal no es muy representativo a la relacion de las variables con el precio, las habitaciones y los baños aumentan el precio en 29 y 25 millones respectivamente.
Cuando analizamos el error estandar (Residual standar error) demuestra que el modelo no se ajusta correctamente a los datos.
El modelo explica un 66% de la variabilidad en los precios de las viviendas, aunque podemos ver que tiene muchas mejoras este modelo respecto a la data estudiada.
Se encontro que el modelo no tiene muy buena adaptabilidad a representar los datos, se recomienda probar una transformacion de variables o ajustar las predicciones finales de alguna manera, tambien se recomienda analizar un modelo mejor para los datos.
# Obtener los valores ajustados y los residuos
fitted_values1 <- fitted(modelo1)
residuals1 <- residuals(modelo1)
# Graficar los residuos versus los valores ajustados
plot(fitted_values1, residuals1,
xlab = "Valores Ajustados",
ylab = "Residuos",
main = "Residuos vs Valores Ajustados")
abline(h = 0, col = "red")
Con el analisis de linealidad encontramos que los valores no son lineales, por ende este modelado no seria buen predictor para el objetivo final.
dwtest(modelo1)
##
## Durbin-Watson test
##
## data: modelo1
## DW = 1.6804, p-value = 2.481e-05
## alternative hypothesis: true autocorrelation is greater than 0
Tenemos un valor de 1.6 es alto y cercano a 2 indicando que los residuos no estan autocorrelacionados.
# Graficar los residuos versus los valores ajustados
plot(fitted_values1, residuals1,
xlab = "Valores Ajustados",
ylab = "Residuos",
main = "Residuos vs Valores Ajustados")
abline(h = 0, col = "red")
#Homosteasidad, se verifica con el grafico de dispersion de linealidad Si la dispersión de los residuos es constante a lo largo de los valores ajustados, se cumple el supuesto de homoscedasticidad.
#Si los residuos muestran una dispersión creciente o decreciente, podría haber problemas de heteroscedasticidad.
Analizando el grafico se encuentra un resultado heterocedastico de los residuos, no cumple el supuesto de homoscedasticidad. Indica que los datos no son lineales.
#Normalidad
# Histograma de los residuos
hist(residuals1, main = "Histograma de los Residuos", xlab = "Residuos", breaks = 30)
# Q-Q plot
qqnorm(residuals1)
qqline(residuals1, col = "red")
#Sugerencias si se encuentran problemas:
#Transformación de Variables: Considera transformar variables si observas problemas con la linealidad.
#Modelos Alternativos: Si hay heteroscedasticidad, considera modelos como la regresión robusta.
#Variables de Control: Agrega variables adicionales o interacciones si los residuos muestran patrones no explicados.
En el grafico vemos una distribucion en forma de campana indicando unos residuos normales. pero en el segundo grafico encontramos que hay demasiados residuos que no tienen esta normalidad, por eso en el histograma encontramos una campana pero con los bordes muy alargados.
Se sugiere que se realice un modelado diferente, pueden utilizar disferentes modelos y encontrar uno que se adapte mejor a los datos.
library(caret)
## Warning: package 'caret' was built under R version 4.3.3
## Loading required package: lattice
##
## Attaching package: 'lattice'
## The following object is masked from 'package:boot':
##
## melanoma
# Establecer una semilla para reproducibilidad
set.seed(123) # Puedes cambiar el número si deseas resultados diferentes
# Crear un índice aleatorio para dividir los datos
training_indices1 <- createDataPartition(viviendaR1CF$preciom, p = 0.7, list = FALSE)
# Crear los conjuntos de entrenamiento y prueba
train_data1 <- viviendaR1CF[training_indices1, ]
test_data1 <- viviendaR1CF[-training_indices1, ]
# Entrenar el modelo en el conjunto de entrenamiento
modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = train_data1)
# Resumen del modelo entrenado
summary(modelo1)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = train_data1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -841.84 -70.44 -22.78 35.96 1014.47
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 60.47313 24.94996 2.424 0.015774 *
## areaconst 0.78063 0.05638 13.845 < 2e-16 ***
## estrato4 84.57951 23.98948 3.526 0.000468 ***
## estrato5 128.83342 22.24684 5.791 1.36e-08 ***
## estrato6 331.66215 37.24457 8.905 < 2e-16 ***
## habitaciones -8.06161 6.24304 -1.291 0.197298
## parqueaderos 28.10474 6.50063 4.323 1.91e-05 ***
## banios 19.94320 8.18446 2.437 0.015228 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 166.9 on 428 degrees of freedom
## Multiple R-squared: 0.6459, Adjusted R-squared: 0.6401
## F-statistic: 111.5 on 7 and 428 DF, p-value: < 2.2e-16
Ahora realizamos el modelado pero partiendo los datos en un 70% destinados a entrenamiento y otro 30% para testeo, no tenemos resultados significativamente diferentes ya que tenemos que cada metro cuadrado aumenta en 780.630 pesos, que el costo de las viviendas aumenta por el aumento de estrato un poco mayor al anterior. En la variable habitacion tenemos la misma contrariedad que el anterior.
Cuando analizamos el error estandar (Residual standar error) demuestra que el modelo no se ajusta correctamente a los datos.
El modelo explica un 64% de la variabilidad en los precios de las viviendas, aunque podemos ver que tiene muchas mejoras este modelo respecto a la data estudiada.
Se sigue encontrando que el modelo no tiene muy buena adaptabilidad a representar los datos, se recomienda probar una transformacion de variables o ajustar las predicciones finales de alguna manera, tambien se recomienda analizar un modelo mejor para los datos.
Se crea un dataframe como filtro
# Crear un data frame con las características de la vivienda
nueva_vivienda1 <- data.frame(
areaconst = 200,
estrato = factor(c(4, 5), levels = c(4, 5)), # Estratos 4 y 5
habitaciones = 4,
parqueaderos = 1,
banios = 2
)
Prediccion del precio de la vivienda
# Hacer la predicción usando el modelo
precio_predicho1 <- predict(modelo1, nueva_vivienda1)
# Mostrar el precio predicho
precio_predicho1
## 1 2
## 336.9228 381.1767
###segun la prediccion si es posible cumplir los pedidos del clientes con el preaprobado segun el modelo planteado
# Hacer predicciones en el conjunto de prueba
predicciones1 <- predict(modelo1, newdata = test_data1)
# Comparar las predicciones con los valores reales
resultados1 <- data.frame(Real = test_data1$preciom, Prediccion = predicciones1)
# Mostrar los primeros resultados
head(resultados1)
# Calcular el error medio absoluto (MAE)
mae1 <- mean(abs(resultados1$Real - resultados1$Prediccion))
print(paste("Error Medio Absoluto (MAE):", mae1))
## [1] "Error Medio Absoluto (MAE): 115.982712351239"
# También podrías calcular el Root Mean Square Error (RMSE) si es necesario
rmse1 <- sqrt(mean((resultados1$Real - resultados1$Prediccion)^2))
print(paste("Root Mean Square Error (RMSE):", rmse1))
## [1] "Root Mean Square Error (RMSE): 204.287701009325"
# Calcular el R² (Coeficiente de Determinación)
R21 <- 1 - sum((predicciones1 - test_data1$preciom)^2) / sum((mean(test_data1$preciom) - test_data1$preciom)^2)
print(paste("R^2 :", R21))
## [1] "R^2 : 0.653897045035854"
Interpretando los resultados, se encuentra un MAE de 115.98 esto significa que en promedio las predicciones del modelo se desvian 115.98 millones de pesos dando un resultado alejado del real.
Se tiene un RMSE de 204.29 tenemos una magnitud de error de 204.29 millones de pesos, penalizando los errores mas grandes.
Analizando un coeficiente de 0.6539, quiere decir que el modelo es util pero tenemos un 35% de variablidad que no esta siendo explicada. Esto nos alerta a que el modelo no sea la unica fuente de datos para la toma de decisiones.
Como ya se vio que la variable zona esta errada, pasaremos directamente a graficar y filtrar por la ubicacion del poligono de la zona sur de la ciudad.
library(ggplot2)
library(sf)
# DataFrame con las coordenadas de los 6 puntos
puntos_area2 <- data.frame(
punto = c(1, 2, 3, 4, 5, 6, 7),
longitud = c(-76.49156207, -76.50980486, -76.52266282, -76.54846102, -76.54268384, -76.55132043, -76.55113485),
latitud = c(3.31719806, 3.38924985, 3.40522812, 3.41472793, 3.37528857, 3.36238751, 3.31869774)
)
# Dibujar el mapa con los puntos de vivienda y agregar el polígono
ggplot(viviendaR) +
geom_point(aes(x = longitud, y = latitud), color = "blue", size = 2) +
geom_polygon(data = puntos_area2, aes(x = longitud, y = latitud),
fill = "red", alpha = 0.3, color = "black", size = 1) +
ggtitle("Ubicación de los apartamentos y área específica en la zona sur de la ciudad") +
theme_minimal()
Se hace un area que representa la zona sur de Cali y se proyectan los puntos dados por la data, sin embargo encontramos que estos puntos que dicen estar en la Zona SUR no es verdad si miramos las coordenadas dadas, por eso debemos trabajar solo con los puntos que estan en esta zona sur marcada por nosotros.
por eso vamos a tomar la base inicial y vamos a dejar los apartamentos que caen dentro de nuestro poligono sin importar que zona diga en la varieble ZONA.
# Crear un objeto sf con los puntos clave
puntos_clave_sf2 <- st_as_sf(puntos_area2, coords = c("longitud", "latitud"), crs = 4326)
# Convertir los puntos clave en un polígono
poligono2 <- st_convex_hull(st_union(puntos_clave_sf2))
# Filtra la base de datos para incluir solo apartamentos
viviendaR2 <- subset(viviendaR, tipo == "Apartamento")
# Convertir las casas en un objeto sf
vivienda_sf2 <- st_as_sf(viviendaR2, coords = c("longitud", "latitud"), crs = 4326)
# Filtrar las casas que están dentro del polígono
ViviendaR2A_ <- vivienda_sf2[st_within(vivienda_sf2, poligono2, sparse = FALSE), ]
# Supongamos que `viviendas_filtradas` tiene una columna llamada `ID`
ids_filtrados2 <- ViviendaR2A_$id
# Filtrar las viviendas en el data frame
viviendaR2A <- ViviendaR2A_ %>%
filter(id %in% ids_filtrados2)
# Mostrar los primeros registros de las casas dentro de la zona sur
head(viviendaR2A)
ggplot() +
geom_sf(data = poligono2, fill = NA, color = "red") + # Dibujar el polígono
geom_sf(data = viviendaR2A, color = "blue", size = 2) + # apartamentos dentro del polígono
ggtitle("Apartamentos en la zona sur de Cali") +
theme_minimal()
Con la data ahora si comprobada que son los apartamentos de la zona sur, se realiza analisis de las variables.
# Crear un gráfico interactivo para 'precio' vs 'área construida'
fig1 <- plot_ly(viviendaR2A, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(color = 'rgba(255, 182, 193, .9)', size = 10),
text = ~paste('Precio:', preciom, '<br>Área Construida:', areaconst)) %>%
layout(title = "Precio vs Área Construida",
xaxis = list(title = "Área Construida"),
yaxis = list(title = "Precio"))
fig1
Se evidencia que mayor area mayor el precio de la vivienda.
# Crear un gráfico interactivo para 'precio' vs 'estrato'
fig2 <- plot_ly(viviendaR2A, x = ~estrato, y = ~preciom, type = 'box',
boxmean = "sd") %>%
layout(title = "Precio por Estrato",
xaxis = list(title = "Estrato"),
yaxis = list(title = "Precio"))
fig2
## Warning: 'box' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'alignmentgroup', 'boxmean', 'boxpoints', 'customdata', 'customdatasrc', 'dx', 'dy', 'fillcolor', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hoveron', 'hovertemplate', 'hovertemplatesrc', 'hovertext', 'hovertextsrc', 'ids', 'idssrc', 'jitter', 'legendgroup', 'legendgrouptitle', 'legendrank', 'line', 'lowerfence', 'lowerfencesrc', 'marker', 'mean', 'meansrc', 'median', 'mediansrc', 'meta', 'metasrc', 'name', 'notched', 'notchspan', 'notchspansrc', 'notchwidth', 'offsetgroup', 'opacity', 'orientation', 'pointpos', 'q1', 'q1src', 'q3', 'q3src', 'quartilemethod', 'sd', 'sdsrc', 'selected', 'selectedpoints', 'showlegend', 'stream', 'text', 'textsrc', 'transforms', 'type', 'uid', 'uirevision', 'unselected', 'upperfence', 'upperfencesrc', 'visible', 'whiskerwidth', 'width', 'x', 'x0', 'xaxis', 'xcalendar', 'xhoverformat', 'xperiod', 'xperiod0', 'xperiodalignment', 'xsrc', 'y', 'y0', 'yaxis', 'ycalendar', 'yhoverformat', 'yperiod', 'yperiod0', 'yperiodalignment', 'ysrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'
Al igual que la anterior mantiene la norma de mayor estrato mayor es el costo, sin embargo, evidenciamos que los estratos 5 y 6 tienen mas datos atipicos.
# Crear un gráfico interactivo para 'precio' vs 'número de baños'
fig3 <- plot_ly(viviendaR2A, x = ~banios, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(color = 'rgba(255, 182, 193, .9)', size = 10),
text = ~paste('Precio:', preciom, '<br>Baños:', banios)) %>%
layout(title = "Precio vs Número de Baños",
xaxis = list(title = "Número de Baños"),
yaxis = list(title = "Precio"))
fig3
ahora vemos una grafica conjunta de los baños, se consolidan y vemos que no sigue una regla general ya que las viviendas mas costosas tiene una de 4 y la otra de 5 baños pero con el mismo precio.
# Crear un gráfico interactivo para 'precio' vs 'número de habitaciones'
fig4 <- plot_ly(viviendaR2A, x = ~habitaciones, y = ~preciom, type = 'scatter', mode = 'markers',
marker = list(color = 'rgba(255, 182, 193, .9)', size = 10),
text = ~paste('Precio:', preciom, '<br>Habitaciones:', habitaciones)) %>%
layout(title = "Precio vs Número de Habitaciones",
xaxis = list(title = "Número de Habitaciones"),
yaxis = list(title = "Precio"))
fig4
Al igual que la grafica anterior no se evidencia una regla general.
# Crear un gráfico interactivo para 'precio' vs 'zona' (si tienes la variable 'zona')
fig5 <- plot_ly(viviendaR2A, x = ~zona, y = ~preciom, type = 'box',
boxmean = "sd") %>%
layout(title = "Precio por Zona",
xaxis = list(title = "Zona"),
yaxis = list(title = "Precio"))
fig5
## Warning: 'box' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'alignmentgroup', 'boxmean', 'boxpoints', 'customdata', 'customdatasrc', 'dx', 'dy', 'fillcolor', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hoveron', 'hovertemplate', 'hovertemplatesrc', 'hovertext', 'hovertextsrc', 'ids', 'idssrc', 'jitter', 'legendgroup', 'legendgrouptitle', 'legendrank', 'line', 'lowerfence', 'lowerfencesrc', 'marker', 'mean', 'meansrc', 'median', 'mediansrc', 'meta', 'metasrc', 'name', 'notched', 'notchspan', 'notchspansrc', 'notchwidth', 'offsetgroup', 'opacity', 'orientation', 'pointpos', 'q1', 'q1src', 'q3', 'q3src', 'quartilemethod', 'sd', 'sdsrc', 'selected', 'selectedpoints', 'showlegend', 'stream', 'text', 'textsrc', 'transforms', 'type', 'uid', 'uirevision', 'unselected', 'upperfence', 'upperfencesrc', 'visible', 'whiskerwidth', 'width', 'x', 'x0', 'xaxis', 'xcalendar', 'xhoverformat', 'xperiod', 'xperiod0', 'xperiodalignment', 'xsrc', 'y', 'y0', 'yaxis', 'ycalendar', 'yhoverformat', 'yperiod', 'yperiod0', 'yperiodalignment', 'ysrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'
aca encontramos algo interesante y es que si analizamos por la variable zona, vemos que dentro de nuestro poligono de la ciudad hay viviendas que en su variable zona tiene zona diferente al sur, evidenciamos viviendas que realmente estan en el sur de la ciudad pero tienen en su variable zona, una diferente.
# Seleccionar las variables a usar en el modelo, excluyendo 'zona'
viviendaR2AF <- viviendaR2A %>%
select(-zona) # Excluir la variable 'zona'
# Revisar las primeras filas para asegurarse de que las variables están presentes
head(viviendaR2AF, 3)
# Estimar el modelo de regresión lineal múltiple
modelo2 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = viviendaR2AF)
# Resumen del modelo
summary(modelo2)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = viviendaR2AF)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1024.36 -38.03 -2.77 35.94 891.07
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -68.29534 13.67125 -4.996 6.35e-07 ***
## areaconst 1.24325 0.05323 23.356 < 2e-16 ***
## estrato4 30.02654 9.87977 3.039 0.0024 **
## estrato5 51.21655 9.99574 5.124 3.27e-07 ***
## estrato6 189.74830 11.79980 16.081 < 2e-16 ***
## habitaciones -9.57630 3.89246 -2.460 0.0140 *
## parqueaderos 75.03333 4.31017 17.408 < 2e-16 ***
## banios 45.14030 3.48295 12.960 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 92.96 on 2110 degrees of freedom
## Multiple R-squared: 0.7912, Adjusted R-squared: 0.7906
## F-statistic: 1142 on 7 and 2110 DF, p-value: < 2.2e-16
Con este modelo, se ven resultados como que por cada metro cuadrado de mas son 1.243 millones de pesos mas en el costo de la vivienda, se ve cuanto aumenta el costo de una vivienda si aumenta el estrato, un estrato 4 vale 30 millones mas que un estrato 3 y ahi se evidencia para cada estrato vs el estrato 3 si tienen las mismas condiciones. ahora en la variable habitaciones evidenciamos que una habitacion mas en la vivienda reduce el costo de la vivienda pero esto es un resultado poco intuitivo suponiendo desde ya que el modelo lineal no es muy representativo a la relacion de las variables con el precio, las habitaciones y los baños aumentan el precio en 75 y 45 millones respectivamente.
Cuando analizamos el error estandar (Residual standar error) demuestra que el modelo no se ajusta correctamente a los datos.
El modelo explica un 79% de la variabilidad en los precios de las viviendas, aunque podemos ver que tiene muchas mejoras este modelo respecto a la data estudiada.
Al igual que el anterior, se encontro que el modelo no tiene muy buena adaptabilidad a representar los datos, se recomienda probar una transformacion de variables o ajustar las predicciones finales de alguna manera, tambien se recomienda analizar un modelo mejor para los datos.
# Obtener los valores ajustados y los residuos
fitted_values2 <- fitted(modelo2)
residuals2 <- residuals(modelo2)
# Graficar los residuos versus los valores ajustados
plot(fitted_values2, residuals2,
xlab = "Valores Ajustados",
ylab = "Residuos",
main = "Residuos vs Valores Ajustados")
abline(h = 0, col = "red")
No tiene una buena linealidad los datos, entendemos que el modelo no es el mejor para representar los datos y las variables que se estan manejando.
install.packages("zoo")
## Warning: package 'zoo' is in use and will not be installed
library(lmtest)
dwtest(modelo2)
##
## Durbin-Watson test
##
## data: modelo2
## DW = 1.711, p-value = 1.053e-11
## alternative hypothesis: true autocorrelation is greater than 0
Tenemos un valor aun mayor en el DW, no tienen correlacion los residuos.
# Graficar los residuos versus los valores ajustados
plot(fitted_values2, residuals2,
xlab = "Valores Ajustados",
ylab = "Residuos",
main = "Residuos vs Valores Ajustados")
abline(h = 0, col = "red")
#Homosteasidad, se verifica con el grafico de dispersion de linealidad Si la dispersión de los residuos es constante a lo largo de los valores ajustados, se cumple el supuesto de homoscedasticidad.
#Si los residuos muestran una dispersión creciente o decreciente, podría haber problemas de heteroscedasticidad.
Analizando el grafico se encuentra un resultado heterocedastico de los residuos, no cumple el supuesto de homoscedasticidad. Indica que los datos no son lineales.
-Normalidad
#Normalidad
# Histograma de los residuos
hist(residuals2, main = "Histograma de los Residuos", xlab = "Residuos", breaks = 30)
# Q-Q plot
qqnorm(residuals2)
qqline(residuals2, col = "red")
#Sugerencias si se encuentran problemas:
#Transformación de Variables: Considera transformar variables si observas problemas con la linealidad.
#Modelos Alternativos: Si hay heteroscedasticidad, considera modelos como la regresión robusta.
#Variables de Control: Agrega variables adicionales o interacciones si los residuos muestran patrones no explicados.
Si se analiza el grafico demuestra un poco mas de normalidad en los residuos que el anterior, pero no es del todo representativo.
Se sugiere que se realice un modelado diferente, pueden utilizar disferentes modelos y encontrar uno que se adapte mejor a los datos.
library(caret)
# Establecer una semilla para reproducibilidad
set.seed(123) # Puedes cambiar el número si deseas resultados diferentes
# Crear un índice aleatorio para dividir los datos
training_indices2 <- createDataPartition(viviendaR2AF$preciom, p = 0.7, list = FALSE)
# Crear los conjuntos de entrenamiento y prueba
train_data2 <- viviendaR2AF[training_indices2, ]
test_data2 <- viviendaR2AF[-training_indices2, ]
# Entrenar el modelo en el conjunto de entrenamiento
modelo2 <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = train_data2)
# Resumen del modelo entrenado
summary(modelo2)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos +
## banios, data = train_data2)
##
## Residuals:
## Min 1Q Median 3Q Max
## -888.11 -37.01 -2.26 36.47 921.87
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -62.72178 16.44152 -3.815 0.000142 ***
## areaconst 1.07972 0.06101 17.697 < 2e-16 ***
## estrato4 30.19596 11.55892 2.612 0.009084 **
## estrato5 55.55203 11.66150 4.764 2.09e-06 ***
## estrato6 187.07123 13.85225 13.505 < 2e-16 ***
## habitaciones -8.75138 4.59084 -1.906 0.056809 .
## parqueaderos 78.76207 4.94994 15.912 < 2e-16 ***
## banios 45.15705 4.02833 11.210 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 91.06 on 1475 degrees of freedom
## Multiple R-squared: 0.7837, Adjusted R-squared: 0.7826
## F-statistic: 763.3 on 7 and 1475 DF, p-value: < 2.2e-16
Ahora realizamos el modelado pero partiendo los datos en un 70% destinados a entrenamiento y otro 30% para testeo, no tenemos resultados significativamente diferentes ya que tenemos que cada metro cuadrado aumenta en 1.079 millones de pesos, que el costo de las viviendas aumenta por el aumento de estrato un poco mayor al anterior. En la variable habitacion tenemos la misma contrariedad que el anterior.
Cuando analizamos el error estandar (Residual standar error) demuestra que el modelo no se ajusta correctamente a los datos.
El modelo explica un 78% de la variabilidad en los precios de las viviendas, aunque podemos ver que tiene muchas mejoras este modelo respecto a la data estudiada.
Se sigue encontrando que el modelo no tiene muy buena adaptabilidad a representar los datos, se recomienda probar una transformacion de variables o ajustar las predicciones finales de alguna manera, tambien se recomienda analizar un modelo mejor para los datos.
# Crear un data frame con las características de la vivienda
nueva_vivienda2 <- data.frame(
areaconst = 300,
estrato = factor(c(5, 6), levels = c(5, 6)), # Estratos 4 y 5
habitaciones = 5,
parqueaderos = 3,
banios = 3
)
# Hacer la predicción usando el modelo
precio_predicho2 <- predict(modelo2, nueva_vivienda2)
# Mostrar el precio predicho
precio_predicho2
## 1 2
## 644.7462 776.2654
###segun la prediccion si es posible cumplir los pedidos del clientes con el preaprobado segun el modelo planteado
# Hacer predicciones en el conjunto de prueba
predicciones2 <- predict(modelo2, newdata = test_data2)
# Comparar las predicciones con los valores reales
resultados2 <- data.frame(Real = test_data2$preciom, Prediccion = predicciones2)
# Mostrar los primeros resultados
head(resultados2)
# Calcular el error medio absoluto (MAE)
mae2 <- mean(abs(resultados2$Real - resultados2$Prediccion))
print(paste("Error Medio Absoluto (MAE):", mae2))
## [1] "Error Medio Absoluto (MAE): 58.8590443061943"
# También podrías calcular el Root Mean Square Error (RMSE) si es necesario
rmse2 <- sqrt(mean((resultados2$Real - resultados2$Prediccion)^2))
print(paste("Root Mean Square Error (RMSE):", rmse2))
## [1] "Root Mean Square Error (RMSE): 98.5103203154061"
# Calcular el R² (Coeficiente de Determinación)
R22 <- 1 - sum((predicciones2 - test_data2$preciom)^2) / sum((mean(test_data2$preciom) - test_data2$preciom)^2)
print(paste("R^2 :", R22))
## [1] "R^2 : 0.799712349557379"
Interpretando los resultados, se encuentra un MAE de 58.85 esto significa que en promedio las predicciones del modelo se desvian 58.85 millones de pesos dando un resultado alejado del real.
Se tiene un RMSE de 98.51 tenemos una magnitud de error de 98.51 millones de pesos, penalizando los errores mas grandes.
Analizando un coeficiente de 0.7997, quiere decir que el modelo es util pero tenemos un 20% de variablidad que no esta siendo explicada. Esto nos alerta a que el modelo no sea la unica fuente de datos para la toma de decisiones.
Luego de realizar el modelado y la evaluacion de resultados tenemos observaciones como que los modelos representan mas del 64% de los datos (ambos modelos), pero no es recomendable como unica fuente de informacion para la toma de deciciones ya que se encontro una variabilidad de resultados alto y que no es muy acertada en los valores de los precios, respecto al valor real con la data recibida.
Se recomienda que se realice el ejercicio de modelado, probando 3 opciones, la priemra una transformacion de variables, la segunda probar un modelado logaritmico y la tercera probar modelos como arbol de deciciones u otro que se considere pertinente.
tener encuenta que los poligonos utilizados estan basados en la informacion encontrada en la pagina de la alcaldia de Cali, no es 100% real pero si tiene mas del 95% de parecido a la distribucion encontrada en la pagina de la alcaldia.