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.
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
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).
{include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(paqueteMETODOS)
## Cargando paquete requerido: dplyr
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
## Cargando paquete requerido: ggplot2
## Warning: package 'ggplot2' was built under R version 4.4.2
data(vivienda)
str(vivienda)
## spc_tbl_ [8,322 × 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:8322] 1147 1169 1350 5992 1212 ...
## $ zona : chr [1:8322] "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
## $ piso : chr [1:8322] NA NA NA "02" ...
## $ estrato : num [1:8322] 3 3 3 4 5 5 4 5 5 5 ...
## $ preciom : num [1:8322] 250 320 350 400 260 240 220 310 320 780 ...
## $ areaconst : num [1:8322] 70 120 220 280 90 87 52 137 150 380 ...
## $ parqueaderos: num [1:8322] 1 1 2 3 1 1 2 2 2 2 ...
## $ banios : num [1:8322] 3 2 2 5 2 3 2 3 4 3 ...
## $ habitaciones: num [1:8322] 6 3 4 3 3 3 3 4 6 3 ...
## $ tipo : chr [1:8322] "Casa" "Casa" "Casa" "Casa" ...
## $ barrio : chr [1:8322] "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
## $ longitud : num [1:8322] -76.5 -76.5 -76.5 -76.5 -76.5 ...
## $ latitud : num [1:8322] 3.43 3.43 3.44 3.44 3.46 ...
## - attr(*, "spec")=List of 3
## ..$ cols :List of 13
## .. ..$ id : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ zona : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ piso : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ estrato : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ preciom : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ areaconst : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ parqueaderos: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ banios : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ habitaciones: list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ tipo : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ barrio : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
## .. ..$ longitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## .. ..$ latitud : list()
## .. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
## ..$ default: list()
## .. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
## ..$ delim : chr ";"
## ..- attr(*, "class")= chr "col_spec"
## - attr(*, "problems")=<externalptr>
#Cargamos las librerias correspondientes
#install.packages("leaflet")
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.4.3
library(dplyr)
library(ggplot2)
library(plotly)
##
## Adjuntando el paquete: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
#Observamos que la base de datos se encuentre correctamente cargada en R
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>
A simple vista evidenciamos algunos datos faltantes, por los que realizaremos una limpieza y preparación de los datos para poder realizar un análisis correctamente.
#Observaremos los tipos de datos de cada una de las variables
glimpse(vivienda)
## Rows: 8,322
## Columns: 13
## $ id <dbl> 1147, 1169, 1350, 5992, 1212, 1724, 2326, 4386, 1209, 159…
## $ zona <chr> "Zona Oriente", "Zona Oriente", "Zona Oriente", "Zona Sur…
## $ piso <chr> NA, NA, NA, "02", "01", "01", "01", "01", "02", "02", "02…
## $ estrato <dbl> 3, 3, 3, 4, 5, 5, 4, 5, 5, 5, 6, 4, 5, 6, 4, 5, 5, 4, 5, …
## $ preciom <dbl> 250, 320, 350, 400, 260, 240, 220, 310, 320, 780, 750, 62…
## $ areaconst <dbl> 70, 120, 220, 280, 90, 87, 52, 137, 150, 380, 445, 355, 2…
## $ parqueaderos <dbl> 1, 1, 2, 3, 1, 1, 2, 2, 2, 2, NA, 3, 2, 2, 1, 4, 2, 2, 2,…
## $ banios <dbl> 3, 2, 2, 5, 2, 3, 2, 3, 4, 3, 7, 5, 6, 2, 4, 4, 4, 3, 2, …
## $ habitaciones <dbl> 6, 3, 4, 3, 3, 3, 3, 4, 6, 3, 6, 5, 6, 2, 5, 5, 4, 3, 3, …
## $ tipo <chr> "Casa", "Casa", "Casa", "Casa", "Apartamento", "Apartamen…
## $ barrio <chr> "20 de julio", "20 de julio", "20 de julio", "3 de julio"…
## $ longitud <dbl> -76.51168, -76.51237, -76.51537, -76.54000, -76.51350, -7…
## $ latitud <dbl> 3.43382, 3.43369, 3.43566, 3.43500, 3.45891, 3.36971, 3.4…
Encontramos 3 variables cualitativas, que son: Zona, Tipo y Barrio.
#Varificaremos el numero de valores nulos por columnas
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
Las dos variables con mayor cantidad de datos faltantes son: piso y parqueaderos,lo cual supone un problema, si corregimos estos datos aplicando la media o mediana de las columnas terminaríamos por crear posibles ofertas que no cumplan con los criterios de los clientes, por lo que en este caso se decide eliminar todas las filas que presenten valores nulos para poder presentar viviendas d ela sque se tenga plena certeza que cumplen con los requerimientos del cliente
#Procederemos a eliminar las columnas que no son necesarias para nuestro análisis
vivienda <- vivienda[, !(names(vivienda) %in% c('id', 'barrio'))]
vivienda <- vivienda[complete.cases(vivienda), ]
colSums(is.na(vivienda))
## zona piso estrato preciom areaconst parqueaderos
## 0 0 0 0 0 0
## banios habitaciones tipo longitud latitud
## 0 0 0 0 0
Podemos evidenciar que ya no existen valores faltantes en la base de datos y que se eliminaron columnas no necesarias para análisis.
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 todos los puntos se ubican en la zona correspondiente o se presentan valores en otras zonas, por que?).
# Filtrar por tipo, zona, y mostrar 3 primeros registros
base1 <- vivienda %>% filter(tipo == "Casa", zona == "Zona Norte")
head(base1,3)
## # A tibble: 3 × 11
## zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Zona N… 02 5 320 150 2 4 6 Casa
## 2 Zona N… 02 5 780 380 2 3 3 Casa
## 3 Zona N… 02 4 625 355 3 5 5 Casa
## # ℹ 2 more variables: longitud <dbl>, latitud <dbl>
#Mapa zona norte
mapa_zonan <- leaflet(base1) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 5,
color = "blue", fillOpacity = 0.6, stroke = FALSE
)
mapa_zonan
Con el mapa evidenciamos que no todas las casas corresponden a su ubicación por zona, es decir, las coordenadas de todas las viviendas que aparecen registradas dentro de la zona norte no corresponden a dicha ubicación, esto puede deberse a que la información de latitud y longitud está mal diligenciada, así que realizaremos un mapa que incluya todas las zonas con el objetivo de verificar si el problema es general en todo el DF.
colores <- colorFactor(palette = "Set2", domain = vivienda$zona)
mapa_completo <- leaflet(vivienda) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 5,
color = ~colores(zona),
fillOpacity = 0.6, stroke = FALSE
) %>%
addLegend("bottomright",
pal = colores,
values = ~zona,
title = "Zona",
opacity = 1)
mapa_completo
Luego de verificar todas las zonas del DF podemos concluir que en efecto, la información de la latitud y longitud se encuentran erradas. La tabla podría corregirse verificando la latitud y longitud correcta de cada una de las zonas de Cali y eliminar las entradas que tengan un error en la digitación.
base1 %>%
filter(tipo == "Casa" & zona == "Zona Norte") %>%
group_by(tipo) %>%
summarize(Cantidad = n())
## # A tibble: 1 × 2
## tipo Cantidad
## <chr> <int>
## 1 Casa 254
# Lo primero que debemos realizar es un matriz de correlación con el objetivo de observar el comportamiento de las variables, pero antes debemos convertir la variable "Estrato en vaiable dummie y que así pase de ser categórica a numérica.
vivienda$estrato <- factor(vivienda$estrato)
estrato_dummies <- model.matrix(~ estrato - 1, data = vivienda)
colnames(estrato_dummies) <- paste("estrato", levels(vivienda$estrato),sep = "_")
base1 <- cbind(vivienda, estrato_dummies)
vivienda_COR <- base1 %>% select(preciom, areaconst, estrato_3, estrato_4, estrato_5, estrato_6, banios, habitaciones, parqueaderos)
correlation_matrix <- cor(vivienda_COR, use = "complete.obs")
plot_ly(vivienda_COR,
type = "heatmap",
z = correlation_matrix,
x = rownames(correlation_matrix),
y = colnames(correlation_matrix))
Con el mapa de calor se muestran las corrlaciones entre las variables y el precio del inmueble en millones. El área construida, numero de baños, parqueaderos y estrato 6 son las variables que más presentan correlación.Este comportamiento tiene sentido si tenemos en cuenta que son las vairables explicativas que serán usadas para determinar el precio con el modelo de regresión.Es importante señalar que la variable con mayor correlación es area contruida de las viviendas (0.69), no hay correlación mayor a 0.85 con ninguna variable, pero hay correlación positiva.
library(plotly)
plot_ly(base1, x = ~areaconst, y = ~preciom, type = "scatter", mode = "markers",
marker = list(color = "blue")) %>%
layout(title = "Relación entre Área Construida y Precio",
xaxis = list(title = "Área Construida (m²)"),
yaxis = list(title = "Precio (millones de pesos)"))
Con el scatter plot podemos graficar la correlación previamente descrita, efectivamente a mayot area construida aumenta el precio del inmueble.
library(ggplot2)
ggplot(base1, aes(x = factor(banios), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Distribución del Precio por numero de baños",
x = "Baños",
y = "Precio (millones de pesos)") +
theme_minimal()
ggplot(base1, aes(x = factor(parqueaderos), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Distribución del Precio por número de parqueaderos",
x = "Numero de Parqueaderos",
y = "Precio (millones de pesos)") +
theme_minimal()
library(ggplot2)
ggplot(base1, aes(x = factor(habitaciones), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Distribución del Precio por numero de habitaciones",
x = "Numero de habitaciones",
y = "Precio (millones de pesos)") +
theme_minimal()
library(ggplot2)
ggplot(vivienda, aes(x = factor(estrato), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Distribución del Precio por Estrato",
x = "Estrato",
y = "Precio (millones de pesos)") +
theme_minimal()
En general todas las variables explicativas muestran su relación con el
precio en millones, todas expresan un aumento en el precio del inmueble
acorde al aumento de sus unidades de medida. Los estratos 5 y 6
evidentemente cuentan con inmuebles con mucho mayor precio, las casas
con 3 habitaciones son las que más varían en precio, el numéro de baños
y parqueaderos a medida que aumentan no presentan outliers, sin embargo,
esto puede deberse a que hay pocos registros en las casas con grán
número de baños y parqueadero.
# Modelo con variables a ajustar
modelo1 <- lm(preciom ~ areaconst + estrato_3 + estrato_4 + estrato_5 + estrato_6 + habitaciones + parqueaderos + banios, data = base1)
summary(modelo1)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato_3 + estrato_4 + estrato_5 +
## estrato_6 + habitaciones + parqueaderos + banios, data = base1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -882.72 -73.50 -7.40 47.23 1061.06
##
## Coefficients: (1 not defined because of singularities)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 272.32063 9.95055 27.37 <2e-16 ***
## areaconst 0.86931 0.02585 33.63 <2e-16 ***
## estrato_3 -283.26963 10.76147 -26.32 <2e-16 ***
## estrato_4 -252.12148 7.66032 -32.91 <2e-16 ***
## estrato_5 -205.26892 6.60170 -31.09 <2e-16 ***
## estrato_6 NA NA NA NA
## habitaciones -27.77785 2.54196 -10.93 <2e-16 ***
## parqueaderos 66.71102 2.97390 22.43 <2e-16 ***
## banios 55.73302 2.96889 18.77 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 163.2 on 4800 degrees of freedom
## Multiple R-squared: 0.7492, Adjusted R-squared: 0.7488
## F-statistic: 2048 on 7 and 4800 DF, p-value: < 2.2e-16
Cada metro cuadrado que aumenta una vivienda el precio aumentará 87 millones, por cada parqueadero disponible el precio subirá 66 millones y por cada baño adicional 55 millones, los estratos presentan una correlación negativa, quiere decir que el preció disminuirá dicha cantitdad de millones dependiendo de su ubicación. Con el valor R cuadrado sabemos que nuestro modelo explica el precio de las casas en la zona norte en un 74%, todas nustras variables explicativas presentan una correlación muy elevada.
par(mfrow = c(2, 2))
plot(modelo1)
La gráfica de los resuduos y los valores ajustados presenta dispersión de los residuos, lo que pod´ria significar heterocedasticidad, en el Q-Q residuals al no alinearse con la diagonal no se observa distribución normal con los residuos. Scale-Location refuerza la idea de la heterocedasticidad al evidenciar una varianza creciente y no constante al aumento de los valores ajustados.
shapiro.test(resid(modelo1)) # Si p < 0.05, los residuos no son normales.
##
## Shapiro-Wilk normality test
##
## data: resid(modelo1)
## W = 0.85034, p-value < 2.2e-16
library(car)
## Warning: package 'car' was built under R version 4.4.2
## Cargando paquete requerido: carData
## Warning: package 'carData' was built under R version 4.4.2
##
## Adjuntando el paquete: 'car'
## The following object is masked from 'package:dplyr':
##
## recode
durbinWatsonTest(modelo1)
## lag Autocorrelation D-W Statistic p-value
## 1 0.1478225 1.703829 0
## Alternative hypothesis: rho != 0
Con las pruebas de shapiro-wilk y Dubin-Watson confirmamos que los residuos no tienen una distribución normal y que existe autocorrelación entre nuestras variables. Podrías realizar una tranformación logaritmica del precio para luego verificar nuvamente si los supuestos se cumplen.
# Se debe primero crear un dataframe con la solicitud del cliente para realizar la predicción
vivienda1 <- data.frame(
areaconst = 200,
parqueaderos = 1,
banios = 2,
habitaciones = 4,
estrato_3 = 0,
estrato_4 = 0,
estrato_5 = 1,
estrato_6 = 0
)
# Predecir precio según características vivienda 1 en estrato 5
predict(modelo1, newdata = vivienda1)
## 1
## 307.9787
predict(modelo1, newdata = vivienda1)
## 1
## 307.9787
vivienda1 <- data.frame(
areaconst = 200,
parqueaderos = 1,
banios = 2,
habitaciones = 4,
estrato_3 = 0,
estrato_4 = 1,
estrato_5 = 0,
estrato_6 = 0
)
# Predecir precio según características vivienda 1 en estrato 4
predict(modelo1, newdata = vivienda1)
## 1
## 261.1261
Nuestro modelo fue capaz de predecir el precio de dos casa, una en ubicada en el estrato 5 con un precio de 307.9787 y otra en estrato 4 con un valor de 261.1261, ambas por debajo del valor del crédito preaprobado.
ofertas_caso1 <- base1 %>%
filter(
areaconst >= 180 & areaconst <= 220,
estrato_4 == 1 | estrato_5 == 1,
parqueaderos >= 1,
banios >= 2,
habitaciones >= 4,
preciom <= 334 ,
zona == "Zona Norte"
)
library(leaflet)
paleta_colores <- colorFactor(palette = "Set1", domain = base1$preciom)
mapa_ofertas1 <- leaflet(ofertas_caso1) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
popup = ~paste( "<br>Zona:", zona,"<br>Precio:", preciom,"<br>Parqueaderos:", parqueaderos,"<br>Baños:", banios,"<br>Habitaciones:", habitaciones),
radius = 9,
color = ~paleta_colores(preciom),
fillOpacity = 1, stroke = FALSE
)
## Warning in RColorBrewer::brewer.pal(max(3, n), palette): n too large, allowed maximum for palette Set1 is 9
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(max(3, n), palette): n too large, allowed maximum for palette Set1 is 9
## Returning the palette you asked for with that many colors
mapa_ofertas1
En el gráfico notamos que solo 3 ofertas cumplen con los solicitado por el cliente.
base2 <- vivienda %>% filter(tipo == "Apartamento", zona == "Zona Sur")
head(base1,3)
## zona piso estrato preciom areaconst parqueaderos banios habitaciones
## 1 Zona Sur 02 4 400 280 3 5 3
## 2 Zona Norte 01 5 260 90 1 2 3
## 3 Zona Norte 01 5 240 87 1 3 3
## tipo longitud latitud estrato_3 estrato_4 estrato_5 estrato_6
## 1 Casa -76.5400 3.43500 0 1 0 0
## 2 Apartamento -76.5135 3.45891 0 0 1 0
## 3 Apartamento -76.5170 3.36971 0 0 1 0
#Mapa zona sur
mapa_zonas <- leaflet(base2) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 5,
color = "blue", fillOpacity = 0.6, stroke = FALSE
)
mapa_zonas
#Mapa completo
colores <- colorFactor(palette = "Set2", domain = vivienda$zona)
mapa_completo <- leaflet(vivienda) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
radius = 5,
color = ~colores(zona),
fillOpacity = 0.6, stroke = FALSE
) %>%
addLegend("bottomright",
pal = colores,
values = ~zona,
title = "Zona",
opacity = 1)
mapa_completo
Se observa el mismo problema que en el caso anterior, los datos de la zona no se encuentran bien entiquetados según la latitud y la longitud.
vivienda$estrato <- factor(vivienda$estrato)
estrato_dummies <- model.matrix(~ estrato - 1, data = vivienda)
colnames(estrato_dummies) <- paste("estrato", levels(vivienda$estrato),sep = "_")
base2 <- cbind(vivienda, estrato_dummies)
vivienda_COR <- base2 %>% select(preciom, areaconst, estrato_3, estrato_4, estrato_5, estrato_6, banios, habitaciones, parqueaderos)
correlation_matrix <- cor(vivienda_COR, use = "complete.obs")
plot_ly(vivienda_COR,
type = "heatmap",
z = correlation_matrix,
x = rownames(correlation_matrix),
y = colnames(correlation_matrix))
#Area construida y Precio
library(plotly)
plot_ly(base2, x = ~areaconst, y = ~preciom, type = "scatter", mode = "markers",
marker = list(color = "blue")) %>%
layout(title = "Relación entre Área Construida y Precio",
xaxis = list(title = "Área Construida (m²)"),
yaxis = list(title = "Precio (millones de pesos)"))
Evidenciamos correlación positiva, entre el precio y las variables explicativas y correlación negativa dependiendo del tipo de estrato, este comportamiento puede ser explicado con más detalle en el modelo de regresión. Las riables más correlacionadas son: área construida, número de parqueaderos y número de baños.
ggplot(base2, aes(x = factor(banios), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Distribución del Precio por numero de baños",
x = "Baños",
y = "Precio (millones de pesos)") +
theme_minimal()
ggplot(base2, aes(x = factor(parqueaderos), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Distribución del Precio por número de parqueaderos",
x = "Numero de Parqueaderos",
y = "Precio (millones de pesos)") +
theme_minimal()
library(ggplot2)
ggplot(base2, aes(x = factor(habitaciones), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Distribución del Precio por numero de habitaciones",
x = "Numero de habitaciones",
y = "Precio (millones de pesos)") +
theme_minimal()
library(ggplot2)
ggplot(vivienda, aes(x = factor(estrato), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Distribución del Precio por Estrato",
x = "Estrato",
y = "Precio (millones de pesos)") +
theme_minimal()
Los estratos más altos presentan mayores orecios en las viviendas, el numero de habitaciones, de baños y de parqueaderos presentan un comportamiento particular, los valores más altos se centra en los valores del 1-3 y van disminuyendo mientras va aumentando el número de unidades de la variable, probablemente a se deba a que existen pocos apartamentos que cuenten con tales resgistros de habitaciones, baños y parqueaderos. 3. ESTIMACIÓN DEL MODELO
# Modelo con variables a ajustar
modelo2 <- lm(preciom ~ areaconst + estrato_3 + estrato_4 + estrato_5 + estrato_6 + habitaciones + parqueaderos + banios, data = base2)
summary(modelo2)
##
## Call:
## lm(formula = preciom ~ areaconst + estrato_3 + estrato_4 + estrato_5 +
## estrato_6 + habitaciones + parqueaderos + banios, data = base2)
##
## Residuals:
## Min 1Q Median 3Q Max
## -882.72 -73.50 -7.40 47.23 1061.06
##
## Coefficients: (1 not defined because of singularities)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 272.32063 9.95055 27.37 <2e-16 ***
## areaconst 0.86931 0.02585 33.63 <2e-16 ***
## estrato_3 -283.26963 10.76147 -26.32 <2e-16 ***
## estrato_4 -252.12148 7.66032 -32.91 <2e-16 ***
## estrato_5 -205.26892 6.60170 -31.09 <2e-16 ***
## estrato_6 NA NA NA NA
## habitaciones -27.77785 2.54196 -10.93 <2e-16 ***
## parqueaderos 66.71102 2.97390 22.43 <2e-16 ***
## banios 55.73302 2.96889 18.77 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 163.2 on 4800 degrees of freedom
## Multiple R-squared: 0.7492, Adjusted R-squared: 0.7488
## F-statistic: 2048 on 7 and 4800 DF, p-value: < 2.2e-16
Cada metro cuadrado que aumenta una vivienda el precio aumentará 87 millones, por cada parqueadero disponible el precio subirá 66 millones y por cada baño adicional 55 millones, los estratos presentan una correlación negativa, quiere decir que el preció disminuirá dicha cantitdad de millones dependiendo de su ubicación. Con el valor R cuadrado sabemos que nuestro modelo explica el precio de las casas en la zona norte en un 74%, todas nustras variables explicativas presentan una correlación muy elevada.
par(mfrow = c(2, 2))
plot(modelo2)
La gráfica de los resuduos y los valores ajustados presenta dispersión de los residuos, lo que pod´ria significar heterocedasticidad, en el Q-Q residuals al no alinearse con la diagonal no se observa distribución normal con los residuos. Scale-Location refuerza la idea de la heterocedasticidad al evidenciar una varianza creciente y no constante al aumento de los valores ajustados.
shapiro.test(resid(modelo1)) # Si p < 0.05, los residuos no son normales.
##
## Shapiro-Wilk normality test
##
## data: resid(modelo1)
## W = 0.85034, p-value < 2.2e-16
library(car)
durbinWatsonTest(modelo2)
## lag Autocorrelation D-W Statistic p-value
## 1 0.1478225 1.703829 0
## Alternative hypothesis: rho != 0
Con las pruebas de shapiro-wilk y Dubin-Watson confirmamos que los residuos no tienen una distribución normal y que existe autocorrelación (ligera pero presente) entre nuestras variables. Podría realizar una tranformación logaritmica del precio para luego verificar nuevamente si los supuestos se cumplen.
# Se debe primero crear un dataframe con la solicitud del cliente para realizar la predicción
vivienda2 <- data.frame(
areaconst = 300,
parqueaderos = 3,
banios = 3,
habitaciones = 5,
estrato_3 = 0,
estrato_4 = 0,
estrato_5 = 1,
estrato_6 = 0
)
# Predecir precio según características vivienda 2 en estrato 5
predict(modelo2, newdata = vivienda2)
## 1
## 556.2865
# Se debe primero crear un dataframe con la solicitud del cliente para realizar la predicción
vivienda2 <- data.frame(
areaconst = 300,
parqueaderos = 3,
banios = 3,
habitaciones = 5,
estrato_3 = 0,
estrato_4 = 0,
estrato_5 = 0,
estrato_6 = 1
)
# Predecir precio según características vivienda 2 en estrato 6
predict(modelo2, newdata = vivienda2)
## 1
## 761.5554
En ambos casos nuestro modelo realizó predicciones por debajo del crédito disponible por el cliente.
ofertas_caso2 <- base2 %>%
filter(
areaconst >= 280 & areaconst <= 320,
estrato_5 == 1 | estrato_6 == 1,
parqueaderos >= 3,
banios >= 3,
habitaciones >= 5,
preciom <= 849 ,
zona == "Zona Sur"
)
library(leaflet)
paleta_colores <- colorFactor(palette = "Set1", domain = base2$preciom)
mapa_ofertas2 <- leaflet(ofertas_caso2) %>%
addTiles() %>%
addCircleMarkers(
lng = ~longitud, lat = ~latitud,
popup = ~paste( "<br>Zona:", zona,"<br>Precio:", preciom,"<br>Parqueaderos:", parqueaderos,"<br>Baños:", banios,"<br>Habitaciones:", habitaciones),
radius = 9,
color = ~paleta_colores(preciom),
fillOpacity = 1, stroke = FALSE
)
## Warning in RColorBrewer::brewer.pal(max(3, n), palette): n too large, allowed maximum for palette Set1 is 9
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(max(3, n), palette): n too large, allowed maximum for palette Set1 is 9
## Returning the palette you asked for with that many colors
mapa_ofertas2