En el presente documento trataremos el caso particular de maría una empresaria que apertura su inmobiliaria y necesita realizar un estudio para determinar posibilidades con dos casos particulares para una casa y un apartamento.
Este documento está dividido en los siguientes puntos:
1.Contexto
2.Pasos requeridos
3.Desarrollo de pasos
Requeridos Vivienda 1
4.Desarrollo de pasos Requeridos Vivienda 2
5.Conclusiones
Dentro de estos numerales desarrollaremos los pasos requeridos para la determinación de las mejores recomendaciones para el caso de la inmobiliaria C&A.
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:
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) .
como entregable se debera realizar un informe ejecutivo con anexos soporte de las estimaciones publicado en RPubs - el enlace debe entregarse en la plataforma Bs
procedemos a cargar la base de datos
#install.packages("devtools") # solo la primera vez
#devtools::install_github("dgonxalex80/paqueteMODELOS", force =TRUE)
#cargamos paquete de datos y data
library(paqueteMODELOS)
## Loading required package: boot
## Loading required package: broom
## Loading required package: GGally
## Loading required package: ggplot2
## Registered S3 method overwritten by 'GGally':
## method from
## +.gg ggplot2
## Loading required package: gridExtra
## Loading required package: knitr
## Loading required package: summarytools
data("vivienda")
#mostramos los primeros 10 registros de la data
head(vivienda,10)
## # A tibble: 10 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1147 Zona … <NA> 3 250 70 1 3 6
## 2 1169 Zona … <NA> 3 320 120 1 2 3
## 3 1350 Zona … <NA> 3 350 220 2 2 4
## 4 5992 Zona … 02 4 400 280 3 5 3
## 5 1212 Zona … 01 5 260 90 1 2 3
## 6 1724 Zona … 01 5 240 87 1 3 3
## 7 2326 Zona … 01 4 220 52 2 2 3
## 8 4386 Zona … 01 5 310 137 2 3 4
## 9 1209 Zona … 02 5 320 150 2 4 6
## 10 1592 Zona … 02 5 780 380 2 3 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
dim(vivienda)
## [1] 8322 13
#generamos lo tipos de datos
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>
como podemos darnos cuent contamos con un total de 13 atributos y 8322 registros, ahroa procederemos a realizar la seleccion de la base del primer caso es decir tomaremos casas con una rea contruida mayor a 200 con 1 parquedero , 4 habitaciones, en estratos 4 y 5 en la zona norte y con un precio maximo de 350 millones
BaseSeleccionada = subset(vivienda, vivienda$tipo=="Casa" & vivienda$zona=="Zona Norte")
head(BaseSeleccionada, 3)
## # A tibble: 3 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1209 Zona N… 02 5 320 150 2 4 6
## 2 1592 Zona N… 02 5 780 380 2 3 3
## 3 4057 Zona N… 02 6 750 445 NA 7 6
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
library(sqldf)
## Loading required package: gsubfn
## Loading required package: proto
## Loading required package: RSQLite
agrupacionzona=sqldf("SELECT zona, COUNT(*) as Freq FROM BaseSeleccionada GROUP BY zona")
agrupacionzona
## zona Freq
## 1 Zona Norte 722
agrupaciontipo=sqldf("SELECT tipo, COUNT(*) as Freq FROM BaseSeleccionada GROUP BY tipo")
agrupaciontipo
## tipo Freq
## 1 Casa 722
# Creación de mapa
library(leaflet)
library(ggplot2)
#creamos el mapa de la distribucion de los datos
mapa_base1<-leaflet(BaseSeleccionada) %>%
addTiles() %>%
addCircleMarkers(lng=~longitud,lat=~latitud,radius=3)
mapa_base1
como podemows darnos cuenta existen un total de 722 registros que corresponden a casas en la zona norte , pero al momento de graficar su posicion teniendo en cuenta su latitud y longitud vemos que hay ubicaciones que se encuetnran por fuera de la zona norte de la ciudad de cali, esto prodria deberse al hecho de errores al momento de la toma de informacion o digitacion.
teniendo en cuenta lo anterior seria un grave error el tomar estos datos por lo que debemos realizar una re zonificacion de la base original teniendo en cuenta una hubicacion donde inice la zona norte de cali, para lo cual dividimos todo lo que este por encima de la longitud 3.460961 como zona norte esto se saca teniendo en cuenta que la zona norte llega hasta el sepraraor vial de la calle 25 y calle 26 en cali, para el caso de la zona sur tendremops todo lo que sea menor a 3.403935 y lo que se encuentre en medio sera declarado zona centro, este tipo de division se hace por motivos de facilitar el proceso de estudio pero lo correcto seria aplciar un modelo no supervisado de clasificacion, ya sea un random forest, perceptorenes multipaca
library(dplyr)
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:gridExtra':
##
## combine
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
#generamos las nuevas zonas
vivienda_zona_new<- vivienda %>%
dplyr::filter(areaconst >=0) %>%
mutate(Nueva_Zona= case_when(latitud<=3.403935~"New Zona Sur", latitud>=3.460961~"New Zona Norte", latitud>3.403935&latitud<3.460961~"New Zona Centro" )) %>%
arrange(areaconst)
#generamos la nueva base
BaseSeleccionada = subset(vivienda_zona_new, vivienda_zona_new$tipo=="Casa" & vivienda_zona_new$Nueva_Zona=="New Zona Norte")
head(BaseSeleccionada, 3)
## # A tibble: 3 × 14
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 502 Zona N… <NA> 3 190 30 1 2 3
## 2 519 Zona N… 02 5 125 45 NA 2 3
## 3 628 Zona O… <NA> 3 100 53 NA 1 3
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>
#validamos los nuevos valores
agrupaciontiponew=sqldf("SELECT Nueva_Zona, COUNT(*) as Freq FROM BaseSeleccionada GROUP BY Nueva_Zona")
agrupaciontiponew
## Nueva_Zona Freq
## 1 New Zona Norte 546
#volvemos a generar el mapa de distribuciones
# Creación de mapa
library(leaflet)
library(ggplot2)
#creamos el mapa de la distribucion de los datos
mapa_base1<-leaflet(BaseSeleccionada) %>%
addTiles() %>%
addCircleMarkers(lng=~longitud,lat=~latitud,radius=3)
mapa_base1
como podemos observar existe una mejor distribucion de los inmuebles y se agregaron nuevos datos al proceso para el analisis
antes de empezar con el analisis de correlaciones entre las variables realizaremos una pequeña validacion de la data para encontrar outliers y nulos
library(naniar)
# devtools::install_github("dgonxalex80/paqueteMODELOS", force = TRUE)
Faltantes = gg_miss_var(BaseSeleccionada, show_pct=TRUE)
Faltantes
#faltantesporcen=n_miss(vivienda_faltantes$id)
faltantesVar = naniar::miss_var_summary(BaseSeleccionada)
faltantesVar
## # A tibble: 14 × 3
## variable n_miss pct_miss
## <chr> <int> <dbl>
## 1 piso 235 43.0
## 2 parqueaderos 183 33.5
## 3 id 0 0
## 4 zona 0 0
## 5 estrato 0 0
## 6 preciom 0 0
## 7 areaconst 0 0
## 8 banios 0 0
## 9 habitaciones 0 0
## 10 tipo 0 0
## 11 barrio 0 0
## 12 longitud 0 0
## 13 latitud 0 0
## 14 Nueva_Zona 0 0
#subset de datos sin data
tr = subset(BaseSeleccionada, is.na(BaseSeleccionada$id))
tr
## # A tibble: 0 × 14
## # ℹ 14 variables: id <dbl>, zona <chr>, piso <chr>, estrato <dbl>,
## # preciom <dbl>, areaconst <dbl>, parqueaderos <dbl>, banios <dbl>,
## # habitaciones <dbl>, tipo <chr>, barrio <chr>, longitud <dbl>,
## # latitud <dbl>, Nueva_Zona <chr>
p> Como podemos darnos cuenta la data presenta datos faltantes en
gran medida en los atributos de piso y parqueaderos, pero todos los
dem??s presentan datos faltantes, realizando el analisis, podemos
observar que un 33% de la data de parqueaderos esta nula y piso el 43%
esta nulo .
p> teniendo en cuenta los resultados obtenidos en los campos de parqueaderos y pisos se toman las siguientes determinaciones:
#calculamos la moda de los paqueaderos
frecuencia_parqueaderos = data.frame(table(BaseSeleccionada$parqueaderos))
modaparq = frecuencia_parqueaderos[which.max(frecuencia_parqueaderos$Freq),1]
modaparq
## [1] 2
## Levels: 1 2 3 4 5 6 7 8 9 10
#modificamos los valores nulos de parqueaderos , ojo cmabiar el valor de 1 por la moda
BaseSeleccionada$parqueaderos= case_when( is.na(BaseSeleccionada$parqueaderos) ~1 , !is.na(BaseSeleccionada$parqueaderos) ~ BaseSeleccionada$parqueaderos)
head(BaseSeleccionada)
## # A tibble: 6 × 14
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 502 Zona N… <NA> 3 190 30 1 2 3
## 2 519 Zona N… 02 5 125 45 1 2 3
## 3 628 Zona O… <NA> 3 100 53 1 1 3
## 4 487 Zona N… 03 3 198 55 1 2 4
## 5 720 Zona N… 04 3 120 60 1 1 3
## 6 773 Zona N… <NA> 3 125 60 1 2 2
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>
Como siguiente paso eliminamos los datos duplicados de la siguiente forma
#prcedemos a dejar la base sin registros duplicados
#devtools::install_github("edzer/sp")
library(dplyr)
BaseSeleccionada = distinct(BaseSeleccionada)
BaseSeleccionada
## # A tibble: 546 × 14
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 502 Zona … <NA> 3 190 30 1 2 3
## 2 519 Zona … 02 5 125 45 1 2 3
## 3 628 Zona … <NA> 3 100 53 1 1 3
## 4 487 Zona … 03 3 198 55 1 2 4
## 5 720 Zona … 04 3 120 60 1 1 3
## 6 773 Zona … <NA> 3 125 60 1 2 2
## 7 573 Zona … 02 3 295 60 1 1 2
## 8 886 Zona … 10 4 165 60 1 2 2
## 9 313 Zona … <NA> 3 210 60 1 2 3
## 10 173 Zona … 02 3 150 60 1 2 3
## # ℹ 536 more rows
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>
#validamos los nuevos valores
agrupacion=sqldf("SELECT tipo, COUNT(*) as Freq FROM BaseSeleccionada GROUP BY tipo")
agrupacion
## tipo Freq
## 1 Casa 546
luego de realizar el analisis de nulos procedemos a realizar el analisis de correlaciones entre las variables debido a que hay mucha diferencia entre las variables de precio y area construida creamos otras variables con el logaritmo, de esta forma aumentamos la confiabilidad de la matriz
#grafico normal de matriz de correlaciones
library(GGally)
library(ggcorrplot)
library(dplyr)
BaseSeleccionada$preciomlog=log(BaseSeleccionada$preciom)
BaseSeleccionada$areaconstlog=log(BaseSeleccionada$areaconst)
BaseSeleccionada
## # A tibble: 546 × 16
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 502 Zona … <NA> 3 190 30 1 2 3
## 2 519 Zona … 02 5 125 45 1 2 3
## 3 628 Zona … <NA> 3 100 53 1 1 3
## 4 487 Zona … 03 3 198 55 1 2 4
## 5 720 Zona … 04 3 120 60 1 1 3
## 6 773 Zona … <NA> 3 125 60 1 2 2
## 7 573 Zona … 02 3 295 60 1 1 2
## 8 886 Zona … 10 4 165 60 1 2 2
## 9 313 Zona … <NA> 3 210 60 1 2 3
## 10 173 Zona … 02 3 150 60 1 2 3
## # ℹ 536 more rows
## # ℹ 7 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>, preciomlog <dbl>, areaconstlog <dbl>
df2 = BaseSeleccionada %>%
select( preciomlog, areaconstlog, estrato, parqueaderos,banios,habitaciones)
#graficamos la tabla de correlaciones
GGally::ggpairs(df2, title="Matriz de Correlaciones de Variables")
# install.packages("plotly")
# install.packages("ggcorrplot")
#correlaciones con gploty
dfn<-select(df2, estrato, preciomlog, areaconstlog, parqueaderos, banios, habitaciones)
r<-cor(dfn)
p<-ggcorrplot(r,type="lower",
title="Correlaciones",
colors=c("red","yellow","blue"),
outline.color="black", ggtheme = theme_test() + theme(text = element_text(size = 7)))
plotly::ggplotly(p)
De los anteriores resultados obtenidos podemos inferir lo siguiente:
Ahora procederemos a calcular el modelo lineal multiple y generaremos los coeficientes del modelo, para lo cual crearemos unas variabbles dummy que permiten trabajar con el modelo
BaseSeleccionada$estrato4<-as.numeric(BaseSeleccionada$estrato==4)
BaseSeleccionada$estrato5<-as.numeric(BaseSeleccionada$estrato==5)
BaseSeleccionada$estrato6<-as.numeric(BaseSeleccionada$estrato==6)
#calculamos el modelo sin separar los estratos
modelobase <- lm(preciomlog ~ areaconstlog+ habitaciones+ parqueaderos + banios+ estrato , data = BaseSeleccionada)
summary(modelobase)
##
## Call:
## lm(formula = preciomlog ~ areaconstlog + habitaciones + parqueaderos +
## banios + estrato, data = BaseSeleccionada)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.68578 -0.16295 -0.02156 0.13947 1.21121
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.3315494 0.1033589 22.558 < 2e-16 ***
## areaconstlog 0.4775141 0.0258218 18.493 < 2e-16 ***
## habitaciones -0.0006772 0.0088085 -0.077 0.93875
## parqueaderos 0.0373387 0.0096861 3.855 0.00013 ***
## banios 0.0623635 0.0118634 5.257 2.11e-07 ***
## estrato 0.1716794 0.0156646 10.960 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2599 on 540 degrees of freedom
## Multiple R-squared: 0.787, Adjusted R-squared: 0.785
## F-statistic: 399.1 on 5 and 540 DF, p-value: < 2.2e-16
#modelo completo
modelobase <- lm(preciomlog ~ areaconstlog+ habitaciones+ parqueaderos + banios+ estrato4+ estrato5+ estrato6 , data = BaseSeleccionada)
summary(modelobase)
##
## Call:
## lm(formula = preciomlog ~ areaconstlog + habitaciones + parqueaderos +
## banios + estrato4 + estrato5 + estrato6, data = BaseSeleccionada)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.68201 -0.15530 -0.02235 0.14936 1.21673
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.850983 0.112661 25.306 < 2e-16 ***
## areaconstlog 0.475899 0.025735 18.492 < 2e-16 ***
## habitaciones 0.002351 0.008810 0.267 0.78967
## parqueaderos 0.036585 0.009623 3.802 0.00016 ***
## banios 0.055875 0.011963 4.671 3.80e-06 ***
## estrato4 0.235686 0.034060 6.920 1.29e-11 ***
## estrato5 0.332559 0.033107 10.045 < 2e-16 ***
## estrato6 0.624307 0.063886 9.772 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2581 on 538 degrees of freedom
## Multiple R-squared: 0.7908, Adjusted R-squared: 0.7881
## F-statistic: 290.6 on 7 and 538 DF, p-value: < 2.2e-16
#creamos un modelos con los valores originales para ser usado en las prediciones
modeloPrediccion <- lm(preciom ~ areaconst+ habitaciones+ parqueaderos + banios+ estrato4+ estrato5+ estrato6 , data = BaseSeleccionada)
Ahora procederemos a realizar una estimacion paso a paso mediante el metodo Steppwise
modelo_b0<- lm(preciom ~ 1, data=BaseSeleccionada) # modelo y= b0
modelo_all <- lm(preciomlog ~ areaconstlog+ habitaciones+ parqueaderos + banios+ estrato4+ estrato5+ estrato6 , data=BaseSeleccionada) # modelo con todas las variables independientes
forward <- step(modelo_b0, direction='forward', scope=formula(modelo_all), trace=0)
# Visualización de los resultados
forward$anova
## Step Df Deviance Resid. Df Resid. Dev AIC
## 1 NA NA 545 33949422 6028.619
## 2 + areaconstlog -1 18754732.1 544 15194690 5591.675
## 3 + estrato6 -1 2572070.0 543 12622620 5492.417
## 4 + parqueaderos -1 782436.2 542 11840184 5459.477
## 5 + estrato5 -1 302413.2 541 11537771 5447.351
## 6 + banios -1 240708.9 540 11297062 5437.839
## 7 + estrato4 -1 98793.6 539 11198268 5435.043
summary(forward)
##
## Call:
## lm(formula = preciom ~ areaconstlog + estrato6 + parqueaderos +
## estrato5 + banios + estrato4, data = BaseSeleccionada)
##
## Residuals:
## Min 1Q Median 3Q Max
## -458.55 -76.76 -17.56 50.85 990.68
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -813.217 62.307 -13.052 < 2e-16 ***
## areaconstlog 200.165 13.738 14.570 < 2e-16 ***
## estrato6 359.895 34.024 10.578 < 2e-16 ***
## parqueaderos 24.483 5.372 4.558 6.41e-06 ***
## estrato5 74.955 17.383 4.312 1.92e-05 ***
## banios 17.445 5.661 3.081 0.00217 **
## estrato4 40.030 18.357 2.181 0.02964 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 144.1 on 539 degrees of freedom
## Multiple R-squared: 0.6701, Adjusted R-squared: 0.6665
## F-statistic: 182.5 on 6 and 539 DF, p-value: < 2.2e-16
los dos modelos tienen una buena explicacion por medio de los modelos en el caso del primer modelo para casas tiene un R que es capaz de explicarlo en un 79% separando los estratos y para el caso de la estimacion paso a paso mediante el metodo Steppwise este nos indica que el modelo deberia realizarce con casi todas las variables sin tener en cuenta las habitaciones, para el mejoramiento de estos resultados podriamos ver la opcion de normalizar los datos de areacontruida y precio para que tenga un mejor manejo de los outliers, este proceso se realizo y se coloco en las columnas de preciomlog y areaconslog
Ahora realizaremos la validacion de supuestos del modelo
#validamos los suspuestos del modelo
par(mfrow = c(2, 2))
plot(modelobase)
de las anteriores graficas podemos determinar lo siguiente:
teniendo en cuenta la grafica de residualVsfitted y scale-location permiten apreciar que la varianza es poco normal, esto debido a los proceso de limpieza que se realizaron a la data antes del proceso de modelado.
la grafica de normalidad muestra que los residuales tienen un buen ajuste
ahora procederemos a predecir el precio de la vivienda para las caracterisitcas deseadas
predict(modeloPrediccion, data.frame(areaconst=200, estrato4=1, estrato5=0, estrato6=0, parqueaderos=1, banios=2, habitaciones=4 ),interval = "confidence")
## fit lwr upr
## 1 322.0662 290.5816 353.5509
predict(modeloPrediccion, data.frame(areaconst=200, estrato4=0, estrato5=1, estrato6=0, parqueaderos=1, banios=2, habitaciones=4 ),interval = "confidence")
## fit lwr upr
## 1 360.4805 332.1304 388.8307
teniendo en cuenta lo anterior podemos apreciar que el precio para una casa en la zona norte, teniendo en cuenta las especificaciones del primer caso, oscila aproximadamente entre 290.5 y 353.5 millones de pesos, para el estrato 4 y para el estrato 5 el precio oscila entre 332.1 y 388 millones de pesos
teniendo en cuenta que para nuestra primera solicitud se tiene un prestamos aprobado de 350 millones y se brindara 5 posibles casas, pero primero generamos todas las posibilidades.
library(dplyr)
casa = filter(BaseSeleccionada, areaconst <= 200, parqueaderos <= 1, banios <= 2, habitaciones <= 4, Nueva_Zona == "New Zona Norte", estrato %in% c(4, 5), preciom <= 350)
casa
## # A tibble: 14 × 19
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 519 Zona … 02 5 125 45 1 2 3
## 2 886 Zona … 10 4 165 60 1 2 2
## 3 346 Zona … <NA> 4 170 77 1 2 2
## 4 493 Zona … <NA> 4 190 86 1 2 3
## 5 1183 Zona … 03 5 300 100 1 2 3
## 6 1073 Zona … <NA> 4 280 104. 1 2 3
## 7 1666 Zona … 02 4 275 120 1 2 4
## 8 406 Zona … 03 4 170 120 1 2 3
## 9 364 Zona … 03 4 160 120 1 2 3
## 10 410 Zona … 03 4 160 120 1 2 3
## 11 411 Zona … 03 4 170 120 1 2 3
## 12 420 Zona … 03 4 160 120 1 2 3
## 13 1008 Zona … <NA> 4 215 144. 1 2 4
## 14 93 Zona … 03 4 265 162 1 2 4
## # ℹ 10 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>, preciomlog <dbl>, areaconstlog <dbl>, estrato4 <dbl>,
## # estrato5 <dbl>, estrato6 <dbl>
como podemos darnos cuenta contamos con un total de 14 posibilidades que cubren las necescidades especificas, ademas se aclara que para las necesidades especificas no existen registros, pero trabajaremos con rangos cercanos a las necesidades sin pasarnos de los estipulado por la empresa cliente
las casa seleccionadas para este proceso son las de codigos 93(se selecciona por que es la mas grande), 1008 (se selecciona por que es la seguna mas grande), 1183 (se selecciona para tener posibilidades en otro estrato), 519 (se selecciona para tener posibilidades en otro estrato) y 1666 (es una de las que mas se acerca a las necesidades estipuladas por la empresa)viviendas_propuestas_base<- BaseSeleccionada %>%
dplyr::filter(id %in% c(93,1008,1183,519,1666)) %>%
mutate(diferencia_cupo=350-preciom, precio_m2=preciom/areaconst) %>%
arrange(precio_m2)
viviendas_propuestas_base
## # A tibble: 5 × 21
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1008 Zona N… <NA> 4 215 144. 1 2 4
## 2 93 Zona O… 03 4 265 162 1 2 4
## 3 1666 Zona N… 02 4 275 120 1 2 4
## 4 519 Zona N… 02 5 125 45 1 2 3
## 5 1183 Zona O… 03 5 300 100 1 2 3
## # ℹ 12 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>, preciomlog <dbl>, areaconstlog <dbl>, estrato4 <dbl>,
## # estrato5 <dbl>, estrato6 <dbl>, diferencia_cupo <dbl>, precio_m2 <dbl>
por ultimo procedemos a visualizar donde se encuentran ubicadas cada una de las opciones de casas en la zona norte
# Creación de mapa con flecha de norte y barra de escala
library(leaflet)
library(sf)
## Linking to GEOS 3.11.2, GDAL 3.7.2, PROJ 9.3.0; sf_use_s2() is TRUE
library(ggplot2)
mapa_opciones<-leaflet(viviendas_propuestas_base) %>%
addTiles() %>%
addCircleMarkers(lng=~longitud,lat=~latitud,radius=7)
mapa_opciones
procedemos a cargar la base de datos y validar los tipos de datos
#generamos lo tipos de datos
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>
como podemos darnos cuent contamos con un total de 13 atributos y 8322 registros, ahroa procederemos a realizar la seleccion de la base del primer caso es decir tomaremos casas con una rea contruida mayor a 200 con 1 parquedero , 4 habitaciones, en estratos 4 y 5 en la zona norte y con un precio maximo de 350 millones
BaseSeleccionadaAPT = subset(vivienda, vivienda$tipo=="Apartamento" & vivienda$zona=="Zona Sur")
head(BaseSeleccionadaAPT, 3)
## # A tibble: 3 × 13
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 5098 Zona S… 05 4 290 96 1 2 3
## 2 698 Zona S… 02 3 78 40 1 1 2
## 3 8199 Zona S… <NA> 6 875 194 2 5 3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
library(sqldf)
agrupacionzona=sqldf("SELECT zona, COUNT(*) as Freq FROM BaseSeleccionadaAPT GROUP BY zona")
agrupacionzona
## zona Freq
## 1 Zona Sur 2787
agrupaciontipo=sqldf("SELECT tipo, COUNT(*) as Freq FROM BaseSeleccionadaAPT GROUP BY tipo")
agrupaciontipo
## tipo Freq
## 1 Apartamento 2787
# Creación de mapa
library(leaflet)
library(ggplot2)
#creamos el mapa de la distribucion de los datos
mapa_base1<-leaflet(BaseSeleccionadaAPT) %>%
addTiles() %>%
addCircleMarkers(lng=~longitud,lat=~latitud,radius=3)
mapa_base1
como podemows darnos cuenta existen un total de 2787 registros que corresponden a Apartamentos en la zona sur , pero al momento de graficar su posicion teniendo en cuenta su latitud y longitud vemos que hay ubicaciones que se encuentran por fuera de la zona sur de la ciudad de cali, esto prodria deberse al hecho de errores al momento de la toma de informacion o digitacion.
teniendo en cuenta lo anterior seria un grave error el tomar estos datos por lo que debemos realizar una re zonificacion de la base original teniendo en cuenta una hubicacion donde inice la zona norte de cali, para lo cual dividimos todo lo que este por encima de la longitud 3.460961 como zona norte esto se saca teniendo en cuenta que la zona norte llega hasta el sepraraor vial de la calle 25 y calle 26 en cali, para el caso de la zona sur tendremops todo lo que sea menor a 3.403935 y lo que se encuentre en medio sera declarado zona centro, este tipo de division se hace por motivos de facilitar el proceso de estudio pero lo correcto seria aplciar un modelo no supervisado de clasificacion, ya sea un random forest, perceptorenes multipaca
library(dplyr)
#generamos las nuevas zonas
vivienda_zona_new<- vivienda %>%
dplyr::filter(areaconst >=0) %>%
mutate(Nueva_Zona= case_when(latitud<=3.403935~"New Zona Sur", latitud>=3.460961~"New Zona Norte", latitud>3.403935&latitud<3.460961~"New Zona Centro" )) %>%
arrange(areaconst)
#generamos la nueva base
BaseSeleccionadaAPT = subset(vivienda_zona_new, vivienda_zona_new$tipo=="Apartamento" & vivienda_zona_new$Nueva_Zona=="New Zona Sur")
head(BaseSeleccionadaAPT, 3)
## # A tibble: 3 × 14
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 698 Zona S… 02 3 78 40 1 1 2
## 2 6007 Zona S… <NA> 4 108 40 NA 1 1
## 3 7656 Zona S… <NA> 3 110 44 NA 2 2
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>
#validamos los nuevos valores
agrupaciontiponew=sqldf("SELECT Nueva_Zona, COUNT(*) as Freq FROM BaseSeleccionadaAPT GROUP BY Nueva_Zona")
agrupaciontiponew
## Nueva_Zona Freq
## 1 New Zona Sur 2145
#volvemos a generar el mapa de distribuciones
# Creación de mapa
library(leaflet)
library(ggplot2)
#creamos el mapa de la distribucion de los datos
mapa_base1<-leaflet(BaseSeleccionadaAPT) %>%
addTiles() %>%
addCircleMarkers(lng=~longitud,lat=~latitud,radius=3)
mapa_base1
como podemos observar existe una mejor distribucion de los inmuebles y se agregaron nuevos datos al proceso para el analisis
antes de empezar con el analisis de correlaciones entre las variables realizaremos una pequeña validacion de la data para encontrar outliers y nulos
library(naniar)
# devtools::install_github("dgonxalex80/paqueteMODELOS", force = TRUE)
Faltantes = gg_miss_var(BaseSeleccionadaAPT, show_pct=TRUE)
Faltantes
#faltantesporcen=n_miss(vivienda_faltantes$id)
faltantesVar = naniar::miss_var_summary(BaseSeleccionadaAPT)
faltantesVar
## # A tibble: 14 × 3
## variable n_miss pct_miss
## <chr> <int> <dbl>
## 1 piso 528 24.6
## 2 parqueaderos 339 15.8
## 3 id 0 0
## 4 zona 0 0
## 5 estrato 0 0
## 6 preciom 0 0
## 7 areaconst 0 0
## 8 banios 0 0
## 9 habitaciones 0 0
## 10 tipo 0 0
## 11 barrio 0 0
## 12 longitud 0 0
## 13 latitud 0 0
## 14 Nueva_Zona 0 0
#subset de datos sin data
tr = subset(BaseSeleccionadaAPT, is.na(BaseSeleccionadaAPT$id))
tr
## # A tibble: 0 × 14
## # ℹ 14 variables: id <dbl>, zona <chr>, piso <chr>, estrato <dbl>,
## # preciom <dbl>, areaconst <dbl>, parqueaderos <dbl>, banios <dbl>,
## # habitaciones <dbl>, tipo <chr>, barrio <chr>, longitud <dbl>,
## # latitud <dbl>, Nueva_Zona <chr>
p> Como podemos darnos cuenta la data presenta datos faltantes en
gran medida en los atributos de piso y parqueaderos, pero todos los
demas no presentan datos faltantes, realizando el analisis, podemos
observar que un 15% de la data de parqueaderos esta nula y piso el 24%
esta nulo .
p> teniendo en cuenta los resultados obtenidos en los campos de parqueaderos y pisos se toman las siguientes determinaciones:
#calculamos la moda de los paqueaderos
frecuencia_parqueaderos = data.frame(table(BaseSeleccionadaAPT$parqueaderos))
modaparq = frecuencia_parqueaderos[which.max(frecuencia_parqueaderos$Freq),1]
modaparq
## [1] 1
## Levels: 1 2 3 4 10
#modificamos los valores nulos de parqueaderos , ojo cmabiar el valor de 1 por la moda
BaseSeleccionadaAPT$parqueaderos= case_when( is.na(BaseSeleccionadaAPT$parqueaderos) ~2 , !is.na(BaseSeleccionadaAPT$parqueaderos) ~ BaseSeleccionadaAPT$parqueaderos)
head(BaseSeleccionadaAPT)
## # A tibble: 6 × 14
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 698 Zona S… 02 3 78 40 1 1 2
## 2 6007 Zona S… <NA> 4 108 40 2 1 1
## 3 7656 Zona S… <NA> 3 110 44 2 2 2
## 4 5873 Zona O… <NA> 5 89 44 1 1 2
## 5 1998 Zona S… 03 5 130 45 1 2 2
## 6 1485 Zona S… 07 4 145 45 2 2 2
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>
Como siguiente paso eliminamos los datos duplicados de la siguiente forma
#prcedemos a dejar la base sin registros duplicados
#devtools::install_github("edzer/sp")
library(dplyr)
BaseSeleccionadaAPT = distinct(BaseSeleccionadaAPT)
BaseSeleccionadaAPT
## # A tibble: 2,145 × 14
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 698 Zona … 02 3 78 40 1 1 2
## 2 6007 Zona … <NA> 4 108 40 2 1 1
## 3 7656 Zona … <NA> 3 110 44 2 2 2
## 4 5873 Zona … <NA> 5 89 44 1 1 2
## 5 1998 Zona … 03 5 130 45 1 2 2
## 6 1485 Zona … 07 4 145 45 2 2 2
## 7 1990 Zona … 06 4 140 45 1 1 2
## 8 8027 Zona … <NA> 4 78 46 1 1 2
## 9 793 Zona … 05 4 121 47 2 1 2
## 10 8219 Zona … <NA> 3 87 47 2 1 3
## # ℹ 2,135 more rows
## # ℹ 5 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>
#validamos los nuevos valores
agrupacion=sqldf("SELECT tipo, COUNT(*) as Freq FROM BaseSeleccionadaAPT GROUP BY tipo")
agrupacion
## tipo Freq
## 1 Apartamento 2145
luego de realizar el analisis de nulos procedemos a realizar el analisis de correlaciones entre las variables
BaseSeleccionadaAPT$preciomlog=log(BaseSeleccionadaAPT$preciom)
BaseSeleccionadaAPT$areaconstlog=log(BaseSeleccionadaAPT$areaconst)
BaseSeleccionadaAPT
## # A tibble: 2,145 × 16
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 698 Zona … 02 3 78 40 1 1 2
## 2 6007 Zona … <NA> 4 108 40 2 1 1
## 3 7656 Zona … <NA> 3 110 44 2 2 2
## 4 5873 Zona … <NA> 5 89 44 1 1 2
## 5 1998 Zona … 03 5 130 45 1 2 2
## 6 1485 Zona … 07 4 145 45 2 2 2
## 7 1990 Zona … 06 4 140 45 1 1 2
## 8 8027 Zona … <NA> 4 78 46 1 1 2
## 9 793 Zona … 05 4 121 47 2 1 2
## 10 8219 Zona … <NA> 3 87 47 2 1 3
## # ℹ 2,135 more rows
## # ℹ 7 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>, preciomlog <dbl>, areaconstlog <dbl>
df2 = BaseSeleccionadaAPT %>%
select( preciomlog, areaconstlog, estrato, parqueaderos,banios,habitaciones)
#grafico normal de matriz de correlaciones
library(GGally)
library(ggcorrplot)
GGally::ggpairs(df2, title="Matriz de correlaciones Apartementos")
# install.packages("plotly")
# install.packages("ggcorrplot")
#correlaciones con gploty
dfn<-select(df2, estrato, preciomlog, areaconstlog, parqueaderos, banios, habitaciones)
r<-cor(dfn)
p<-ggcorrplot(r,type="lower",
title="Correlaciones",
colors=c("red","yellow","blue"),
outline.color="black", ggtheme = theme_test() + theme(text = element_text(size = 7)))
plotly::ggplotly(p)
De los anteriores resultados obtenidos podemos inferir lo siguiente:
Ahora procederemos a calcular el modelo lineal multiple y generaremos los coeficientes del modelo
BaseSeleccionadaAPT$estrato4<-as.numeric(BaseSeleccionadaAPT$estrato==4)
BaseSeleccionadaAPT$estrato5<-as.numeric(BaseSeleccionadaAPT$estrato==5)
BaseSeleccionadaAPT$estrato6<-as.numeric(BaseSeleccionadaAPT$estrato==6)
#calculamos el modelo sin separar los estratos
modelobase <- lm(preciomlog ~ areaconstlog+ habitaciones+ parqueaderos + banios+ estrato , data = BaseSeleccionadaAPT)
summary(modelobase)
##
## Call:
## lm(formula = preciomlog ~ areaconstlog + habitaciones + parqueaderos +
## banios + estrato, data = BaseSeleccionadaAPT)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.83249 -0.11398 0.00466 0.12977 0.74281
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.226757 0.064654 18.974 < 2e-16 ***
## areaconstlog 0.707711 0.019353 36.569 < 2e-16 ***
## habitaciones -0.031204 0.008559 -3.646 0.000273 ***
## parqueaderos 0.038603 0.007879 4.900 1.03e-06 ***
## banios 0.080300 0.007827 10.259 < 2e-16 ***
## estrato 0.214336 0.007027 30.501 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.203 on 2139 degrees of freedom
## Multiple R-squared: 0.8544, Adjusted R-squared: 0.8541
## F-statistic: 2511 on 5 and 2139 DF, p-value: < 2.2e-16
modelobase <- lm(preciomlog ~ areaconstlog+ habitaciones+ parqueaderos + banios+ estrato4+ estrato5+ estrato6 , data = BaseSeleccionadaAPT)
summary(modelobase)
##
## Call:
## lm(formula = preciomlog ~ areaconstlog + habitaciones + parqueaderos +
## banios + estrato4 + estrato5 + estrato6, data = BaseSeleccionadaAPT)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.82404 -0.11739 0.01046 0.13240 0.79915
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.764514 0.071420 24.706 < 2e-16 ***
## areaconstlog 0.720356 0.019225 37.470 < 2e-16 ***
## habitaciones -0.023175 0.008519 -2.721 0.00657 **
## parqueaderos 0.033235 0.008031 4.138 3.64e-05 ***
## banios 0.068539 0.007886 8.692 < 2e-16 ***
## estrato4 0.305962 0.019799 15.453 < 2e-16 ***
## estrato5 0.457312 0.020597 22.203 < 2e-16 ***
## estrato6 0.735758 0.024753 29.724 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2004 on 2137 degrees of freedom
## Multiple R-squared: 0.8582, Adjusted R-squared: 0.8578
## F-statistic: 1848 on 7 and 2137 DF, p-value: < 2.2e-16
modeloprediccion2 <- lm(preciom ~ areaconst+ habitaciones+ parqueaderos + banios+ estrato4+ estrato5+ estrato6 , data = BaseSeleccionadaAPT)
Ahora procederemos a realizar una estimacion paso a paso mediante el metodo Steppwise
modelo_b0<- lm(preciom ~ 1, data=BaseSeleccionadaAPT) # modelo y= b0
modelo_all <- lm(preciomlog ~ areaconstlog+ habitaciones+ parqueaderos + banios+ estrato4+ estrato5+ estrato6, data=BaseSeleccionadaAPT) # modelo con todas las variables independientes
forward <- step(modelo_b0, direction='forward', scope=formula(modelo_all), trace=0)
# Visualización de los resultados
forward$anova
## Step Df Deviance Resid. Df Resid. Dev AIC
## 1 NA NA 2144 94976213 22949.73
## 2 + areaconstlog -1 65870237.97 2143 29105975 20414.87
## 3 + estrato6 -1 6767960.93 2142 22338014 19849.19
## 4 + parqueaderos -1 1514673.42 2141 20823341 19700.58
## 5 + banios -1 728051.91 2140 20095289 19626.24
## 6 + habitaciones -1 349583.97 2139 19745705 19590.60
## 7 + estrato5 -1 25136.20 2138 19720569 19589.87
## 8 + estrato4 -1 56664.96 2137 19663904 19585.69
summary(forward)
##
## Call:
## lm(formula = preciom ~ areaconstlog + estrato6 + parqueaderos +
## banios + habitaciones + estrato5 + estrato4, data = BaseSeleccionadaAPT)
##
## Residuals:
## Min 1Q Median 3Q Max
## -616.85 -40.94 3.99 37.00 893.72
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1042.962 34.185 -30.510 < 2e-16 ***
## areaconstlog 270.302 9.202 29.375 < 2e-16 ***
## estrato6 160.336 11.848 13.533 < 2e-16 ***
## parqueaderos 44.602 3.844 11.603 < 2e-16 ***
## banios 35.816 3.774 9.489 < 2e-16 ***
## habitaciones -23.581 4.077 -5.784 8.39e-09 ***
## estrato5 29.365 9.858 2.979 0.00293 **
## estrato4 23.517 9.477 2.482 0.01316 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 95.93 on 2137 degrees of freedom
## Multiple R-squared: 0.793, Adjusted R-squared: 0.7923
## F-statistic: 1169 on 7 and 2137 DF, p-value: < 2.2e-16
los dos modelos tienen una buena explicacion por medio de los modelos en el caso del segundo modelo para apartamentoses es aun mejor que el primer modelo d por lo que alcanza a tener un R de 85% , para el mejoramiento de estos resultados podriamos ver la opcion de normalizar los datos de areacontruida y precio para que tenga un mejor manejo de los outliers, esto fue realizado y se tuvo un muy bien R cuadrado, y teniendo en cuenta el metodo Steppwise deberieamos realizar e lmodelo con todfas las variables
Ahora realizaremos la validacion de supuestos del modelo#validamos los suspuestos del modelo
par(mfrow = c(2, 2))
plot(modelobase)
de las anteriores graficas podemos determinar lo siguiente:
teniendo en cuenta la grafica de residual Vs fitted y scale-location permiten apreciar que la varianza es normal, esto debido a los proceso de limpieza que se realizaron a la data antes del proceso de modelado.
la grafica de normalidad muestra que los residuales tienen un buen ajuste
ahora procederemos a predecir el precio de la vivienda para las caracterisitcas deseadas
predict(modeloprediccion2, data.frame(areaconst=300, estrato4=0, estrato5=1, estrato6=0, parqueaderos=3, banios=3, habitaciones=5 ),interval = "confidence")
## fit lwr upr
## 1 670.8884 645.5841 696.1927
predict(modeloprediccion2, data.frame(areaconst=300, estrato4=0, estrato5=0, estrato6=1, parqueaderos=3, banios=3, habitaciones=5 ),interval = "confidence")
## fit lwr upr
## 1 816.4451 791.2794 841.6107
teniendo en cuenta lo anterior podemos apreciar que el precio para un apartamento en la zona norte, teniendo en cuenta las especificaciones del primer caso, oscila aproximadamente entre 645.58 y 696.19 millones de pesos para el estrato 5 y para el estrato 6 el precio oscila entre 791.27 y 841.61 millones de pesos
teniendo en cuenta que para nuestra primera solicitud se tiene un prestamos aprobado de 350 millones y se brindara 5 posibles Apartamentos, pero primero generamos todas las posibilidades.
library(dplyr)
Apartamento = filter(BaseSeleccionadaAPT, areaconst <= 300, parqueaderos <= 3, banios <= 3, habitaciones <= 5, Nueva_Zona == "New Zona Sur", estrato %in% c(5,6), preciom <= 850)
Apartamento
## # A tibble: 943 × 19
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 5873 Zona … <NA> 5 89 44 1 1 2
## 2 1998 Zona … 03 5 130 45 1 2 2
## 3 3551 Zona … <NA> 5 245 50 1 1 1
## 4 1639 Zona … 06 5 155 50 1 1 2
## 5 3621 Zona … 05 6 245 50.3 2 1 1
## 6 1635 Zona … <NA> 5 147 51 1 2 3
## 7 1619 Zona … 02 5 155 52 2 2 2
## 8 1875 Zona … 02 6 128 55 2 2 2
## 9 7694 Zona … 06 5 219 55 2 2 3
## 10 3622 Zona … 03 6 260 55 2 1 1
## # ℹ 933 more rows
## # ℹ 10 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>, preciomlog <dbl>, areaconstlog <dbl>, estrato4 <dbl>,
## # estrato5 <dbl>, estrato6 <dbl>
como podemos darnos cuenta contamos con un total de 943 posibilidades que cubren las necescidades especificas, ademas se aclara que para las necesidades especificas no existen registros, pero trabajaremos con rangos cercanos a las necesidades sin pasarnos de los estipulado por la empresa cliente
las casa seleccionadas para este proceso son las de codigos 6175 (se selecciona por que es la mas grande y tiene un numero de habitaicones cercano), 5880 (se selecciona por lo que contiene un buen numero de habitaciones y parquederos), 6361 (se selecciona para tener posibilidades en otro estrato), 4008 (se selecciona para tener posibilidades en otro estrato) y 5701 (es una de las que mas se acerca a las necesidades estipuladas por la empresa)viviendas_propuestas_base<- BaseSeleccionadaAPT %>%
dplyr::filter(id %in% c(6175,5880,6361,4008,5701)) %>%
mutate(diferencia_cupo=850-preciom, precio_m2=preciom/areaconst) %>%
arrange(precio_m2)
viviendas_propuestas_base
## # A tibble: 5 × 21
## id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 6175 Zona S… 05 5 350 270 3 3 4
## 2 6361 Zona S… <NA> 6 655 241 2 3 3
## 3 4008 Zona S… 07 6 410 142 2 3 4
## 4 5701 Zona S… <NA> 6 570 160 3 3 3
## 5 5880 Zona S… <NA> 6 670 168 2 3 4
## # ℹ 12 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>,
## # Nueva_Zona <chr>, preciomlog <dbl>, areaconstlog <dbl>, estrato4 <dbl>,
## # estrato5 <dbl>, estrato6 <dbl>, diferencia_cupo <dbl>, precio_m2 <dbl>
por ultimo procedemos a visualizar donde se encuentran ubicadas cada una de las opciones de casas en la zona sur
# Creación de mapa con flecha de norte y barra de escala
library(leaflet)
library(sf)
library(ggplot2)
mapa_opciones<-leaflet(viviendas_propuestas_base) %>%
addTiles() %>%
addCircleMarkers(lng=~longitud,lat=~latitud,radius=7)
mapa_opciones
por ultimo podemos obtener las siguientes conclusiones: