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:
# Create a data frame with the table data
table_data <- data.frame(
Características = c("Tipo", "área construida", "parqueaderos", "baños", "habitaciones", "estrato", "zona", "crédito preaprobado"),
Vivienda_1 = c("Casa", "200", "1", "2", "4", "4 o 5", "Norte", "350 millones"),
Vivienda_2 = c("Apartamento", "300", "3", "3", "5", "5 o 6", "Sur", "850 millones")
)
kable(table_data, caption = "Comparación de Viviendas")
| 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) .
Se llevó a cabo un análisis estadístico riguroso para identificar las mejores opciones de selección de ofertas en el proceso de adquisición de la vivienda. Para ello, se realizó una limpieza de datos y se estructuró la información registrada en la fuente de datos.
Adicionalmente, se realizó una segmentación de datos para el entrenamiento de modelos de regresión lineal múltiple en las categorías: \(zona norte - casas\) y \(zona sur - apartamentos\), asegurando que las ofertas utilizadas estén correctamente ubicadas en el sector correspondiente.
Ofertas zona norte casas
Del total de 700 ofertas disponibles en la zona norte con tipo de vivienda casas, se realizó una limpieza de datos para excluir aquellas ubicadas fuera de la zona, obteniendo un total de 449 ofertas válidas.
Ofertas zona sur apartamentos
Del total de 2777 ofertas disponibles en la zona sur con tipo de vivienda sur, se realizó una limpieza de datos para excluir aquellas ubicadas fuera de la zona, obteniendo un total de 2214 ofertas válidas.
Modelo de regresión lineal multiple zona norte casas
Se generó un modelo de regresión lineal multiple \(log - ling\) el cual obtuvo un \(Adjusted R2 = 0.758\)
\[\begin{align*} precio = 4.8123353 + 0.0013657 \cdot areaconstruida + 0.0816912 \cdot banios + 0.2766516 \cdot e4 + \\ 0.4192394 \cdot e5 + 0.6710490 \cdot e6 + 0.0377740 \cdot parqueaderos + 0.0256739 \cdot habitaciones \end{align*}\]
Modelo de regresión lineal multiple zona norte casas
Se generó un modelo de regresión lineal multiple \(log - ling\) el cual obtuvo un \(Adjusted R2 = 0.821\)
\[ \begin{align*} precio = 4.387416 + 0.002226 \cdot areaconstruida + 0.111078 \cdot banios + 0.282537 \cdot e4 + \\ 0.462540 \cdot e5 + 0.784609 \cdot e6 + 0.158962 \cdot parqueaderos + 0.019957 \cdot habitaciones \end{align*} \]
Para la vivienda tipo casa en la zona norte, se recomienda al cliente adquirir una propiedad en el barrio La Merced, ya que se identificaron tres ofertas que cumplen con todas las condiciones requeridas, incluyendo un precio máximo acorde con el valor del crédito preaprobado. Además, los predios seleccionados son comparables con base en un análisis de mercado. Ofertas 937, 1108 y 1163.
Para la vivienda tipo apartamento en la zona sur, se recomienda al cliente adquirir el predio ubicado en el barrio Pance, con un valor de 850 millones, ya que cumple con todas las condiciones requeridas, especialmente la área construida. Este inmueble es el único que satisface la exigencia de 300 metros cuadrados, sin haberse identificado otra oferta con dicha característica. Oferta con id 5574.
El conjunto de datos analiza la dinámica inmobiliaria en la ciudad de Cali y está compuesto por 8,322 observaciones y 13 variables. Estas incluyen características físicas de las propiedades, como el número de habitaciones, baños, área construida y parqueaderos, además de información geoespacial, como la zona, el barrio, la latitud y la longitud. Asimismo, se incluyen variables económicas como el estrato socioeconómico y el precio de venta, junto con el tipo de vivienda (casa o apartamento). Esta estructuración permite un análisis integral del mercado inmobiliario en la ciudad.
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")=
.. cols(
.. id = col_double(),
.. zona = col_character(),
.. piso = col_character(),
.. estrato = col_double(),
.. preciom = col_double(),
.. areaconst = col_double(),
.. parqueaderos = col_double(),
.. banios = col_double(),
.. habitaciones = col_double(),
.. tipo = col_character(),
.. barrio = col_character(),
.. longitud = col_double(),
.. latitud = col_double()
.. )
- attr(*, "problems")=<externalptr>
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>
tabla_variables <- data.frame(
Variable = c("id", "zona", "piso", "estrato", "precio", "area construida",
"parqueaderos", "banios", "habitaciones", "tipo", "barrio",
"longitud", "latitud"),
Tipo = c("Cuantitativa(Discreta)", "Cualitativa(Nominal)",
"Cuantitativa(Discreta)", "Cualitativa(Ordinal)",
"Cuantitativa(Discreta)", "Cuantitativa(Continua)",
"Cuantitativa(Discreta)", "Cuantitativa(Discreta)",
"Cuantitativa(Discreta)", "Cualitativa(Nominal)",
"Cualitativa(Nominal)", "Cuantitativa(Continua)",
"Cuantitativa(Continua)"))
tabla_variables
Variable Tipo
1 id Cuantitativa(Discreta)
2 zona Cualitativa(Nominal)
3 piso Cuantitativa(Discreta)
4 estrato Cualitativa(Ordinal)
5 precio Cuantitativa(Discreta)
6 area construida Cuantitativa(Continua)
7 parqueaderos Cuantitativa(Discreta)
8 banios Cuantitativa(Discreta)
9 habitaciones Cuantitativa(Discreta)
10 tipo Cualitativa(Nominal)
11 barrio Cualitativa(Nominal)
12 longitud Cuantitativa(Continua)
13 latitud Cuantitativa(Continua)
El análisis de valores faltantes revela que las principales variables afectadas son piso y parqueaderos, con 2,638 y 1,605 datos ausentes, respectivamente, además de algunas ausencias menores en otras columnas. Para su tratamiento, se puede optar por la imputación con la mediana en variables numéricas y la moda en categóricas, o bien eliminar registros incompletos si representan una fracción pequeña del total, asegurando así la integridad del análisis sin distorsionar los resultados.
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
Se realizó una limpieza y transformación de datos para garantizar la
calidad del insumo. Primero, se eliminaron registros completamente
vacíos y aquellos sin identificador único. Luego, se normalizaron las
variables categóricas estandarizando nomenclaturas en minúsculas.
Posteriormente, se imputaron valores faltantes en piso
utilizando la mediana por tipo de vivienda, mientras que los valores
nulos en parqueaderos se reemplazaron por cero. Finalmente,
se filtraron registros inconsistentes eliminando aquellos sin
habitaciones o baños y asegurando la presencia de al menos una variable
relevante con valores mayores a cero, obteniendo así un dataset
completamente limpio y sin valores faltantes, listo para el
análisis.
# 1. Limpieza de valores NA y registros no válidos
vivienda <- vivienda[rowSums(is.na(vivienda)) != ncol(vivienda),] # Eliminar filas completamente vacías
vivienda <- vivienda[!is.na(vivienda$id),] # Eliminar registros sin identificador único
# 2. Normalización de datos categóricos
vivienda$zona <- tolower(vivienda$zona) # Convertir zonas a minúsculas
vivienda$tipo <- tolower(vivienda$tipo) # Convertir tipo de vivienda a minúsculas
vivienda$tipo[vivienda$tipo == "apto"] <- "apartamento" # Unificar nomenclatura
vivienda$barrio <- tolower(vivienda$barrio) # Convertir barrios a minúsculas
# 3. Transformaciones y limpieza de variables numéricas
vivienda$piso <- as.numeric(vivienda$piso) # Convertir a numérico
vivienda$parqueaderos[is.na(vivienda$parqueaderos)] <- 0 # Reemplazar NA en parqueaderos por 0
# 4. Filtrado de datos inconsistentes o irrelevantes
vivienda <- vivienda[vivienda$habitaciones != 0,] # Eliminar registros sin habitaciones
vivienda <- vivienda[vivienda$banios != 0,] # Eliminar registros sin baños
vivienda <- vivienda[rowSums(vivienda[,c("parqueaderos", "banios", "habitaciones")] == 0) < 3,] # Mantener registros con al menos una de estas variables > 0
vivienda <- vivienda[rowSums(vivienda[,c("banios", "habitaciones")] == 0) < 2,] # Mantener registros con al menos una de estas variables > 0
# Calcular la mediana del piso por tipo de vivienda
vivienda <- vivienda %>%
group_by(tipo) %>%
mutate(piso = ifelse(is.na(piso), median(piso, na.rm = TRUE), piso)) %>%
ungroup()
colSums(is.na(vivienda))
id zona piso estrato preciom areaconst
0 0 0 0 0 0
parqueaderos banios habitaciones tipo barrio longitud
0 0 0 0 0 0
latitud
0
Se realizó un tratamiento a la variable barrio con el
objetivo de corregir inconsistencias en la nomenclatura. Primero, se
normalizaron los valores convirtiéndolos a minúsculas, eliminando tildes
y espacios adicionales. Luego, se aplicó una lista de correcciones para
unificar nombres que presentaban variaciones en su escritura. Como
resultado, el número de barrios distintos se redujo de
437 a 386, mejorando la coherencia y
calidad del dataset para un análisis más preciso.
# Cargar el paquete stringr
library(stringr)
normalize_barrio <- function(barrio) {
barrio <- tolower(barrio) # Convertir a minúsculas
barrio <- str_replace_all(barrio, "[áéíóú]", function(x) chartr("áéíóú", "aeiou", x)) # Reemplazar tildes
barrio <- str_trim(barrio) # Eliminar espacios en blanco adicionales
return(barrio)
}
# Aplicar la función a la columna 'barrio'
vivienda <- vivienda %>%
mutate(barrio = normalize_barrio(barrio))
# Definir la lista de correcciones
correcciones <- list(
"meléndez" = "melendez",
"ciudad meléndez" = "ciudad melendez",
"juanamb√∫" = "juanambu",
"el trébol" = "el trebol",
"las américas" = "las americas",
"rep√∫blica de israel" = "republica de israel",
"base aérea" = "base aerea",
"alférez real" = "alferez real"
)
# Corregir los nombres en la columna 'barrio'
vivienda$barrio <- sapply(vivienda$barrio, function(barrio) {
if (barrio %in% names(correcciones)) {
return(correcciones[[barrio]])
} else {
return(barrio)
}
})
vivienda$estrato <- as.factor(vivienda$estrato)
Se realizó un filtrado de datos seleccionando las ofertas clasificadas en la zona norte y tipo de vivienda casa.
base1 <- vivienda[vivienda$zona == "zona norte" & vivienda$tipo == "casa",]
kable(head(base1, 3), caption = "Primeros 3 Registros de Casas en Zona Norte")
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1209 | zona norte | 2 | 5 | 320 | 150 | 2 | 4 | 6 | casa | acopi | -76.51341 | 3.47968 |
| 1592 | zona norte | 2 | 5 | 780 | 380 | 2 | 3 | 3 | casa | acopi | -76.51674 | 3.48721 |
| 4057 | zona norte | 2 | 6 | 750 | 445 | 0 | 7 | 6 | casa | acopi | -76.52950 | 3.38527 |
library(leaflet)
library(RColorBrewer)
pal <- colorNumeric(
palette = rev(brewer.pal(9, "RdYlBu")), # Puedes cambiar la paleta de colores
domain = base1$preciom
)
leaflet(data = base1) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = ~sqrt(preciom)/10,
color = ~pal(preciom),
popup = ~paste("Precio:", preciom)) %>%
addLegend(
"bottomright",
pal = pal,
values = ~preciom,
title = "Precio")
Se identificó que, de las 700 ofertas relacionadas en la zona norte con tipo de vivienda casa, algunas se encuentran ubicadas en otras zonas de la ciudad de Cali. Esta situación se debe principalmente a una incorrecta georreferenciación durante la clasificación de las ofertas en dicha zona.
Con el fin de limpiar las ofertas que se encuentran por fuera de la zona norte, se realizó un filtro a partir de las coordenadas limítrofes de la zona de norte de la ciudad de Cali, estas son coordenadas mínimas \(longitud = -76.52732195\) \(latitud = 3.4369546\) y coordenadas máximas \(longitud = -76.46485570\) \(latitud = 3.51233553\)
base1_limpia <- base1[base1$longitud >= -76.52732195 & base1$latitud >= 3.4369546 & base1$longitud <= -76.46485570 & base1$latitud <= 3.51233553,]
pal <- colorNumeric(
palette = rev(brewer.pal(9, "RdYlBu")), # Puedes cambiar la paleta de colores
domain = base1$preciom
)
leaflet(data = base1_limpia) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = ~sqrt(preciom)/20,
color = ~pal(preciom),
#fillOpacity = 0.2,
#clusterOptions = markerClusterOptions(),
popup = ~paste("Precio:", preciom)) %>%
addLegend(
"bottomright",
pal = pal,
values = ~preciom,
title = "Precio")
library(GGally)
quant_vars <- base1_limpia %>%
select(preciom, estrato, areaconst,parqueaderos, banios, habitaciones)
ggpairs(quant_vars, title = " ")
- Se tiene una alta correlación (0.726) entre el area construida y el
precio de la vivienda en el resto de variables no se tiene una alta
correlación.
Se realizó una revisión de colinealidad con el análisis de factor de varianza (VIF).
vif(lm(preciom ~ areaconst + estrato + banios + parqueaderos, data =base1_limpia))
GVIF Df GVIF^(1/(2*Df))
areaconst 1.530232 1 1.237025
estrato 1.512030 3 1.071339
banios 1.480292 1 1.216673
parqueaderos 1.334996 1 1.155420
Dado que todos los valores están por debajo de 5 Se pueden mantener todas las variables en el modelo de regresión múltiple sin problemas.
Se realizó la estimación de dos modelos \(1) lin - lin\), \(2)log - lin\) y se comparó su rendimiento para determinar cual es el que tiene mejor ajustes para la estimación.
model_1 <- lm(preciom ~ areaconst + banios + estrato + parqueaderos + habitaciones,data = base1_limpia)
model_2 <- lm(log(preciom) ~ areaconst + banios + estrato + parqueaderos + habitaciones,data = base1_limpia)
stargazer(model_1,model_2,type = "text")
===========================================================
Dependent variable:
----------------------------
preciom log(preciom)
(1) (2)
-----------------------------------------------------------
areaconst 0.591*** 0.001***
(0.045) (0.0001)
banios 28.394*** 0.082***
(5.534) (0.013)
estrato4 65.146*** 0.277***
(14.968) (0.036)
estrato5 117.805*** 0.419***
(14.777) (0.035)
estrato6 335.935*** 0.671***
(50.713) (0.121)
parqueaderos 15.608*** 0.038***
(3.910) (0.009)
habitaciones 0.618 0.026**
(4.248) (0.010)
Constant 56.110*** 4.812***
(16.045) (0.038)
-----------------------------------------------------------
Observations 449 449
R2 0.695 0.761
Adjusted R2 0.690 0.758
Residual Std. Error (df = 441) 107.619 0.256
F Statistic (df = 7; 441) 143.614*** 200.930***
===========================================================
Note: *p<0.1; **p<0.05; ***p<0.01
Como resultado, se obtuvo que el \(modelo2\) \(2)log - lin\) tiene un mejor ajuste en todas las variables se tiene un \(Adjusted R2 = 0.758\)
summary(model_2)
Call:
lm(formula = log(preciom) ~ areaconst + banios + estrato + parqueaderos +
habitaciones, data = base1_limpia)
Residuals:
Min 1Q Median 3Q Max
-1.48673 -0.15191 -0.01026 0.14091 1.11204
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.8123353 0.0382240 125.898 < 2e-16 ***
areaconst 0.0013657 0.0001075 12.704 < 2e-16 ***
banios 0.0816912 0.0131841 6.196 1.33e-09 ***
estrato4 0.2766516 0.0356588 7.758 6.04e-14 ***
estrato5 0.4192394 0.0352021 11.909 < 2e-16 ***
estrato6 0.6710490 0.1208116 5.555 4.82e-08 ***
parqueaderos 0.0377740 0.0093151 4.055 5.92e-05 ***
habitaciones 0.0256739 0.0101200 2.537 0.0115 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.2564 on 441 degrees of freedom
Multiple R-squared: 0.7613, Adjusted R-squared: 0.7575
F-statistic: 200.9 on 7 and 441 DF, p-value: < 2.2e-16
par(mfrow= c(2,2))
plot(model_2)
### Paso 4. Validación de supuestos
shapiro.test(residuals(model_2))
Shapiro-Wilk normality test
data: residuals(model_2)
W = 0.9687, p-value = 3.332e-08
Dado el p-valor obtiene un valor menor al nivel de significancia (0.05), los residuos del modelo no tienen una distribución normal.
library(lmtest)
dwtest(model_2)
Durbin-Watson test
data: model_2
DW = 1.5587, p-value = 8.973e-07
alternative hypothesis: true autocorrelation is greater than 0
Dado el p-valor obtiene un valor menor al nivel de significancia (0.05), los errores del modelo no son independientes.
gqtest(model_2)
Goldfeld-Quandt test
data: model_2
GQ = 1.1095, df1 = 217, df2 = 216, p-value = 0.2226
alternative hypothesis: variance increases from segment 1 to 2
Dado el p-valor obtiene un valor menor al nivel de significancia (0.05), se puede afirmar que la varianza de los errores no es constante.
Al realizar la estimación del valor de la vivienda con el modelo seleccionado se cumple con todas las condiciones y características de la solicitud del usuario, una vivienda en estrato 4 tendría un valor estimado de \(288 millones\) y en estrato 5 de alrededor de \(333 millones\)
modeloprecio <- function(ac,b,e4,e5,e6,p,h){
nprecio = 4.8123353 + 0.0013657*ac + 0.0816912*b + 0.2766516*e4 + 0.4192394*e5 + 0.6710490*e6 + 0.0377740*p + 0.0256739*h
return(nprecio)}
exp(modeloprecio(200,2,1,0,0,1,4)) # estrato 4
[1] 288.8706
exp(modeloprecio(200,2,0,1,0,1,4)) # estrato 5
[1] 333.1413
Se realizó la selección de 8 posibles ofertas potenciales para el cliente de casas en la zona norte de Cali, las cuales tengan como minino los 200 metros de área construida, 4 habitaciones, máximo 3 baños y minio un parqueadero en los estratos 4 y 5. El resultado son estás ofertas:
ofertas_base1 <- base1_limpia %>%
filter(as.numeric(as.character(estrato)) < 6 & as.numeric(as.character(estrato)) >= 4,
areaconst >= 200,
parqueaderos >= 1,
banios <= 3,
habitaciones == 4,
preciom <= 350)
kable(head(ofertas_base1), caption = "Ofertas de casas zona norte")
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 819 | zona norte | 2 | 5 | 350 | 264 | 2 | 3 | 4 | casa | la flora | -76.50330 | 3.46412 |
| 937 | zona norte | 2 | 4 | 350 | 280 | 2 | 3 | 4 | casa | la merced | -76.50603 | 3.46643 |
| 1108 | zona norte | 2 | 4 | 330 | 260 | 1 | 3 | 4 | casa | la merced | -76.51060 | 3.48108 |
| 1163 | zona norte | 2 | 5 | 350 | 216 | 2 | 2 | 4 | casa | la merced | -76.51218 | 3.48181 |
| 1887 | zona norte | 1 | 5 | 340 | 203 | 2 | 3 | 4 | casa | vipasa | -76.51803 | 3.48257 |
| 1842 | zona norte | 2 | 5 | 350 | 240 | 2 | 3 | 4 | casa | vipasa | -76.51800 | 3.48100 |
pal <- colorNumeric(
palette = "blue", # Puedes cambiar la paleta de colores
domain = base1$preciom
)
leaflet(data = ofertas_base1) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = ~sqrt(preciom)/5,
color = ~pal(preciom),
#fillOpacity = 0.2,
#clusterOptions = markerClusterOptions(),
popup = ~paste("Precio:", preciom)) %>%
addLegend(
"bottomright",
pal = pal,
values = ~preciom,
title = "Precio")
Se realizó un filtrado de datos seleccionando las ofertas clasificadas en la zona sur y tipo de vivienda apartamento.
base2 <- vivienda[vivienda$zona == "zona sur" & vivienda$tipo == "apartamento",]
kable(head(base2, 3), caption = "Primeros 3 Registros de Casas en Zona Norte")
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 5098 | zona sur | 5 | 4 | 290 | 96 | 1 | 2 | 3 | apartamento | acopi | -76.53464 | 3.44987 |
| 698 | zona sur | 2 | 3 | 78 | 40 | 1 | 1 | 2 | apartamento | aguablanca | -76.50100 | 3.40000 |
| 8199 | zona sur | 4 | 6 | 875 | 194 | 2 | 5 | 3 | apartamento | aguacatal | -76.55700 | 3.45900 |
library(leaflet)
library(RColorBrewer)
pal <- colorNumeric(
palette = rev(brewer.pal(9, "RdYlBu")), # Puedes cambiar la paleta de colores
domain = base1$preciom
)
leaflet(data = base2) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = ~sqrt(preciom)/10,
color = ~pal(preciom),
popup = ~paste("Precio:", preciom)) %>%
addLegend(
"bottomright",
pal = pal,
values = ~preciom,
title = "Precio")
Se identificó que, de las 2777 ofertas relacionadas en la zona sur con tipo de vivienda apartamento, algunas se encuentran ubicadas en otras zonas de la ciudad de Cali. Esta situación se debe principalmente a una incorrecta georreferenciación durante la clasificación de las ofertas en dicha zona.
Con el fin de limpiar las ofertas que se encuentran por fuera de la zona sur, se realizó un filtro a partir de las coordenadas limítrofes de la zona de sur de la ciudad de Cali, estas son coordenadas mínimas \(longitud = -76.60063914\) \(latitud = 3.30352817\) y coordenadas máximas \(longitud = -76.49858161\) \(latitud = 3.41262415\)
base2_limpia <- base2[base2$longitud >= -76.60063914 & base2$latitud >= 3.30352817 & base2$longitud <= -76.49858161 & base2$latitud <= 3.41262415,]
pal <- colorNumeric(
palette = rev(brewer.pal(9, "RdYlBu")), # Puedes cambiar la paleta de colores
domain = base1$preciom
)
leaflet(data = base2_limpia) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = ~sqrt(preciom)/20,
color = ~pal(preciom),
#fillOpacity = 0.2,
#clusterOptions = markerClusterOptions(),
popup = ~paste("Precio:", preciom)) %>%
addLegend(
"bottomright",
pal = pal,
values = ~preciom,
title = "Precio")
library(GGally)
quant_vars <- base2_limpia %>%
select(preciom, estrato, areaconst,parqueaderos, banios, habitaciones)
ggpairs(quant_vars, title = " ")
- Se tiene una alta correlación (0.751) entre el área construida y el
precio. - Se tiene una alta correlación (0.706) entre el número de
parqueaderos y el precio. - Se tiene una alta correlación (0.706) entre
el número de baños y el precio.
Se realizó una revisión de colinealidad con el análisis de factor de varianza (VIF).
vif(lm(preciom ~ areaconst + estrato + banios + parqueaderos, data =base2_limpia))
GVIF Df GVIF^(1/(2*Df))
areaconst 2.078719 1 1.441776
estrato 1.826155 3 1.105579
banios 2.386784 1 1.544922
parqueaderos 1.953618 1 1.397719
Dado que todos los valores están por debajo de 5 Se pueden mantener todas las variables en el modelo de regresión múltiple sin problemas.
Se realizó la estimación de dos modelos \(1) lin - lin\), \(2)log - lin\) y se comparó su rendimiento para determinar cual es el que tiene mejor ajustes para la estimación.
b2_model_1 <- lm(preciom ~ areaconst + banios + estrato + parqueaderos + habitaciones,data = base2_limpia)
b2_model_2 <- lm(log(preciom) ~ areaconst + banios + estrato + parqueaderos + habitaciones,data = base2_limpia)
stargazer(b2_model_1,b2_model_2,type = "text")
============================================================
Dependent variable:
----------------------------
preciom log(preciom)
(1) (2)
------------------------------------------------------------
areaconst 1.269*** 0.002***
(0.052) (0.0001)
banios 46.114*** 0.111***
(3.461) (0.008)
estrato4 17.965** 0.283***
(8.705) (0.021)
estrato5 31.794*** 0.463***
(8.966) (0.021)
estrato6 183.966*** 0.785***
(11.015) (0.026)
parqueaderos 54.117*** 0.159***
(3.564) (0.008)
habitaciones -15.510*** 0.020**
(3.876) (0.009)
Constant -10.804 4.387***
(12.433) (0.029)
------------------------------------------------------------
Observations 2,214 2,214
R2 0.783 0.822
Adjusted R2 0.783 0.821
Residual Std. Error (df = 2206) 91.828 0.217
F Statistic (df = 7; 2206) 1,139.039*** 1,451.127***
============================================================
Note: *p<0.1; **p<0.05; ***p<0.01
Como resultado, se obtuvo que el \(modelo2\) \(2)log - lin\) tiene un mejor ajuste en todas las variables se tiene un \(Adjusted R2 = 0.821\)
summary(b2_model_2)
Call:
lm(formula = log(preciom) ~ areaconst + banios + estrato + parqueaderos +
habitaciones, data = base2_limpia)
Residuals:
Min 1Q Median 3Q Max
-1.77620 -0.13805 -0.00499 0.14488 1.15616
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.387416 0.029393 149.267 <2e-16 ***
areaconst 0.002226 0.000124 17.946 <2e-16 ***
banios 0.111078 0.008183 13.574 <2e-16 ***
estrato4 0.282537 0.020580 13.729 <2e-16 ***
estrato5 0.462540 0.021197 21.821 <2e-16 ***
estrato6 0.784609 0.026041 30.129 <2e-16 ***
parqueaderos 0.158962 0.008426 18.867 <2e-16 ***
habitaciones 0.019957 0.009164 2.178 0.0295 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.2171 on 2206 degrees of freedom
Multiple R-squared: 0.8216, Adjusted R-squared: 0.821
F-statistic: 1451 on 7 and 2206 DF, p-value: < 2.2e-16
par(mfrow= c(2,2))
plot(b2_model_2)
### Paso 4. Validación de supuestos
shapiro.test(residuals(b2_model_2))
Shapiro-Wilk normality test
data: residuals(b2_model_2)
W = 0.97835, p-value < 2.2e-16
Dado el p-valor obtiene un valor menor al nivel de significancia (0.05), los residuos del modelo no tienen una distribución normal.
library(lmtest)
dwtest(b2_model_2)
Durbin-Watson test
data: b2_model_2
DW = 1.6209, p-value < 2.2e-16
alternative hypothesis: true autocorrelation is greater than 0
Dado el p-valor obtiene un valor menor al nivel de significancia (0.05), los errores del modelo no son independientes.
gqtest(b2_model_2)
Goldfeld-Quandt test
data: b2_model_2
GQ = 0.7842, df1 = 1099, df2 = 1099, p-value = 1
alternative hypothesis: variance increases from segment 1 to 2
Dado el p-valor obtiene un valor mayor al nivel de significancia (0.05), se puede afirmar que la varianza de los errores es constante.
Al realizar la estimación del valor de la vivienda con el modelo seleccionado se cumple con todas las condiciones y características de la solicitud del usuario, superando en tal solo \(3 millones\) el valor de la vivienda con todas las caracteristicas para el estrato 6. Una vivienda en estrato 5 tendría un valor estimado de \(618 millones\) y en estrato 6 de alrededor de \(853 millones\). En este caso la diferencia de estrato si marca una clara diferencia en el valor del inmueble.
b2_modeloprecio <- function(ac,b,e4,e5,e6,p,h){
nprecio = 4.387416 + 0.002226*ac + 0.111078*b + 0.282537*e4 + 0.462540*e5 + 0.784609*e6 + 0.158962*p + 0.019957*h
return(nprecio)}
exp(b2_modeloprecio(300,3,0,1,0,3,5)) # estrato 5
[1] 618.7251
exp(b2_modeloprecio(300,3,0,0,1,3,5)) # estrato 6
[1] 853.8282
Se realizó la selección de 8 posibles ofertas potenciales para el cliente de casas en la zona norte de Cali, las cuales tengan como minino los 200 metros de área construida, 4 habitaciones, máximo 3 baños y minio un parqueadero en los estratos 4 y 5. El resultado son estás ofertas:
ofertas_base2 <- base2_limpia %>%
filter(as.numeric(as.character(estrato)) <= 6 & as.numeric(as.character(estrato)) > 4,
areaconst >= 200,
banios <= 4,
preciom <= 850 & preciom >= 700)
kable(head(ofertas_base2), caption = "Ofertas de casas zona norte")
| id | zona | piso | estrato | preciom | areaconst | parqueaderos | banios | habitaciones | tipo | barrio | longitud | latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3848 | zona sur | 12 | 6 | 760 | 200 | 2 | 3 | 3 | apartamento | ciudad jardin | -76.52897 | 3.36403 |
| 4133 | zona sur | 12 | 6 | 760 | 200 | 2 | 2 | 3 | apartamento | ciudad jardin | -76.52999 | 3.36550 |
| 3603 | zona sur | 1 | 6 | 833 | 213 | 2 | 3 | 3 | apartamento | ciudad jardin pance | -76.52726 | 3.34865 |
| 4266 | zona sur | 5 | 6 | 700 | 250 | 2 | 4 | 5 | apartamento | el ingenio | -76.53043 | 3.37062 |
| 3827 | zona sur | 2 | 6 | 820 | 213 | 2 | 3 | 3 | apartamento | pance | -76.52888 | 3.35064 |
| 5574 | zona sur | 4 | 6 | 850 | 352 | 4 | 3 | 3 | apartamento | pance | -76.53729 | 3.34265 |
pal <- colorNumeric(
palette = "blue", # Puedes cambiar la paleta de colores
domain = base1$preciom
)
leaflet(data = ofertas_base2) %>%
addTiles() %>%
addCircleMarkers(
~longitud, ~latitud,
radius = ~sqrt(preciom)/5,
color = ~pal(preciom),
#fillOpacity = 0.2,
#clusterOptions = markerClusterOptions(),
popup = ~paste("Precio:", preciom)) %>%
addLegend(
"bottomright",
pal = pal,
values = ~preciom,
title = "Precio")