1. Análisis exploratorio del precio y áreas de vivienda

Primeramente, para conocer la data que se realiza un resumen de estadísticas descriptivas. De esta manera se puede observar:

summary(vivienda4)
##            zona      estrato     preciom        areaconst     
##  Zona Centro :   8   3:   0   Min.   :207.4   Min.   : 40.00  
##  Zona Norte  : 288   4:1706   1st Qu.:230.7   1st Qu.: 60.00  
##  Zona Oeste  :  60   5:   0   Median :238.8   Median : 75.00  
##  Zona Oriente:   6   6:   0   Mean   :243.7   Mean   : 87.63  
##  Zona Sur    :1344            3rd Qu.:251.5   3rd Qu.: 98.00  
##                               Max.   :309.7   Max.   :200.00  
##           tipo     
##  Apartamento:1363  
##  Casa       : 343  
##                    
##                    
##                    
## 
summarytools::descr(vivienda4[,c(3,4)])
## Descriptive Statistics  
## vivienda4  
## N: 1706  
## 
##                     areaconst   preciom
## ----------------- ----------- ---------
##              Mean       87.63    243.70
##           Std.Dev       36.35     19.56
##               Min       40.00    207.41
##                Q1       60.00    230.73
##            Median       75.00    238.77
##                Q3       98.00    251.51
##               Max      200.00    309.70
##               MAD       22.24     14.19
##               IQR       38.00     20.77
##                CV        0.41      0.08
##          Skewness        1.53      1.26
##       SE.Skewness        0.06      0.06
##          Kurtosis        1.68      1.25
##           N.Valid     1706.00   1706.00
##         Pct.Valid      100.00    100.00
# Filtrar solo los registros que corresponden a 'Apartamento'
apartamentos <- vivienda4 %>% filter(tipo == "Apartamento")
casas <- vivienda4 %>% filter(tipo == "Casa")
# Visualizar el resumen de apartamentos
summary(apartamentos)
##            zona      estrato     preciom        areaconst     
##  Zona Centro :   7   3:   0   Min.   :207.4   Min.   : 40.00  
##  Zona Norte  : 237   4:1363   1st Qu.:228.8   1st Qu.: 60.00  
##  Zona Oeste  :  52   5:   0   Median :236.1   Median : 70.00  
##  Zona Oriente:   2   6:   0   Mean   :237.7   Mean   : 75.48  
##  Zona Sur    :1065            3rd Qu.:243.6   3rd Qu.: 84.00  
##                               Max.   :305.2   Max.   :200.00  
##           tipo     
##  Apartamento:1363  
##  Casa       :   0  
##                    
##                    
##                    
## 

Después de tener solo los datos de las ofertas de apartamentos por zonas es muy similar. La zona sur es la que más oferta tiene con 1.065 viviendas (78.14%%), seguido de la zona norte 237 (17.39%), zona oeste 52 (3.8%), zona centro 8 (0.5%) y por último zona oriente 6 (0.4%).

2. Analisis bivariado (Precio - Area)

# Histogramas de precios y área construida
hist(apartamentos$preciom, main = "Distribucion de Precios", xlab = "Precio")

hist(apartamentos$areaconst, main = "Distribucion de Area Construida", xlab = "Area Construida")

Se puede observar en el histograma de precios que existe un sesgo positivo.

# Gráfico de correlación
ggpairs(vivienda4[,3:4], title="Viviendas estrato 4")

ggpairs(apartamentos[,3:4], title="Apartamentos estrato 4") 

ggpairs(casas[,3:4], title="Casas estrato 4") 

Se realizó un análisis gráfico y se calculó la correlación para el total de las viviendas, así como para apartamentos y casas, con el objetivo de identificar si existen cambios significativos o datos atípicos en función del tipo de vivienda.

boxplot(vivienda4[,3:4])

boxplot(apartamentos[,3:4])

boxplot(casas[,3:4])

Cuando se ve las gráficas de correlaciones se evidencia que en general las viviendas tiene una correlación lineal positiva fuerte.

No obstante, cuando se ve solo los aparamentos, si bien se mantiene la correlación positiva fuerte, esta disminuye un poco. Esto se debe a que existen datos atipicos en los apartamentos como se observa en los gráficos boxplot.

ggplot(apartamentos, aes(x = zona, y = preciom, fill = zona)) +
  geom_boxplot() +
  stat_summary(fun = mean, geom = "point", shape = 20, size = 3, color = "red", fill = "red") +
  labs(title = "Distribucion de Precios por Zona con Media y Mediana", x = "Zona", y = "Precio de la Propiedad") +
  theme_minimal()

Mirando la distribución de precios por zonas vemos que los datos atipicos se encuentran principalmente en la Zona Sur y Zona Norte, lo cual se puede explicar al ser las zonas donde más apartamentos ofertados.

3. Modelo de regresion lineal simple

# Modelo de regresión lineal
modelo <- lm(preciom ~ areaconst, data = apartamentos)

# Resumen del modelo
summary(modelo)
## 
## Call:
## lm(formula = preciom ~ areaconst, data = apartamentos)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -26.5139  -5.0886  -0.0031   4.6406  24.3309 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 2.001e+02  6.698e-01  298.67   <2e-16 ***
## areaconst   4.984e-01  8.503e-03   58.62   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 7.081 on 1361 degrees of freedom
## Multiple R-squared:  0.7163, Adjusted R-squared:  0.7161 
## F-statistic:  3436 on 1 and 1361 DF,  p-value: < 2.2e-16

Intercepto (β0 = 200.1): El precio de un apartamento con 0 metros cuadrados sería 200.1 millones de pesos, lo cual no tiene un sentido práctico en sí, pero sirve para la construcción del modelo como punto de partida.

Pendiente (β1 = 0.4984): Indica que, en promedio, por cada metro cuadrado adicional de área construida, el precio del apartamento aumenta en 0.4984 millones de pesos. En otras palabras, por cada metro cuadrado adicional, el precio sube aproximadamente 498 mil pesos COP.

Teniendo los resultados del modelo se puede realizar las siguientes interpretaciones:

Construccion de intervalo de confianza (95%)

# Obtener el intervalo de confianza del 95% para los coeficientes del modelo
confint(modelo, level = 0.95)
##                   2.5 %     97.5 %
## (Intercept) 198.7494103 201.377500
## areaconst     0.4817357   0.515097

Para B1 (el coeficiente de areaconst), el intervalo de confianza es (0.4817, 0.5151). Como este intervalo no incluye el valor cero, podemos afirmar que el área construida tiene un efecto significativo sobre el precio

Ahora se realiza una comparación con la prueba t:

# Alternativamente, puedes extraer el valor t manualmente
t_value <- coef(summary(modelo))["areaconst", "t value"]
p_value <- coef(summary(modelo))["areaconst", "Pr(>|t|)"]

# Mostrar valor t y p-value
t_value
## [1] 58.61576
p_value
## [1] 0

Interpretacion del R^2

¿Cuál sería el precio promedio estimado para un apartamento de 110 metros cuadrados? Considera entonces con este resultado que un apartamento en la misma zona con 110 metros cuadrados en un precio de 200 millones sería una atractiva esta oferta? ¿Qué consideraciones adicionales se deben tener?

# Definir los coeficientes del modelo
intercept <- 200.1  # Intercepto en millones de COP
slope <- 0.4984     # Coeficiente de areaconst (precio por metro cuadrado)

# Área del apartamento en metros cuadrados
area <- 110

# Calcular el precio estimado
estimated_price <- intercept + (slope * area)

# Mostrar el resultado
estimated_price
## [1] 254.924

El precio estimado que da de avuerdo al modelo es de COP 254.9 mm por lo que si hay un apartametno en la misma zona de 200 mm sí sería atractivo.

# Filtrar apartamentos con área construida de 110
apartamentos_filtrados <- apartamentos[apartamentos$areaconst == 110, ]

# Mostrar los resultados filtrados
print(apartamentos_filtrados)
## # A tibble: 16 × 5
##    zona       estrato preciom areaconst tipo       
##    <fct>      <fct>     <dbl>     <dbl> <fct>      
##  1 Zona Sur   4          253.       110 Apartamento
##  2 Zona Sur   4          262.       110 Apartamento
##  3 Zona Sur   4          265.       110 Apartamento
##  4 Zona Oeste 4          263.       110 Apartamento
##  5 Zona Sur   4          260.       110 Apartamento
##  6 Zona Sur   4          251.       110 Apartamento
##  7 Zona Sur   4          259.       110 Apartamento
##  8 Zona Sur   4          267.       110 Apartamento
##  9 Zona Sur   4          259.       110 Apartamento
## 10 Zona Sur   4          244.       110 Apartamento
## 11 Zona Sur   4          245.       110 Apartamento
## 12 Zona Sur   4          245.       110 Apartamento
## 13 Zona Sur   4          246.       110 Apartamento
## 14 Zona Sur   4          256.       110 Apartamento
## 15 Zona Sur   4          263.       110 Apartamento
## 16 Zona Sur   4          256.       110 Apartamento
summary(apartamentos_filtrados)
##            zona    estrato    preciom        areaconst            tipo   
##  Zona Centro : 0   3: 0    Min.   :244.3   Min.   :110   Apartamento:16  
##  Zona Norte  : 0   4:16    1st Qu.:249.6   1st Qu.:110   Casa       : 0  
##  Zona Oeste  : 1   5: 0    Median :257.6   Median :110                   
##  Zona Oriente: 0   6: 0    Mean   :255.9   Mean   :110                   
##  Zona Sur    :15           3rd Qu.:262.5   3rd Qu.:110                   
##                            Max.   :267.0   Max.   :110

Despues de que se revisa los apartamentos de 110 metros cuadrados que se encuentran en la data, se puede ver que en promedio se encuentran en COP 255.9 mm por lo que la oferta de COP 200 mm sigue siendo muy atractiva. Ya una consideración adicional sería ver el estado del apartamento.

Validación de supuestos del modelo

# Grafica de los residuos vs los valores ajustados (homocedasticidad)
plot(modelo$fitted.values, modelo$residuals,
     main = "Residuos vs Valores Ajustados",
     xlab = "Valores Ajustados",
     ylab = "Residuos")
abline(h = 0, col = "red")

# Gráfico QQ-Plot para la normalidad de los residuos
qqnorm(modelo$residuals, main = "QQ-Plot de los Residuos")
qqline(modelo$residuals, col = "red")

# Histograma de los residuos
hist(modelo$residuals, main = "Histograma de los Residuos", xlab = "Residuos", breaks = 20)

# Shapiro Test para validación de normalidad
shapiro.test(modelo$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo$residuals
## W = 0.99885, p-value = 0.5419
# Test de Breusch-Pagan para validación Homoscedasticidad
lmtest::bptest(modelo)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 0.83288, df = 1, p-value = 0.3614
# Test de Durbin-Watson para ver No autocorrelación de errores
lmtest::dwtest(modelo)
## 
##  Durbin-Watson test
## 
## data:  modelo
## DW = 2.0204, p-value = 0.6435
## alternative hypothesis: true autocorrelation is greater than 0
  1. Normalidad de los residuos (Shapiro-Wilk test):
    • *W = 0.99885, p-valor = **0.5419*.
    • Un p-valor mayor que 0.05 indica que no se rechaza la hipótesis nula de que los residuos siguen una distribución normal. Se cumple el supuesto de normalidad.
  2. Homoscedasticidad (Breusch-Pagan test):
    • BP = *0.83288, p-valor = **0.3614*.
    • Un p-valor mayor que 0.05 indica que no se rechaza la hipótesis nula de homoscedasticidad, es decir, los errores tienen varianza constante. Se cumple el supuesto de homoscedasticidad.
  3. Independencia de los residuos (Durbin-Watson test):
    • DW = *2.0204, p-valor = **0.6435*.
    • Un valor cercano a 2 indica que no hay autocorrelación significativa entre los residuos, y el p-valor mayor que 0.05 también apoya que no se rechaza la hipótesis de independencia de los errores. Se cumple el supuesto de independencia.

Con base a los resultados, se puede decir que cumplen los supuestos sobre los errores en este modelo, lo que sugiere que los residuos no presentan problemas de normalidad, homoscedasticidad o autocorrelación. Asimismo, al ver el gráfico de Residuos vs Valores parece ser que la linealidad e independencia parecen cumplirse.

Tranformación de variables

modelo <- lm(preciom ~ areaconst, data = apartamentos)           # Lin - Lin
modelo2=lm(preciom ~ log(areaconst), data=apartamentos)      # Lin - Log
modelo3=lm(log(preciom) ~ areaconst, data=apartamentos)      # Log - Lin
modelo4=lm(log(preciom) ~ log(areaconst), data=apartamentos) # Log - Log

library(stargazer)
## 
## Please cite as:
##  Hlavac, Marek (2022). stargazer: Well-Formatted Regression and Summary Statistics Tables.
##  R package version 5.2.3. https://CRAN.R-project.org/package=stargazer
stargazer(modelo, modelo2, modelo3, modelo4, type="text", df=FALSE)
## 
## =======================================================================
##                                     Dependent variable:                
##                     ---------------------------------------------------
##                              preciom                log(preciom)       
##                         (1)          (2)          (3)          (4)     
## -----------------------------------------------------------------------
## areaconst             0.498***                  0.002***               
##                       (0.009)                  (0.00004)               
##                                                                        
## log(areaconst)                    42.878***                  0.174***  
##                                    (0.794)                   (0.003)   
##                                                                        
## Constant             200.063***   53.820***     5.318***     4.723***  
##                       (0.670)      (3.409)      (0.003)      (0.014)   
##                                                                        
## -----------------------------------------------------------------------
## Observations           1,363        1,363        1,363        1,363    
## R2                     0.716        0.682        0.696        0.674    
## Adjusted R2            0.716        0.682        0.695        0.674    
## Residual Std. Error    7.081        7.496        0.030        0.031    
## F Statistic         3,435.808*** 2,919.088*** 3,110.029*** 2,814.311***
## =======================================================================
## Note:                                       *p<0.1; **p<0.05; ***p<0.01

Se puede decir que el Modelo 1 (Modelo de regresion lineal) es el mejor basado en el \(R^2\), el \(R^2\) ajustado y el error estándar residual, ya que muestra la mejor capacidad de explicación de la variabilidad en los datos y un mejor ajuste.

Dado que el Modelo 1 es el más adecuado para orientar los precios de los inmuebles, una estrategia adicional para un análisis más profundo sería filtrar los datos según las zonas de interés para la compra. Esto permitirá evitar la inclusión de datos de otras áreas que puedan afectar negativamente las características y objetivos de búsqueda.

Por ejemplo, consideremos el caso en el que el interés de compra se centra en la zona sur:

apartamentos2 <- apartamentos %>% filter(zona == "Zona Sur")

summary(apartamentos2)
##            zona      estrato     preciom        areaconst     
##  Zona Centro :   0   3:   0   Min.   :207.4   Min.   : 40.00  
##  Zona Norte  :   0   4:1065   1st Qu.:228.6   1st Qu.: 60.00  
##  Zona Oeste  :   0   5:   0   Median :235.8   Median : 70.00  
##  Zona Oriente:   0   6:   0   Mean   :237.2   Mean   : 74.57  
##  Zona Sur    :1065            3rd Qu.:243.3   3rd Qu.: 83.00  
##                               Max.   :305.2   Max.   :200.00  
##           tipo     
##  Apartamento:1065  
##  Casa       :   0  
##                    
##                    
##                    
## 
modelo_apartamentos2 <- lm(preciom ~ areaconst, data = apartamentos2)           # Lin - Lin

summary(modelo_apartamentos2)
## 
## Call:
## lm(formula = preciom ~ areaconst, data = apartamentos2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -26.7112  -5.0879   0.0108   4.6395  21.5644 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 199.7297     0.7840  254.74   <2e-16 ***
## areaconst     0.5023     0.0101   49.73   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 7.109 on 1063 degrees of freedom
## Multiple R-squared:  0.6994, Adjusted R-squared:  0.6991 
## F-statistic:  2473 on 1 and 1063 DF,  p-value: < 2.2e-16
# Gráfico QQ-Plot para la normalidad de los residuos
qqnorm(modelo_apartamentos2$residuals, main = "QQ-Plot de los Residuos")
qqline(modelo_apartamentos2$residuals, col = "red")

# Shapiro Test para validación de normalidad
shapiro.test(modelo_apartamentos2$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo_apartamentos2$residuals
## W = 0.99886, p-value = 0.7481
# Test de Breusch-Pagan para validación Homoscedasticidad
lmtest::bptest(modelo_apartamentos2)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo_apartamentos2
## BP = 0.27608, df = 1, p-value = 0.5993
# Test de Durbin-Watson para ver No autocorrelación de errores
lmtest::dwtest(modelo_apartamentos2)
## 
##  Durbin-Watson test
## 
## data:  modelo_apartamentos2
## DW = 2.0038, p-value = 0.5209
## alternative hypothesis: true autocorrelation is greater than 0