En el presente informe se realiza una evaluación de un modelo lineal para la base de datos de viviendas obtenida del portal fincaraiz, en el cual se pretende estimar el precio de una vivienda en millones de pesos a través de su área en metros cuadrados. Para ello, se realiza un filtro a la base de datos descargada para obtener un modelo que represente específicamente a las viviendas de tipo apartamento. Con esto, se obtiene una base con información de apartamentos de estrato 4 (para ver los códigos utilizados en este informe, diríjase al apartado de anexos).
En primer lugar, se lleva a cabo un análisis descriptivo univariado de las variables que describen el área construida y el precio por metro cuadrado en millones de pesos colombianos. Posteriormente, se realiza un análisis bivariado con el fin de encontrar posibles relaciones entre las variables y comportamientos útiles para el establecimiento del modelo. Finalmente, se plantea el modelo de regresión, además de la validación de supuestos y el planteamiento de posibles transformaciones para mejorar el modelo.
El análisis descriptivo de la variable “Área Construida” revela un promedio de 75.48 \(m^2\), con una ligera desviación hacia la derecha en los datos. Posteriormente, se procede a construir un diagrama de densidad para visualizar la distribución de las áreas de apartamentos contenidas en la base de datos.
## Descriptive Statistics
## vivienda4a$areaconst
## N: 1363
##
## areaconst
## ----------------- -----------
## Mean 75.48
## Std.Dev 22.56
## Min 40.00
## Q1 60.00
## Median 70.00
## Q3 84.00
## Max 200.00
## MAD 14.83
## IQR 24.00
## CV 0.30
## Skewness 2.08
## SE.Skewness 0.07
## Kurtosis 6.32
## N.Valid 1363.00
## Pct.Valid 100.00
ggplot(vivienda4a, aes(x = areaconst)) +
geom_density(fill = "orange", alpha = 0.5) +
labs(title = "Densidad del Área construida",
x = "Área construida en m^2 ",
y = "Densidad") +
theme_minimal()+
theme(
plot.title = element_text(hjust = 0.5))Al verificar el gráfico de densidad, se valida la existencia de una inclinación de los datos hacia la derecha.
Posteriormente, se realiza el respectivo análisis univariado para la variable correspondiente al precio en millones de pesos para los apartamentos. En este análisis, se puede observar un comportamiento similar al de la variable área, en el cual se evidencia cómo la asimetría sugiere una inclinación a la derecha en la gráfica. Por lo tanto, se procede a realizar su respectivo diagrama de densidad.
## Descriptive Statistics
## vivienda4a$preciom
## N: 1363
##
## preciom
## ----------------- ---------
## Mean 237.68
## Std.Dev 13.29
## Min 207.41
## Q1 228.79
## Median 236.14
## Q3 243.59
## Max 305.19
## MAD 10.98
## IQR 14.79
## CV 0.06
## Skewness 1.28
## SE.Skewness 0.07
## Kurtosis 3.19
## N.Valid 1363.00
## Pct.Valid 100.00
ggplot(vivienda4a, aes(x = preciom)) +
geom_density(fill = "blue", alpha = 0.5) +
labs(title = "Densidad del Precio de la Vivienda",
x = "Precio de la Vivienda (millones de pesos COP)",
y = "Densidad") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5))Dado que ambas gráficas muestran una concentración mayor hacia la derecha, se puede observar que los apartamentos con áreas de mayor presencia también tienen precios similares. Por esta razón, se procede a la realización de un análisis bivariado.
Como primera etapa del análisis bivariado, se realiza un gráfico de tipo boxplot para rangos específicos de áreas, con el fin de determinar la variabilidad de los datos en las áreas especificadas. Esto ayuda a medir la concentración de los mismos y su tendencia.
ggplot(vivienda4a, aes(x = factor(cut(areaconst, breaks = 10)), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Diagrama de Caja del Precio de la Vivienda por Rangos de Áreas",
x = "Rango de Área de la Vivienda",
y = "Precio de la Vivienda (millones de pesos COP)") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))Del gráfico se puede observar cómo para los diferentes rangos de áreas se obtienen pocos valores atípicos, además de un aumento en la media del valor de la vivienda, lo que muestra la existencia de una relación directa. Por ello, se decide realizar una matriz de correlación con el fin de evaluar una posible relación lineal.
## [1] 0.8463271
Se puede observar en la parte superior izquierda que el coeficiente de Pearson de estas variables muestra una correlación positiva fuerte. Además, se puede observar en el gráfico de dispersión, el cual se realiza a continuación para un mayor detalle del mismo, la marcada relación entre las variables. Por ello, se comienza con la realización del modelo.
ggplot(vivienda4a, aes(x = areaconst, y = preciom)) +
geom_point(color = "blue", alpha = 0.7) +
labs(title = "Precio vs. Área de la Vivienda",
x = "Área de la Vivienda (metros cuadrados)",
y = "Precio de la Vivienda (millones de pesos COP)") +
theme_minimal()Con los datos anteriores, se procede a plantear un modelo de regresión lineal a través del código descrito a continuación.
##
## Call:
## lm(formula = preciom ~ areaconst, data = vivienda4a)
##
## 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
Los datos obtenidos muestran un coeficiente b1 o pendiente de 0.4984. Esta pendiente sugiere que por cada metro cuadrado, el precio de la vivienda tiene una variación de 0.4984 millones de pesos. Por otro lado, se obtiene un coeficiente b0 o intercepto de 200.1 millones. Este coeficiente no tiene un significado específico, ya que no pueden venderse viviendas con 0 metros cuadrados. Sin embargo, es esencial para el ajuste base de los precios.
Además de los coeficientes, se puede observar que los p-values para cada coeficiente son menores que el valor de significancia, lo que indica que es pertinente rechazar la hipótesis nula de que bo y b1 son iguales a 0, y nos muestra que son importantes para la descripción de la variable dependiente. Para reforzar esta respuesta, se realiza una prueba con un 95% de confianza y se puede observar cómo los coeficientes se encuentran dentro de los rangos establecidos, lo que reafirma que son significativos.
## 2.5 % 97.5 %
## (Intercept) 198.7494103 201.377500
## areaconst 0.4817357 0.515097
Posteriormente, se verifica el valor de \(R^2\) para el modelo, encontrando que con la ecuación descrita:
\[ \text{Precio en millones} = 200.1 + 0.4984 \times \text{Área} \]
Es posible describir el 71.63% del comportamiento del precio de un apartamento de estrato 4 en la ciudad de Cali. Es necesario aclarar que este modelo solo aplica para la zona en la que se realizó el estudio.
## [1] 0.7162696
Como parte del ejercicio, se propone estimar el precio promedio para un apartamento con un área de 110 \(m^2\) y verificar qué tan atractiva resulta una oferta de 200 millones de pesos para un apartamento de estas características.
Para ello, se utiliza la función predict, la cual nos indica un rango donde se encontrará el precio de la vivienda con un 95% de confianza, obteniendo los siguientes resultados.
## fit lwr upr
## 1 254.8893 240.9814 268.7971
Además, se procede a filtrar las viviendas con un área igual en el ejercicio propuesto y realizar un histograma de los precios para este subgrupo.
lasde110 <- vivienda4[vivienda4$areaconst == 110,]
ggplot(lasde110, aes(x = preciom)) +
geom_histogram(binwidth = 10, fill = "skyblue", color = "black") +
labs(title = "Distribución del Precio de la Vivienda",
x = "Precio de la Vivienda (millones de pesos COP)",
y = "Frecuencia") +
theme_minimal()De esta manera, a través de las pruebas anteriores, se puede afirmar que un precio de 200 millones de pesos es significativamente bajo en comparación con el precio promedio de vivienda para esta área. Por lo tanto, es necesario realizar otras consideraciones que podrían afectar su precio, como la tenencia de parqueadero, la seguridad del apartamento, entre otras.
Para concluir que el modelo planteado es correcto, es necesario primero realizar una validación de supuestos para los residuales. Entre los supuestos tenemos:
Este supuesto estima que la media de los residuales debe ser 0 y, por lo tanto, al graficarlos no se debe visualizar ningún patrón, sino que, por el contrario, se debe observar una nube de puntos.
## [1] 2.792293e-18
De lo anterior, se puede observar tanto la nube de puntos como la proximidad de la media de los residuales a 0.
Este supuesto espera que la varianza sea constante. Para ello, se realiza el siguiente gráfico donde no hay evidencia de un aumento o disminución en la varianza.
plot(mol, which = 3)
abline(h = 1.5, col = "red", lty = 2, lwd = 2)
abline(h = 0.2, col = "red", lty = 2, lwd = 2) Sin embargo, para la validación completa de los supuestos, se realiza un test de Breusch-Pagan, obteniendo valores p mayores al nivel de significancia. Esto no permite rechazar la hipótesis nula y afirmar que no existe heterocedasticidad en los residuales, y que su varianza es constante.
##
## studentized Breusch-Pagan test
##
## data: mol
## BP = 0.83288, df = 1, p-value = 0.3614
Este supuesto expone que los residuales del modelo deben tener un comportamiento normal. Para validarlo, se realizan dos gráficos:
dfres = as.data.frame(mol$residuals)
normres= as.data.frame(scale(dfres$`mol$residuals`))
ggplot(normres, aes(x = V1)) +
geom_density(fill = "orange", alpha = 0.5) +
stat_function(fun=dnorm, color = 'blue', lwd = 1)+
labs(title = "Densidad de residuales"
) +
theme_minimal()+
theme(
plot.title = element_text(hjust = 0.5)) Finalmente, se realiza un Test de Shapiro-Wilk con valores de p-value de 0.5419, lo que indica que no hay suficiente evidencia para rechazar la hipótesis nula y sugiere que los datos se distribuyen de manera similar a una distribución normal.
##
## Shapiro-Wilk normality test
##
## data: mol$residuals
## W = 0.99885, p-value = 0.5419
Finalmente, este supuesto expone que no debe existir autocorrelación entre los errores. Para ello, se realiza la siguiente gráfica en la que no se deben vislumbrar comportamientos con patrones. Además de eso, se realiza el test de Durbin-Watson, en el cual se obtiene un valor de 0.6435, lo que no proporciona evidencia suficiente para rechazar la hipótesis nula. Por lo tanto, es posible asegurar que no existe autocorrelación en los errores.
##
## Durbin-Watson test
##
## data: mol
## DW = 2.0204, p-value = 0.6435
## alternative hypothesis: true autocorrelation is greater than 0
Finalmente, se proponen distintas transformaciones que podrían ayudar a mejorar el modelo. Para ello, se busca la mejor transformación mediante el gráfico Box-Cox.
## [1] 0.9292929
Del gráfico se obtiene que el modelo ideal es aquel para el cual no se realiza ninguna transformación. Sin embargo, como ejercicio práctico, se decide utilizar la segunda mejor transformación obtenida del gráfico, que es para lambda -0.5, lo que corresponde a la raíz cuadrada de y. Además, se utilizan otras tres transformaciones y se realizan sus respectivas validaciones de supuestos.
modelo1=lm(preciom ~ areaconst,data=vivienda4a) # Lin - Lin
modelo2=lm(preciom ~ log(areaconst),data=vivienda4a) # Lin - Log
modelo3=lm(log(preciom) ~ areaconst,data=vivienda4a) # Log - Lin
modelo4=lm(log(preciom) ~ log(areaconst),data=vivienda4a) # Log - Log
modelo5=lm(sqrt(preciom) ~ areaconst,data=vivienda4a) # raiz - lin
stargazer(modelo1, modelo2, modelo3, modelo4,modelo5, type="text", df=FALSE) ## verificar formato##
## =====================================================================================
## Dependent variable:
## -----------------------------------------------------------------
## preciom log(preciom) sqrt(preciom)
## (1) (2) (3) (4) (5)
## -------------------------------------------------------------------------------------
## areaconst 0.498*** 0.002*** 0.016***
## (0.009) (0.00004) (0.0003)
##
## log(areaconst) 42.878*** 0.174***
## (0.794) (0.003)
##
## Constant 200.063*** 53.820*** 5.318*** 4.723*** 14.218***
## (0.670) (3.409) (0.003) (0.014) (0.022)
##
## -------------------------------------------------------------------------------------
## Observations 1,363 1,363 1,363 1,363 1,363
## R2 0.716 0.682 0.696 0.674 0.706
## Adjusted R2 0.716 0.682 0.695 0.674 0.706
## Residual Std. Error 7.081 7.496 0.030 0.031 0.230
## F Statistic 3,435.808*** 2,919.088*** 3,110.029*** 2,814.311*** 3,272.232***
## =====================================================================================
## Note: *p<0.1; **p<0.05; ***p<0.01
Se puede ver que los supuestos con mejor \(R^2\) son el lin - lin y raíz - lin; sin embargo, se procede a realizar las pruebas de los supuestos para cada uno de los modelos y se presentan en la siguiente tabla.
| Modelo | Linealidad | Homocedasticidad | Normalidad | Autocorrelacion |
|---|---|---|---|---|
| lin-lin | 0 | 0.3614413 | 0.5419366 | 0.6435162 |
| lin-log | 0 | 0.0001416 | 0.0130195 | 0.1586902 |
| log-lin | 0 | 0.0081078 | 0.7332808 | 0.6534030 |
| log-log | 0 | 0.7306137 | 0.2867877 | 0.2468955 |
| raiz-log | 0 | 0.0593984 | 0.7462595 | 0.6526522 |
De lo anterior, se debe tener en cuenta que para la prueba de linealidad se utilizó la media de los residuales, por lo que un resultado igual a 0 es el adecuado. Para las pruebas de homocedasticidad, se utilizó el test de Breusch-Pagan, en el cual se esperan valores superiores a 0.05. En cuanto a la normalidad, se utilizó el test Shapiro-Wilk, por lo tanto, también se esperan valores superiores a 0.05. Finalmente, para la autocorrelación, se utilizó el test Durbin-Watson, por lo cual también se esperan resultados superiores a 0.05.
Se puede observar cómo los modelos lin-lin y lin-log no cumplen con el supuesto de homocedasticidad. Para su corrección, se podría realizar un modelo con robustez en los residuales.
El modelo de regresión lineal obtenido proporciona una buena descripción del precio de las viviendas de tipo apartamento en la zona estudiada. Aunque se han identificado algunas áreas de mejora, como la heterocedasticidad en algunos modelos, el modelo general es útil para predecir el precio de una vivienda en función de su área. Además, se ha explorado la posibilidad de mejorar el modelo mediante transformaciones de las variables, lo que puede ser útil en futuros análisis.
Las regresiones lineales son una herramienta poderosa para modelar la relación entre variables continuas. Permiten entender cómo una variable dependiente está influenciada por una o más variables independientes. Sin embargo, es importante tener en cuenta que las regresiones lineales tienen supuestos que deben cumplirse para que los resultados sean válidos. Estos supuestos incluyen linealidad, homocedasticidad, normalidad de los residuos y ausencia de autocorrelación. La validación de estos supuestos es crucial para interpretar correctamente los resultados de la regresión.
La validación de supuestos es una parte fundamental del análisis de regresión lineal. Permite asegurarse de que los supuestos subyacentes del modelo se cumplen y que los resultados obtenidos son válidos y confiables. Esto se logra mediante una serie de pruebas estadísticas y análisis gráficos que evalúan la linealidad, homocedasticidad, normalidad de los residuos y ausencia de autocorrelación. Si alguno de estos supuestos no se cumple, pueden tomarse medidas correctivas, como la transformación de variables o el uso de modelos alternativos, para mejorar la validez del modelo de regresión.
Como anexo, podrán encontrar todos los códigos utilizados para la realización del análisis descrito anteriormente.
#install.packages("devtools") # solo una vez
devtools::install_github("dgonxalex80/paqueteMETODOS")
#====================================================#
# Librerias Utilizadas #
#====================================================#
library(paqueteMETODOS)
library(ggplot2)
library(GGally)
library(stargazer)
library(sandwich)
library(lmtest)
library(tseries)
library(estimatr)
library(kableExtra)
data(vivienda4)
#====================================================#
# Filtro apartamento #
#====================================================#
vivienda4a <- vivienda4[vivienda4$tipo == 'Apartamento',]
#====================================================#
# Punto 1 #
#====================================================#
## PUNTO 1
## analisis exploratorio
descr(vivienda4a$areaconst)
# Gráfico de densidad del precio de la vivienda
ggplot(vivienda4a, aes(x = areaconst)) +
geom_density(fill = "orange", alpha = 0.5) +
labs(title = "Densidad del Área construida",
x = "Área construida en m^2 ",
y = "Densidad") +
theme_minimal()+
theme(
plot.title = element_text(hjust = 0.5))
# Gráfico de densidad del precio de la vivienda
descr(vivienda4a$preciom)
ggplot(vivienda4a, aes(x = preciom)) +
geom_density(fill = "blue", alpha = 0.5) +
labs(title = "Densidad del Precio de la Vivienda",
x = "Precio de la Vivienda (millones de pesos COP)",
y = "Densidad") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5))
#====================================================#
# Punto 2 #
#====================================================#
# cajas
ggplot(vivienda4a, aes(x = factor(cut(areaconst, breaks = 10)), y = preciom)) +
geom_boxplot(fill = "lightblue", color = "black") +
labs(title = "Diagrama de Caja del Precio de la Vivienda por Rangos de Áreas",
x = "Rango de Área de la Vivienda",
y = "Precio de la Vivienda (millones de pesos COP)") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
##matriz de correlacion
ggpairs(vivienda4a[,3:4], title="Precio")
per = cor(vivienda4a$preciom, vivienda4a$areaconst)
per
##dispercion esta guapo
ggplot(vivienda4a, aes(x = areaconst, y = preciom)) +
geom_point(color = "blue", alpha = 0.7) +
labs(title = "Precio vs. Área de la Vivienda",
x = "Área de la Vivienda (metros cuadrados)",
y = "Precio de la Vivienda (millones de pesos COP)") +
theme_minimal()
##correlacion positiva fuerte
mol =lm(preciom ~ areaconst,data=vivienda4a)
summary(mol)
##se ve el mayor grado de significancia y se evidencia que los valores de p estan muy por debajo
#de 0.05
#====================================================#
# Confirmacion del modelo #
#====================================================#
confint(mol, level = 0.95)
resumen <- summary(mol)
r_cuadrado <- resumen$r.squared
r_cuadrado
##predici el 71%
#====================================================#
# Predecir al 95% #
#====================================================#
## precio de apartamento de 110 mt2
predict(mol, data.frame(areaconst = 110), interval = "confidence", level = 0.95)
predict(mol, data.frame(areaconst = 110), interval = "prediction", level = 0.95)## creo que es este
lasde110 <- vivienda4[vivienda4$areaconst == 110,]
ggplot(lasde110, aes(x = preciom)) +
geom_histogram(binwidth = 10, fill = "skyblue", color = "black") +
labs(title = "Distribución del Precio de la Vivienda",
x = "Precio de la Vivienda (millones de pesos COP)",
y = "Frecuencia") +
theme_minimal()
#====================================================#
# Validar supuestos #
#====================================================#
##linealidad
plot(mol, which = 1)
mean(mol$residuals)
##varianza constante
plot(mol, which = 3)
abline(h = 1.5, col = "red", lty = 2, lwd = 2)
abline(h = 0.2, col = "red", lty = 2, lwd =2)
lmtest::bptest(mol)
lmtest::gqtest(mol)
##normalidad
plot(mol, which = 2)##normalidad
dfres = as.data.frame(mol$residuals)
normres= as.data.frame(scale(dfres$`mol$residuals`))
dfres = as.data.frame(mol$residuals)
normres= as.data.frame(scale(dfres$`mol$residuals`))
ggplot(normres, aes(x = V1)) +
geom_density(fill = "orange", alpha = 0.5) +
stat_function(fun=dnorm, color = 'blue', lwd = 1)+
labs(title = "Densidad de residuales"
) +
theme_minimal()+
theme(
plot.title = element_text(hjust = 0.5))
shapiro.test(mol$residuals)
##AUTOCORRELACION
plot(mol$residuals, type = "l",col ="blue",bty="n")
lmtest::dwtest(mol)
#====================================================#
# Identificar transformaciones #
#====================================================#
##
par(mfrow = c(1,2))
boxcox(mol, lambda = -3:3)
#Se repite el proceso pero esta vez entrechando el rango de valores de lambda
bc<-boxcox(mol, lambda = 0:2)
(lambda <- bc$x[which.max(bc$y)])
#====================================================#
# Modelos transformados #
#====================================================#
modelo1=lm(preciom ~ areaconst,data=vivienda4a) # Lin - Lin
modelo2=lm(preciom ~ log(areaconst),data=vivienda4a) # Lin - Log
modelo3=lm(log(preciom) ~ areaconst,data=vivienda4a) # Log - Lin
modelo4=lm(log(preciom) ~ log(areaconst),data=vivienda4a) # Log - Log
modelo5=lm(sqrt(preciom) ~ areaconst,data=vivienda4a) # raiz - lin
stargazer(modelo1, modelo2, modelo3, modelo4,modelo5, type="text", df=FALSE) ## verificar formato
#====================================================#
# Supuestos de todos los modelos #
#====================================================#
mean(modelo1$residuals)
mean(modelo2$residuals)
mean(modelo3$residuals)
mean(modelo4$residuals)
mean(modelo5$residuals)
shapiro.test(modelo1$residuals)
shapiro.test(modelo2$residuals)
shapiro.test(modelo3$residuals)
shapiro.test(modelo4$residuals)
shapiro.test(modelo5$residuals)
lmtest::bptest(modelo1)
lmtest::bptest(modelo2)
lmtest::bptest(modelo3)
lmtest::bptest(modelo4)
lmtest::bptest(modelo5)
lmtest::dwtest(modelo1)
lmtest::dwtest(modelo2)
lmtest::dwtest(modelo3)
lmtest::dwtest(modelo4)
lmtest::dwtest(modelo5)
#====================================================#
# Formateo de tabla #
#====================================================#
modelos <- c("lin-lin", "lin-log", "log-lin", "log-log", "raiz-log")
linealidad <- c(mean(modelo1$residuals), mean(modelo2$residuals), mean(modelo3$residuals), mean(modelo4$residuals), mean(modelo5$residuals))
homocedasticidad <- c(lmtest::bptest(modelo1)$p.value, lmtest::bptest(modelo2)$p.value, lmtest::bptest(modelo3)$p.value, lmtest::bptest(modelo4)$p.value, lmtest::bptest(modelo5)$p.value)
normalidad <- c(shapiro.test(modelo1$residuals)$p.value, shapiro.test(modelo2$residuals)$p.value, shapiro.test(modelo3$residuals)$p.value, shapiro.test(modelo4$residuals)$p.value, shapiro.test(modelo5$residuals)$p.value)
autocorrelacion <- c(lmtest::dwtest(modelo1)$p.value, lmtest::dwtest(modelo2)$p.value, lmtest::dwtest(modelo3)$p.value, lmtest::dwtest(modelo4)$p.value, lmtest::dwtest(modelo5)$p.value)
tabla_datos <- data.frame(Modelo = modelos,
Linealidad = linealidad,
Homocedasticidad = homocedasticidad,
Normalidad = normalidad,
Autocorrelacion = autocorrelacion)
tabla_html <- kable(tabla_datos, "html") %>%
kable_styling(full_width = FALSE)
tabla_html