INFORME

Ante la solicitud del análisis inmobiliario, se realizó un modelo de regresión lineal múltiple que nos permitió obtener valores estimados de posibles precios para las solicitudes realizada por parte de la compañía internacional a la inmobiiliaia C&A . A continuación se muestran las posibles “ofertas potenciales” para cada escenario.

id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
3586 Zona Norte 01 4 330 240 1 2 3 Casa la merced -76.52720 3.48433
1924 Zona Norte 01 4 320 264 1 2 3 Casa vipasa -76.51840 3.48459
1943 Zona Norte NA 5 350 346 1 2 4 Casa vipasa -76.51847 3.47503

Como se puede evidenciar, para la primera solicitud se muestran 3 opciones:

  1. Casa de 240 metros de área, 1 parqueadero, 2 baños, 3 habitaciones y estrato 4 por un precio de 330 millones de pesos.

  2. Casa de 264 metros de área, 1 parqueadero, 2 baños, 3 habitaciones y estrato 4 por un precio de 320 millones de pesos.

  3. Casa de 346 metros de área, 1 parqueadero, 2 baños, 4 habitaciones y estrato 5 por un precio de 350 millones de pesos.

id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
5574 Zona Sur NA 6 850 352 4 3 3 Apartamento pance -76.53729 3.34265

Como se puede evidenciar, para la segunda solicitud se muestra 1 opción:

  1. Casa de 356 metros de área, 4 parqueaderos, 3 baños, 3 habitaciones y estrato 6 por un precio de 850 millones de pesos.

Debido a que solo obtuvimos una propuesta inicial, agregamos las siguientes opciones por un precio un poco mayor al presupuesto inicial.

id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
5248 Zona Sur 08 6 1150 344 4 5 5 Apartamento ciudad jardín -76.53533 3.36971
6023 Zona Sur 08 6 1150 464 4 6 5 Apartamento ciudad jardín -76.54000 3.36800
  1. Casa de 344 metros de área, 4 parqueaderos, 5 baños, 5 habitaciones y estrato 6 por un precio de 1150 millones de pesos.

  2. Casa de 464 metros de área, 4 parqueaderos, 6 baños, 5 habitaciones y estrato 6 por un precio de 1150 millones de pesos.

ANEXO 1. IDENTIFICACIÓN METODOLOGÍA ADECUADA

ANEXO 2. APLICACIÓN METODOLOGÍA SELECIONADA.IONADA.

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 trasladó 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

Instalamos las librerías y paquetes que usaremos

Limpieza de datos

Revisamos las primeras 10 filas de nuestra data frame y verificamos si existen datos faltantes en nuestra base

head(df,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>
md.pattern(df)

##      preciom id zona estrato areaconst banios habitaciones tipo barrio longitud
## 4808       1  1    1       1         1      1            1    1      1        1
## 1909       1  1    1       1         1      1            1    1      1        1
## 876        1  1    1       1         1      1            1    1      1        1
## 726        1  1    1       1         1      1            1    1      1        1
## 1          1  0    0       0         0      0            0    0      0        0
## 2          0  0    0       0         0      0            0    0      0        0
##            2  3    3       3         3      3            3    3      3        3
##      latitud parqueaderos piso     
## 4808       1            1    1    0
## 1909       1            1    0    1
## 876        1            0    1    1
## 726        1            0    0    2
## 1          0            0    0   12
## 2          0            0    0   13
##            3         1605 2638 4275

Notamos que hay varios N/1, procedemos a eliminarlos

df <- df[!is.na(df$id), ]

Llenamos los registros de NA en la columna “piso” con el número 1 asumiendo que es una vivienda de una planta y de parqueadero con el número 0 asumiendo que esa vivienda no tiene parquederos.

df$piso <- ifelse(is.na(df$piso), 1, df$piso)
df$parqueaderos <- ifelse(is.na(df$parqueaderos), 0, df$parqueaderos)

Verificamos nuevamente si existen datos faltantes en nuestra base

md.pattern(df)
##  /\     /\
## {  `---'  }
## {  O   O  }
## ==>  V <==  No need for mice. This data set is completely observed.
##  \  \|/  /
##   `-----'

##      id zona piso estrato preciom areaconst parqueaderos banios habitaciones
## 8319  1    1    1       1       1         1            1      1            1
##       0    0    0       0       0         0            0      0            0
##      tipo barrio longitud latitud  
## 8319    1      1        1       1 0
##         0      0        0       0 0
head(df,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 … 1           3     250        70            1      3            6
##  2  1169 Zona … 1           3     320       120            1      2            3
##  3  1350 Zona … 1           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>

Notamos que ya no hay datos faltantes

Corregimos la zona de acuerdo con la posición geográfica para un análisis más fiable.

df$zona <- NA
df$zona <- ifelse(df$longitud < -76.537138, "Zona Oeste", df$zona)
df$zona <- ifelse(df$longitud > -76.485196, "Zona Oriente", df$zona)
df$zona <- ifelse(df$latitud > 3.460322, "Zona Norte", df$zona)
df$zona <- ifelse(df$latitud < 3.404536, "Zona Sur", df$zona)
df$zona <- ifelse(is.na(df$zona), "Zona Centro", df$zona)
head(df, n = 5)
## # A tibble: 5 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1147 Zona C… 1           3     250        70            1      3            6
## 2  1169 Zona C… 1           3     320       120            1      2            3
## 3  1350 Zona C… 1           3     350       220            2      2            4
## 4  5992 Zona O… 02          4     400       280            3      5            3
## 5  1212 Zona C… 01          5     260        90            1      2            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Punto 1. 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?).

base1 = subset(df, tipo =="Casa" & zona=="Zona Norte")
# Mostrar los primeros 3 registros de la base filtrada
head(base1, 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   504 Zona N… 1           3     180       120            0      3            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
leaflet() %>% addTiles() %>% 
  setView(lng =  -76.51595234451665, lat = 3.436834062816008, zoom = 12)  %>%
  addCircleMarkers(lng = base1$longitud,
                   lat = base1$latitud,
                   label = as.character(paste0(base1$tipo, " est:", base1$estrato, " Precio:",base1$preciom, "'000.000", " Pisos:", base1$piso)), 
                   stroke = FALSE, 
                   fillOpacity = 0.5,
                   radius = 4,
                   color = 'green'
  )

Debido a que anteriormente en nuestra limpieza de datos corregimos la latitud y longitud, podemos observar que todas nuestras observaciones se encuentran dentro del rango de zona norte.

Punto 2. Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio del apartamento) en función del área construida, estrato, numero de baños, numero de habitaciones y zona donde se ubica la vivienda. Use gráficos interactivos con el paquete plotly e interprete los resultados.

Creo mi nueva df con la información solo de la solicitud 1

df1 = base1
head(df1,10)
## # A tibble: 10 × 13
##       id zona   piso  estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  1209 Zona … 02          5     320       150            2      4            6
##  2  1592 Zona … 02          5     780       380            2      3            3
##  3   504 Zona … 1           3     180       120            0      3            3
##  4   604 Zona … 1           5     520       455            0      5            4
##  5  1003 Zona … 1           3     380       300            0      5            8
##  6  1840 Zona … 1           5     395       165            0      4            4
##  7  2730 Zona … 1           5     460       319            0      5            4
##  8  2875 Zona … 1           5     390       357            0      3            6
##  9  2908 Zona … 1           5     780       380            0      3            3
## 10  3182 Zona … 1           4     420       265            0      6            7
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Reordeno mi df

df1 <- df1 %>% select(id, zona, tipo, barrio, piso, estrato, preciom, areaconst, parqueaderos, banios, habitaciones, longitud, latitud)
ggpairs(df1[,7:11], title="Análisis exploratorio de datos")

Podemos observar una correlación de 0.743 entre la variable precio con areaconst lo cual es positivo para nuestro análisis. También con la variable baños de 0.558

Punto 3. Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, numero de cuartos, numero de parqueaderos, numero de baños ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deber están contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).

Convertimos la variable “estrato” en factor, creamos nuestro modelo y mostramos un resumen de él

df1$estrato <- factor(df1$estrato)
str(df1)
## tibble [551 × 13] (S3: tbl_df/tbl/data.frame)
##  $ id          : num [1:551] 1209 1592 504 604 1003 ...
##  $ zona        : chr [1:551] "Zona Norte" "Zona Norte" "Zona Norte" "Zona Norte" ...
##  $ tipo        : chr [1:551] "Casa" "Casa" "Casa" "Casa" ...
##  $ barrio      : chr [1:551] "acopi" "acopi" "acopi" "acopi" ...
##  $ piso        : chr [1:551] "02" "02" "1" "1" ...
##  $ estrato     : Factor w/ 4 levels "3","4","5","6": 3 3 1 3 1 3 3 3 3 2 ...
##  $ preciom     : num [1:551] 320 780 180 520 380 395 460 390 780 420 ...
##  $ areaconst   : num [1:551] 150 380 120 455 300 165 319 357 380 265 ...
##  $ parqueaderos: num [1:551] 2 2 0 0 0 0 0 0 0 0 ...
##  $ banios      : num [1:551] 4 3 3 5 5 4 5 3 3 6 ...
##  $ habitaciones: num [1:551] 6 3 3 4 8 4 4 6 3 7 ...
##  $ longitud    : num [1:551] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:551] 3.48 3.49 3.47 3.46 3.47 ...
modelo <- lm(preciom ~  areaconst + estrato + habitaciones + parqueaderos + banios, data = df1)
residuos <- resid(modelo)
summary(modelo)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = df1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -860.47  -57.76  -13.63   35.43  942.86 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   54.33921   18.44101   2.947 0.003350 ** 
## areaconst      0.74602    0.04583  16.277  < 2e-16 ***
## estrato4      63.82907   17.84550   3.577 0.000379 ***
## estrato5     102.93561   16.93853   6.077 2.31e-09 ***
## estrato6     356.93216   33.57898  10.630  < 2e-16 ***
## habitaciones  -0.61195    4.66376  -0.131 0.895655    
## parqueaderos  18.33363    4.44531   4.124 4.30e-05 ***
## banios        22.41181    6.23423   3.595 0.000354 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 138.5 on 543 degrees of freedom
## Multiple R-squared:  0.6956, Adjusted R-squared:  0.6916 
## F-statistic: 177.2 on 7 and 543 DF,  p-value: < 2.2e-16

Estadísticamente notamos que obtenemos un R2 de 0.69, lo cual indica que nuestro modelo es relativamente bueno para explicar variabilidad en la variable de precio y que la variable “habitaciones” es estadísticamente no significativa debido al valor p 0.89 y que la inclusión de esta, no sería justificada.

Procedemos a revisar la media y mediana de esta variable junto a una prueba de normalidad.

mediahabitaciones <- mean(df1$habitaciones)
medianahabitaciones <- median(df1$habitaciones)
mediahabitaciones
## [1] 4.519056
medianahabitaciones
## [1] 4
normalidadhabitaciones <- shapiro.test(df1$habitaciones)
normalidadhabitaciones
## 
##  Shapiro-Wilk normality test
## 
## data:  df1$habitaciones
## W = 0.88102, p-value < 2.2e-16

Obtenemos un valor W de 0.88 por lo cual confirmamos que la variable habitaciones sigue una distribución normal con media 4.51 y mediana de 4. Lo que nos indica que independientemente las otras variables de las casas en zona norte, las habitaciones en el 95% de los casos, estarán en un valor cercano a la media

Creamos un nuevo modelo sin la variable “habitaciones”

modelo1 <- lm(preciom ~  areaconst + estrato + parqueaderos + banios, data = df1)
residuos1 <- resid(modelo1)
summary(modelo1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + parqueaderos + banios, 
##     data = df1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -861.26  -57.48  -13.45   35.65  942.99 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   53.14172   16.00996   3.319 0.000963 ***
## areaconst      0.74443    0.04417  16.855  < 2e-16 ***
## estrato4      64.38269   17.32388   3.716 0.000223 ***
## estrato5     103.62007   16.10075   6.436 2.70e-10 ***
## estrato6     358.18405   32.16594  11.136  < 2e-16 ***
## parqueaderos  18.29520    4.43164   4.128 4.23e-05 ***
## banios        21.95978    5.19119   4.230 2.74e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 138.4 on 544 degrees of freedom
## Multiple R-squared:  0.6956, Adjusted R-squared:  0.6922 
## F-statistic: 207.1 on 6 and 544 DF,  p-value: < 2.2e-16

Obtenemos el modelo: y= 53.14 + 0.74*areaconst + 64.38*estrato4 + 103.62*estrato5 + 358.18*estrato6 + 18.29*parqueaderos + 21.95*banios

Punto 4. Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).

  1. Linealidad. Gráfico de dispersión de residuos vs. valores ajustados
plot(modelo1, which = 1)

Análisis. Podemos observar el gráfico de dispersión de residuos vs. valores ajustados. En este gráfico, se puede apreciar que los puntos de dispersión se distribuyen aparentemente de manera aleatoria alrededor de la línea horizontal en y=0, sin mostrar patrones no lineales evidentes. La falta de una forma clara de embudo, curva o estructura en forma de U en los datos respalda la noción de que la relación entre las variables es lineal.

2. Homocedasticidad. Gráfico de residuos estandarizados vs. valores ajustados

plot(modelo1, which = 3)

Análisis. Se cumple el supuesto de homocedasticidad al observar que en el gráfico, la dispersión de los residuos se mantiene constante a medida que los valores ajustados cambian, lo que indica que la varianza de los residuos es uniforme en todos los niveles de predicción.

  1. Prueba Breush-Pagan
bptest(residuos ~ fitted(modelo1))
## 
##  studentized Breusch-Pagan test
## 
## data:  residuos ~ fitted(modelo1)
## BP = 71.283, df = 1, p-value < 2.2e-16

Análisis. La prueba de Breusch-Pagan muestra un valorBP de 71.28 y un p-value muy bajo (2.2e-16), lo que significa que el p-value es esencialmente cero. Esto indica que hay evidencia significativa de heterocedasticidad en el modelo. En otras palabras, la varianza de los residuos no es constante a lo largo de todo el rango de valores ajustados, lo que viola el supuesto de homocedasticidad en el modelo de regresión lineal.

  1. Normalidad. Gráfico de cuantiles de los residuos vs. cuantiles teóricos normales
qqnorm(residuos1)
qqline(residuos1)

Análisis. Se observa que los puntos se ajustan de manera aproximada a una linea diagonal, lo que nos sugiere que los residuos se distribuyen de manera similar a una distribución normal. Las desviaciones de la línea diagonal son mínimas y no se pueden ver patrones no lineales tan evidentes, por lo cual fortalece la conslución de que los residuos siguen una distribución normal.

Punto 5. Con el modelo identificado debe predecir el precio de la vivienda con las características de la primera solicitud.

solicitud1 <- data.frame(
  areaconst = 200,
  estrato = "4",
  habitaciones = 4,
  parqueaderos = 1,
  banios = 2
)
precio_solicitud1 <- predict(modelo1, newdata = solicitud1)
cat("El precio predicho de la vivienda estrato 4 es:", precio_solicitud1,"\n")
## El precio predicho de la vivienda estrato 4 es: 328.6259
solicitud1 <- data.frame(
  areaconst = 200,
  estrato = "5",
  habitaciones = 4,
  parqueaderos = 1,
  banios = 2
)
precio_solicitud1 <- predict(modelo1, newdata = solicitud1)
cat("El precio predicho de la vivienda estrato 5 es:", precio_solicitud1,"\n")
## El precio predicho de la vivienda estrato 5 es: 367.8633

Punto 6. Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 1. Tenga en cuenta que la empresa tiene crédito pre-aprobado de máximo 350 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.

ofertas_potenciales <- df1 %>%
  filter(areaconst >= 200,
         parqueaderos == 1,
         banios <= 2,
         habitaciones <= 4,
         estrato %in% c(4, 5),
         preciom <= 350)

# Mostrar las ofertas potenciales
ofertas_potenciales
## # A tibble: 3 × 13
##      id zona    tipo  barrio piso  estrato preciom areaconst parqueaderos banios
##   <dbl> <chr>   <chr> <chr>  <chr> <fct>     <dbl>     <dbl>        <dbl>  <dbl>
## 1  3586 Zona N… Casa  la me… 01    4           330       240            1      2
## 2  1924 Zona N… Casa  vipasa 01    4           320       264            1      2
## 3  1943 Zona N… Casa  vipasa 1     5           350       346            1      2
## # ℹ 3 more variables: habitaciones <dbl>, longitud <dbl>, latitud <dbl>
leaflet() %>% addTiles() %>% 
  setView(lng =  -76.51595234451665, lat = 3.436834062816008, zoom = 12)  %>%
  addCircleMarkers(lng = ofertas_potenciales$longitud,
                   lat = ofertas_potenciales$latitud,
                   label = as.character(paste0(ofertas_potenciales$tipo, " estrato:", ofertas_potenciales$estrato," ", "Baños:", ofertas_potenciales$banios," ", "Precio:",ofertas_potenciales$preciom, "'000.000", " ", " Pisos:", ofertas_potenciales$piso)), 
                   stroke = FALSE, 
                   fillOpacity = 0.5,
                   radius = 4,
                   color = 'green'
  )

Punto 7. Realice los pasos del 1 al 6. Para la segunda solicitud que tiene un crédito pre-aprobado por valor de $850 millones.

Mostrar los primeros 3 registros de la base filtrada

base2 = subset(df, tipo =="Apartamento" & zona=="Zona Sur")
head(base2, 3)
## # A tibble: 3 × 13
##      id zona    piso  estrato preciom areaconst parqueaderos banios habitaciones
##   <dbl> <chr>   <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
## 1  1724 Zona S… 01          5     240        87            1      3            3
## 2  4386 Zona S… 01          5     310       137            2      3            4
## 3  6857 Zona S… 03          3     100        49            0      1            2
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
leaflet() %>% addTiles() %>% 
  setView(lng =  -76.51595234451665, lat = 3.436834062816008, zoom = 12)  %>%
  addCircleMarkers(lng = base2$longitud,
                   lat = base2$latitud,
                   label = as.character(paste0(base2$tipo, " est:", base2$estrato, " Precio:",base2$preciom, "'000.000", " Pisos:", base2$piso)), 
                   stroke = FALSE, 
                   fillOpacity = 0.5,
                   radius = 4,
                   color = 'green'
  )

Creo mi nueva df con la información solo de la solicitud 2 y la reordeno

df2 = base2
head(df2,10)
## # A tibble: 10 × 13
##       id zona   piso  estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  1724 Zona … 01          5     240        87            1      3            3
##  2  4386 Zona … 01          5     310       137            2      3            4
##  3  6857 Zona … 03          3     100        49            0      1            2
##  4  6412 Zona … 05          6     620       135            2      3            4
##  5  1770 Zona … 06          5     170        56            1      1            2
##  6  1353 Zona … 1           4     220        75            0      2            3
##  7  1391 Zona … 1           4     162        60            0      2            3
##  8  1489 Zona … 1           5     225        65            0      2            3
##  9  1490 Zona … 1           5     250        75            0      2            3
## 10  1492 Zona … 1           5     325       107            0      2            3
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>

Realizo el análisis exploratorio de datos

df2 <- df2 %>% select(id, zona, tipo, barrio, piso, estrato, preciom, areaconst, parqueaderos, banios, habitaciones, longitud, latitud)
ggpairs(df2[,7:11], title="Análisis exploratorio de datos")

Observamos una buena correlación entre precio y las variables independientes: areacosnt (0.773), parqueaderos(0.67), banios(0.74)

Convertimos “estrato” en factor, creo el modelo y un resumen de él

df2$estrato <- factor(df2$estrato)
str(df2)
## tibble [2,164 × 13] (S3: tbl_df/tbl/data.frame)
##  $ id          : num [1:2164] 1724 4386 6857 6412 1770 ...
##  $ zona        : chr [1:2164] "Zona Sur" "Zona Sur" "Zona Sur" "Zona Sur" ...
##  $ tipo        : chr [1:2164] "Apartamento" "Apartamento" "Apartamento" "Apartamento" ...
##  $ barrio      : chr [1:2164] "acopi" "acopi" "acopi" "acopi" ...
##  $ piso        : chr [1:2164] "01" "01" "03" "05" ...
##  $ estrato     : Factor w/ 4 levels "3","4","5","6": 3 3 1 4 3 2 2 3 3 3 ...
##  $ preciom     : num [1:2164] 240 310 100 620 170 220 162 225 250 325 ...
##  $ areaconst   : num [1:2164] 87 137 49 135 56 75 60 65 75 107 ...
##  $ parqueaderos: num [1:2164] 1 2 0 2 1 0 0 0 0 0 ...
##  $ banios      : num [1:2164] 3 3 1 3 1 2 2 2 2 2 ...
##  $ habitaciones: num [1:2164] 3 4 2 4 2 3 3 3 3 3 ...
##  $ longitud    : num [1:2164] -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num [1:2164] 3.37 3.38 3.38 3.34 3.37 ...
modelo2 <- lm(preciom ~  areaconst + estrato + habitaciones + parqueaderos + banios, data = df2)
residuos2 <- resid(modelo2)
summary(modelo2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = df2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1219.38   -38.00     0.26    33.06   873.18 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -18.46671   13.00872  -1.420 0.155879    
## areaconst      1.45787    0.05404  26.977  < 2e-16 ***
## estrato4      17.53434    9.38919   1.868 0.061967 .  
## estrato5      33.07259    9.68612   3.414 0.000651 ***
## estrato6     179.61965   11.82556  15.189  < 2e-16 ***
## habitaciones -17.75743    3.98827  -4.452 8.92e-06 ***
## parqueaderos  49.04515    3.41023  14.382  < 2e-16 ***
## banios        49.75506    3.61529  13.762  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 96.85 on 2156 degrees of freedom
## Multiple R-squared:  0.788,  Adjusted R-squared:  0.7873 
## F-statistic:  1145 on 7 and 2156 DF,  p-value: < 2.2e-16

Estadísticamente notamos que obtenemos un R2 de 0.788, lo cual indica que nuestro modelo es relativamente bueno para explicar variabilidad en la variable de precio y que la variable “estrato4” es estadísticamente no significativa debido al valor p 0.061 pero al ser una variable categorica, no la eliminamos de nuestro modelo.

Nuestro modelo qieda de la siguiente forma: preciom= -18.46 + 1.45*areaconst + 17.53*estrato4 + 33.07*estrato5 + 179.61*estrato6 - 17.75*habitaciones + 49.04*parqueaderos + 49.75*banios

Validamos supuestos del modelo

  • Linealidad. Gráfico de dispersión de residuos vs. valores ajustados
plot(modelo2, which = 1)

Como en el caso 1, también se puede apreciar que los puntos de dispersión se distribuyen aparentemente de manera aleatoria alrededor de la línea horizontal en y=0, sin mostrar patrones no lineales evidentes.

  • Homocedasticidad. Gráfico de residuos estandarizados vs. valores ajustados
plot(modelo2, which = 3)

También se cumple el supuesto de homocedasticidad al observar que en el gráfico, la dispersión de los residuos se mantiene constante a medida que los valores ajustados cambian.

  • Test de Breusch-Pagan para homocedasticidad
bptest(residuos2 ~ fitted(modelo2))
## 
##  studentized Breusch-Pagan test
## 
## data:  residuos2 ~ fitted(modelo2)
## BP = 313.78, df = 1, p-value < 2.2e-16

Presenta un BP de 313.78 y un p-value muy bajo (2.2e-16), lo que significa que el p-value es esencialmente cero. Esto indica que hay evidencia significativa de heterocedasticidad en el modelo.

  • Normalidad. Gráfico de cuantiles de los residuos vs. cuantiles teóricos normales
qqnorm(residuos2)
qqline(residuos2)

Se observa que los puntos se ajustan de manera aproximada a una linea diagonal, lo que nos sugiere que los residuos se distribuyen de manera similar a una distribución normal.

solicitud2 <- data.frame(
  areaconst = 300,
  estrato = "5",
  habitaciones = 5,
  parqueaderos = 3,
  banios = 3
)
precio_solicitud2 <- predict(modelo2, newdata = solicitud2)
cat("El precio predicho de la vivienda estrato 5 en la zona sur es:", precio_solicitud2,"\n")
## El precio predicho de la vivienda estrato 5 en la zona sur es: 659.5818
solicitud2 <- data.frame(
  areaconst = 300,
  estrato = "6",
  habitaciones = 5,
  parqueaderos = 3,
  banios = 3
)
precio_solicitud2 <- predict(modelo2, newdata = solicitud2)
cat("El precio predicho de la vivienda estrato 6 en la zona sur es:", precio_solicitud2,"\n")
## El precio predicho de la vivienda estrato 6 en la zona sur es: 806.1289

Ofertas potenciales para la solicitud 2

ofertas_potenciales2 <- df2 %>%
  filter(areaconst >= 300,
         parqueaderos >= 3,
         banios >= 3,
         habitaciones <= 5,
         estrato %in% c(5, 6),
         preciom <= 850)

ofertas_potenciales2
## # A tibble: 1 × 13
##      id zona    tipo  barrio piso  estrato preciom areaconst parqueaderos banios
##   <dbl> <chr>   <chr> <chr>  <chr> <fct>     <dbl>     <dbl>        <dbl>  <dbl>
## 1  5574 Zona S… Apar… pance  1     6           850       352            4      3
## # ℹ 3 more variables: habitaciones <dbl>, longitud <dbl>, latitud <dbl>
leaflet() %>% addTiles() %>% 
  setView(lng =  -76.51595234451665, lat = 3.436834062816008, zoom = 12)  %>%
  addCircleMarkers(lng = ofertas_potenciales2$longitud,
                   lat = ofertas_potenciales2$latitud,
                   label = as.character(paste0(ofertas_potenciales2$tipo, " estrato:", ofertas_potenciales2$estrato," ", "Baños:", ofertas_potenciales2$banios," ", "Precio:",ofertas_potenciales2$preciom, "'000.000", " ", " Pisos:", ofertas_potenciales2$piso)), 
                   stroke = FALSE, 
                   fillOpacity = 0.5,
                   radius = 4,
                   color = 'green'
  )