Julian Andres Ospina Cuesta

Maestría en Ciencia de Datos - Universidad Javeriana Cali
Cali, Colombia
Código: 8984933 +57 3043912471
Autorizo que el documento sea publicado con el resto de mis compañeros de la Universidad Javeriana
#install.packages("devtools") # solo una vez
#devtools::install_github("dgonxalex80/paqueteMETODOS")
library(paqueteMETODOS)
library(knitr)
library(ggplot2)
library(gridExtra)
library(lmtest)
data(vivienda4)

1.Introducción

El presente documento constituye un análisis de las ofertas de viviendas disponibles en el portal Fincaraiz. Dicho portal cuenta con una base de datos que abarca apartamentos de estrato 4 con una superficie de construcción inferior a 200 metros cuadrados, identificados como ‘vivienda4’. El objetivo fundamental de este análisis es la creación de un modelo que sea de guía para la determinación de los precios de estas propiedades inmobiliarias.

A continuación veremos los primeros registros de nuestra base de datos

kable(do.call(data.frame, head(vivienda4)),
      format = "markdown",  
      caption = "**Tabla de los primeros registros base vivienda4**",
      align = "c", escape = FALSE,
      row.names = FALSE,
      booktabs = TRUE)
Tabla de los primeros registros base vivienda4
zona estrato preciom areaconst tipo
Zona Norte 4 220 52 Apartamento
Zona Norte 4 600 160 Casa
Zona Norte 4 320 108 Apartamento
Zona Sur 4 290 96 Apartamento
Zona Norte 4 220 82 Apartamento
Zona Norte 4 305 117 Casa

Observamos que tenemos 5 campos que constituyen los campos de la base, incluyendo el campo dependiente \(y = preciom\) en nuestro futuro modelo. Se observa que tenemos mas tipos de apartamentos en los primeros registros

1.2 El estado de los campos de ‘vivienda4’

Antes de dar inicio a los puntos que nos facilitaron para el analisis, veamos como vienen constituidos cada uno de los campos de nuestra base de datos:

  • Diagnostico inicial
resumen_data <- list(
  num_filas = nrow(vivienda4),
  num_col= ncol(vivienda4),
  vacios_totales = sum(is.na(vivienda4)),
  porc_vacios = sprintf('%.2f%%',sum(is.na(vivienda4))/(nrow(vivienda4)*ncol(vivienda4))*100),
  filas_con_mas_un_vacio = sum(apply(is.na(vivienda4), 1, any)),
  filas_all_vacios = sum(apply(is.na(vivienda4), 1, all)),
  col_all_vacios = sum(colSums(is.na(vivienda4)) == nrow(vivienda4)),
  filas_duplicadas= nrow(vivienda4[duplicated(vivienda4), ])
)

kable(do.call(data.frame, resumen_data),
      format = "markdown", 
      caption = "**Tabla n°1 Resumen de dataset antes de tratamientos**",
      align = "c", escape = FALSE,
      row.names = FALSE,
      booktabs = TRUE)
Tabla n°1 Resumen de dataset antes de tratamientos
num_filas num_col vacios_totales porc_vacios filas_con_mas_un_vacio filas_all_vacios col_all_vacios filas_duplicadas
1706 5 0 0.00% 0 0 0 471

Observamos que tenemos un total de 1706 registros, y ninguno de ellos presenta filas vacías ni campos sin información. Del mismo modo, no se encuentra un campo que haga referencia a que los registros deban ser únicos, por lo que los 471 registros duplicados se atribuyen a la naturaleza de la fuente

1.3 Valores unicos de algunos campos

unique_values <- unique(vivienda4$zona)
kable(data.frame(Valores_Unicos = unique_values), format = "html")
Valores_Unicos
Zona Norte
Zona Sur
Zona Oeste
Zona Oriente
Zona Centro
unique_values <- unique(vivienda4$estrato)
kable(data.frame(Valores_Unicos = unique_values), format = "html")
Valores_Unicos
4
unique_values <- unique(vivienda4$tipo)
kable(data.frame(Valores_Unicos = unique_values), format = "html")
Valores_Unicos
Apartamento
Casa

Observamos que contamos con valores no relacionados al objeto de estudio, pero antes de removerlos, observamos que tan relacionados estan con la variable precio

vivienda4$zona_index = as.integer(factor(vivienda4$zona, levels = unique(vivienda4$zona)))
vivienda4$tipo_index = as.integer(factor(vivienda4$tipo, levels = unique(vivienda4$tipo)))
vivienda4$estrato_index = as.integer(factor(vivienda4$estrato, levels = unique(vivienda4$estrato)))

ggpairs(select(vivienda4, -tipo, -estrato,-estrato_index, -zona), title="Casas, ubicación sur, estratos 5 y 6")

Observamos que en la matriz de correlación, los campos que destacan más son el área de construcción y el tipo de apartamento en relación con la variable de precio. Por lo tanto, continuaremos el análisis considerando el precio como variable dependiente y el área de construcción como variable predictora, específicamente para el tipo de vivienda ‘Apartamentos’

vivienda4 <- subset(vivienda4, tipo == "Apartamento")

resumen_data <- list(
  num_filas = nrow(vivienda4),
  num_col= ncol(vivienda4),
  vacios_totales = sum(is.na(vivienda4)),
  porc_vacios = sprintf('%.2f%%',sum(is.na(vivienda4))/(nrow(vivienda4)*ncol(vivienda4))*100),
  filas_con_mas_un_vacio = sum(apply(is.na(vivienda4), 1, any)),
  filas_all_vacios = sum(apply(is.na(vivienda4), 1, all)),
  col_all_vacios = sum(colSums(is.na(vivienda4)) == nrow(vivienda4)),
  filas_duplicadas= nrow(vivienda4[duplicated(vivienda4), ])
)

kable(do.call(data.frame, resumen_data),
      format = "markdown", 
      caption = "**Tabla n°1 Resumen de dataset antes de tratamientos**",
      align = "c", escape = FALSE,
      row.names = FALSE,
      booktabs = TRUE)
Tabla n°1 Resumen de dataset antes de tratamientos
num_filas num_col vacios_totales porc_vacios filas_con_mas_un_vacio filas_all_vacios col_all_vacios filas_duplicadas
1363 8 0 0.00% 0 0 0 431

Obteniendo un total de 1363, con 431 registros duplicados , que pueden tratarse de diversas casa con similiares precios y metros cuadrados.

2. Analisis exploratorio del preciom y el área de la vivienda

A continuación, exploraremos dos tipos de análisis en los campos predictor y dependiente que utilizaremos en nuestro modelo

2.1 Analisis uni variado

Precio de vivienda (millones de pesos COP)-> preciom

col<-'preciom'
grafico_hist <-ggplot(data = vivienda4, aes(x = !!as.name(col))) +
  geom_histogram(bins = 30, color = "#515354", fill = "#0576FF") +
  geom_vline(aes(xintercept = mean(!!as.name(col))), color = "#FF0576", linetype = "dashed", size = 1) +
  geom_vline(aes(xintercept = median(!!as.name(col))), color = "#50AC05", linetype = "dashed", size = 1) +
  theme_bw() +
  labs(title = paste('Histograma de', col), x = col, y = "Frecuencia")+
  theme_minimal()+
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())

grafico_boxplot <- ggplot(data=vivienda4, aes(y=!!as.name(col)))+
 geom_boxplot(fill="#0576FF")+
 ggtitle("Precio en millones")+
 theme_minimal() +
 theme(plot.background = element_rect(fill = "white"),
       panel.grid = element_blank(),
       panel.border = element_blank(),
       plot.title = element_text(size = 16, hjust = 0.5),
       axis.line = element_line(size = 1, color = "#515354"))

grid.arrange(grafico_hist, grafico_boxplot, ncol = 2)

kable(do.call(data.frame, describe(vivienda4$preciom)),
      format = "markdown",  
      caption = "**Tabla de los primeros registros base vivienda4**",
      align = "c", escape = FALSE,
      row.names = FALSE,
      booktabs = TRUE)
Tabla de los primeros registros base vivienda4
vars n mean sd median trimmed mad min max range skew kurtosis se
1 1363 202.4373 65.29049 185 194.6994 59.304 78 645 567 1.442664 3.833419 1.768488

l observar el histograma y el diagrama de caja (boxplot), notamos la presencia de colas pesadas y sesgos hacia viviendas con precios medios o bajos, lo que es común en un modelo de vivienda. Un punto destacado es la presencia de dos picos de registros alrededor de la media, lo cual resulta llamativo, ya que podría sugerir la existencia de dos subconjuntos de muestras en los datos

Datos más precisos indican una media de 202 millones con una desviación estándar de 65 millones (lo que refleja una alta dispersión), y una mediana de 185 millones. La asimetría de 1.44 señala una distribución sesgada hacia la derecha, respaldando la observación gráfica. Además, la kurtosis muestra picos más pronunciados que una distribución normal, indicando una mayor concentración de valores alrededor de la media.

Área de la vivienda (metros cuadrados)-> areaconst

col<-'areaconst'
grafico_hist <-ggplot(data = vivienda4, aes(x = !!as.name(col))) +
  geom_histogram(bins = 30, color = "#515354", fill = "#0576FF") +
  geom_vline(aes(xintercept = mean(!!as.name(col))), color = "#FF0576", linetype = "dashed", size = 1) +
  geom_vline(aes(xintercept = median(!!as.name(col))), color = "#50AC05", linetype = "dashed", size = 1) +
  theme_bw() +
  labs(title = paste('Histograma de', col), x = col, y = "Frecuencia")+
  theme_minimal()+
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())

grafico_boxplot <- ggplot(data=vivienda4, aes(y=!!as.name(col)))+
 geom_boxplot(fill="#0576FF")+
 ggtitle("Área de construcción (m^2)")+
 theme_minimal() +
 theme(plot.background = element_rect(fill = "white"),
       panel.grid = element_blank(),
       panel.border = element_blank(),
       plot.title = element_text(size = 16, hjust = 0.5),
       axis.line = element_line(size = 1, color = "#515354"))

grid.arrange(grafico_hist, grafico_boxplot, ncol = 2)

kable(do.call(data.frame, describe(vivienda4$areaconst)),
      format = "markdown",  
      caption = "**Tabla de los primeros registros base vivienda4**",
      align = "c", escape = FALSE,
      row.names = FALSE,
      booktabs = TRUE)
Tabla de los primeros registros base vivienda4
vars n mean sd median trimmed mad min max range skew kurtosis se
1 1363 75.47836 22.56461 70 71.94042 14.826 40 200 160 2.082196 6.323576 0.6111951

Observamos un patrón de distribución similar al de los precios, lo que resulta interesante. También se presentan colas pesadas y sesgos hacia viviendas con áreas en metros cuadrados medio-bajas, lo cual es común en un modelo de vivienda. Los valores de asimetría y kurtosis respaldan la representación gráfica, con un pico pronunciado y un sesgo hacia la derecha.

2.2 Analisi bivariado de los datos

Se nos solicita centrarnos en la relación entre el precio \(Y = variable dependiente\) y el área de contrucción \(X= variable predictora\) . Para entender mejor esta relación, observemos cómo se comportan ambas variables en un gráfico de dispersión.

ggplot(data = vivienda4, aes(x = areaconst, y = preciom)) +
  geom_point(color = "gray52", shape = 19) +
  labs(
    title = "Precio vs Área Construcción",
    x = "Áreas de construcción (m2)",
    y = "Precio (Millones pesos)"
  ) +
  theme_minimal()+
  theme(plot.background = element_rect(fill = "white"),
        panel.grid = element_blank(),
        panel.border = element_blank(),
        plot.title = element_text(size = 16, hjust = 0.5),
        axis.line = element_line(size = 1, color = "#515354"))

Se observa un comportamiento lineal entre las variables, lo que sugiere que a medida que aumenta el área de construcción, el precio tiende a incrementarse. Además, notamos que esta relación se vuelve más dispersa a medida que el área de construcción aumenta. Es importante destacar la presencia de algunos datos aparentemente atípicos, como los puntos de precio más bajos en el rango de áreas de construcción de 100 a 150 metros cuadrados, lo cual resulta llamativo dado el patrón lineal aparente.

coeficiente_relacion_Pearson = cor(vivienda4$areaconst, vivienda4$preciom)

cat('El coeficiente de correlación de Pearson entre Precio y el Área de construcción es: ', coeficiente_relacion_Pearson)
## El coeficiente de correlación de Pearson entre Precio y el Área de construcción es:  0.7481389

Importante El coeficiente de Pearson, al respaldar la linealidad entre las variables, refuerza la impresión que se observa en el gráfico de dispersión y lo convierte en un indicio sólido para considerar un modelo de regresión lineal medio-fuerte y positvo.

3. Estimación del modelo de regresión lineal simple \(precio = f(area) + \epsilon\)

modelo_ln = lm(preciom ~ areaconst, data=vivienda4)
summary(modelo_ln)
## 
## Call:
## lm(formula = preciom ~ areaconst, data = vivienda4)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -225.404  -23.902   -4.754   25.763  209.021 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 39.04679    4.09977   9.524   <2e-16 ***
## areaconst    2.16473    0.05204  41.595   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 43.34 on 1361 degrees of freedom
## Multiple R-squared:  0.5597, Adjusted R-squared:  0.5594 
## F-statistic:  1730 on 1 and 1361 DF,  p-value: < 2.2e-16

Observamos que nuestro modelo presenta tanto el intercepto como el coeficiente de variación estimado del área con pruebas t que muestran un alto nivel de significancia. Esto nos permite llegar a dos conclusiones con este enfoque:

  • $b_1 $ nos dice: por cada área de metro cuadrado que avanzamos, el precio en millones sube 2.16
  • \(b_0\) nos dice: Si existiera una casa con cero metros cuadrados de área de construcción, según nuestro modelo, tendría un costo promedio estimado de 39 millones de pesos. Aunque este valor no es realista en términos de negocios inmobiliarios, sugiere que incluso las viviendas más pequeñas en estrato 4 tiene un costo superior de 39 millones.

4. Intervalo de confianza

confint(modelo_ln, level=0.95)
##                2.5 %    97.5 %
## (Intercept) 31.00423 47.089340
## areaconst    2.06264  2.266826

Si examináramos un intervalo de confianza al 95%, podríamos afirmar que con un nivel de confianza del 95%, los valores de \(b_0\) y \(b_1\) varían en un rango que va desde 31 millones a 47 millones y desde 2.06 a 2.26 millones, respectivamente.

5. Indicador de bondad de ajustes \(R^2\)

r2 = summary(modelo_ln)$r.squared
cat('El coeficiente de R\2: ', r2)
## El coeficiente de R:  0.5597117

La prueba de bondad de ajuste de mi modelo indica que explica el 55.97% de la variación en el precio. Esto significa que, considerando que se trata de un modelo de una sola variable, proporciona una buena explicación de cómo el área de construcción influye en el precio. Es importante señalar que, aunque este porcentaje es inferior al 100%, lo cual sería ideal, para un modelo univariable, es un resultado bastante sólido.

6. Prección del modelo areaconst=110

predict(modelo_ln,data.frame(areaconst = 110), interval = "confidence", level = 0.95)
##        fit      lwr      upr
## 1 277.1674 272.9573 281.3775

Se nos pide considerar una oferta de un apartamento con un área de construcción de 110 metros cuadrados con un precio de $200 millones. Según nuestras estimaciones, que tienen un intervalo de confianza de $277 millones, esta oferta estaría $67 millones por debajo de nuestra estimación. En resumen, esta oferta parece ser una buena oportunidad basada en mi modelo.

Si bien el modelo tiene un ajuste del 55.97% de bondad, es crucial recordar la importancia de la revisión de sus supuestos. Desde los gráficos iniciales, observamos comportamientos algo sospechosos que sugieren la posibilidad de no linealidad, especialmente debido a la alta dispersión en los datos. Por lo tanto, sería recomendable probar y validar los supuestos del modelo antes de confiar plenamente en él.

7. Validaciones de los supuestos del modelo

A continuación, analizaremos los residuos de mi regresión bajo las cuatro premisas que nos ayudarán a determinar si los datos se comportan de acuerdo a un modelo lineal o no:

7.1 Analisis por cada supuesto del modelo lineal en los residuos

Varianza constante

Método gráfico

plot(modelo_ln, which = 1)

Si observamos el gráfico “Residuals vs. Fitted (Valores Ajustados)”, el supuesto de aleatoriedad implica que los residuos se comporten como una nube aleatoria en todo el gráfico. En nuestro caso, la relación entre el precio y el área de construcción no presenta una asociación lineal perfecta. Por lo tanto, podemos concluir que este supuesto de linealidad no se cumple

Hipótesis

Ho:V[εi]=σ2

Ha:V[εi]≠σ2

# Test de Breusch-Pagan
bptest(modelo_ln)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo_ln
## BP = 292.99, df = 1, p-value < 2.2e-16

Observamos que debemos rechazar la hipótesis nula debido a que el valor-p es menor que la significancia estándar de 0.05. Esto significa que no cumplimos con el supuesto de varianza constante en nuestro modelo.

Normalidad

Método gráfico

plot(modelo_ln, which = 2)

En el gráfico ‘Q-Q Residuals’, el supuesto de normalidad se verifica cuando la mayoría de los residuos del modelo están cerca de la línea punteada o ‘línea de normalidad del QQ-Plot’. Observamos que este supuesto no se cumple, ya que los residuos no siguen una distribución normal.

Hipótesis

Ho:ε∼Normal

Ha:ε no ∼Normal

shapiro.test(modelo_ln$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo_ln$residuals
## W = 0.96486, p-value < 2.2e-16

Observamos que debemos rechazar la hipótesis nula debido a que el valor-p es menor que la significancia estándar de 0.05. Esto indica que no cumplimos con el supuesto de normalidad en los residuos del modelo.

Linealidad

plot(modelo_ln, which = 3)

En el gráfico ‘Scale Location’, nuestro objetivo es evidenciar si la variable dependiente está linealmente relacionada con la variable independiente. Esto se logra al observar que la línea de ajuste debe ser recta y horizontal, y que el resto de los puntos se distribuyan aleatoriamente alrededor de esta línea. En nuestro caso, no se cumple este supuesto, lo que sugiere una falta de linealidad en la relación entre las variables.

Independencia

Método gráfico

plot(modelo_ln, which = 4)

El gráfico de ‘Cook’s Distance’ tiene como objetivo detectar relaciones temporales, comúnmente llamadas tendencias, entre los datos. Sin embargo, observamos que este gráfico no se basa en una variable de tiempo ni muestra comportamientos que sugieran una relación entre los datos actuales y datos anteriores.

Hipótesis

\(Ho:E[ε_i,ε_j]=0\)

\(Ha:E[ε_i,ε_j]≠0\)

#Test de Durbin-Watson
lmtest::dwtest(modelo_ln)
## 
##  Durbin-Watson test
## 
## data:  modelo_ln
## DW = 1.443, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0

Observamos que debemos rechazar la hipótesis nula debido a que el valor-p es menor que la significancia estándar de 0.05.

8. Transformación

Dado que nuestro modelo no satisface los supuestos de un modelo lineal, es esencial considerar la posibilidad de aplicar alguna transformación que pueda mejorar los ajustes y ayudarnos a alcanzar un comportamiento más cercano a la linealidad.

8.1 Box-Cox para determinar la mejor transformación

Vamos a utilizar la técnica Box-Cox para evaluar la varianza y determinar si los datos se ajustan de manera más adecuada al supuesto de normalidad en modelos lineales y relacionados.

para ello nos basamos en que el valor calculado de \(\lambda\) sera igual a

\[g_λ(x) = \begin{cases} \frac{y^λ-1}{y},&\text{si $λ \neq$ 0} \\ log(y),&\text{si $λ$=0 }\end{cases}\]

no obstante, tambien nos sugiere algunas transformaciones conocidas a partir del valor lambda, las cuales serian:

λ -2 -1 -0.5 0 0.5 1 2
Transformación \(1/y^2\) 1/y \(1/\sqrt{y}\) \(log(y)\) \(\sqrt{y}\) y \(y^2\)

Ahora, procederemos a calcular el valor de lambda para nuestras variables de precio y área de construcción.

bc=boxcox(lm(vivienda4$preciom ~ vivienda4$areaconst), lambda = -1:1)

lambda <- bc$x[which.max(bc$y)]
cat('Valor de lambda: ',lambda, 'transformación sugerida:','log(y)')
## Valor de lambda:  -0.1313131 transformación sugerida: log(y)

El valor de lambda nos dio \(\lambda = -0.131\) y las transformaciones mas cercanas serian \(log(y)\) y \(1/\sqrt{y}\). por lo que vamos a emplear el valor exacto de lambda y las dos transformaciones mas cercanas para determinar cual seria el mejor modelo

8.2 Realizamos transformación para linealizar los modelos

Modelo \(\lambda = 0.-131\)

vivienda4$precio_transf_5 <- ((vivienda4$preciom^lambda) -1)/ lambda
modelo_7 = lm(formula = precio_transf_5 ~ areaconst, data = vivienda4)
summary(modelo_7)
## 
## Call:
## lm(formula = precio_transf_5 ~ areaconst, data = vivienda4)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.48740 -0.06527 -0.00535  0.07957  0.32740 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 3.4459708  0.0097192  354.55   <2e-16 ***
## areaconst   0.0046628  0.0001234   37.79   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1027 on 1361 degrees of freedom
## Multiple R-squared:  0.5121, Adjusted R-squared:  0.5117 
## F-statistic:  1428 on 1 and 1361 DF,  p-value: < 2.2e-16

Observamos que, para el nuevo modelo, tanto el intercepto como el coeficiente de área de construcción siguen siendo significativos, con una prueba de bondad muy cercana al valor que teníamos con el modelo inicial.

ggplot(data = vivienda4, aes(x = areaconst, y = precio_transf_5)) +
  geom_point(color = "gray52", shape = 19) +
  labs(
    title = "Precio transformado Lambda vs Área Construcción",
    x = "Áreas de construcción (m2)",
    y = "Precio transformado con lambda"
  ) +
  theme_minimal()+
  theme(plot.background = element_rect(fill = "white"),
        panel.grid = element_blank(),
        panel.border = element_blank(),
        plot.title = element_text(size = 16, hjust = 0.5),
        axis.line = element_line(size = 1, color = "#515354"))

Se observa que el gráfico de dispersión mejora la linealidad de los datos, pero aún persiste la presencia de puntos muy dispersos.

par(mfrow=c(2,2))
plot(modelo_7)

En cuanto a los supuestos de normalidad y varianza constante de los residuos, es evidente que este modelo no cumple con ninguno de estos principios.

Modelo logaritmico

vivienda4$precio_transf_1 <- log(vivienda4$preciom)
modelo_1 = lm(formula = precio_transf_1 ~ areaconst, data = vivienda4)
summary(modelo_1)
## 
## Call:
## lm(formula = precio_transf_1 ~ areaconst, data = vivienda4)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.98857 -0.13188 -0.01249  0.15595  0.66387 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 4.5512586  0.0194001  234.60   <2e-16 ***
## areaconst   0.0094530  0.0002463   38.38   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2051 on 1361 degrees of freedom
## Multiple R-squared:  0.5198, Adjusted R-squared:  0.5195 
## F-statistic:  1473 on 1 and 1361 DF,  p-value: < 2.2e-16

Observamos que, en el caso del nuevo modelo, tanto el intercepto como el coeficiente de área de construcción siguen siendo significativos, y la prueba de bondad se mantiene muy cercana al valor que teníamos con el modelo original.

ggplot(data = vivienda4, aes(x = areaconst, y = precio_transf_1)) +
  geom_point(color = "gray52", shape = 19) +
  labs(
    title = "Precio transformado Logaritmo vs Área Construcción",
    x = "Áreas de construcción (m2)",
    y = "Log(Precio)"
  ) +
  theme_minimal()+
  theme(plot.background = element_rect(fill = "white"),
        panel.grid = element_blank(),
        panel.border = element_blank(),
        plot.title = element_text(size = 16, hjust = 0.5),
        axis.line = element_line(size = 1, color = "#515354"))

Se nota una mejora en la linealidad de los datos en el gráfico de dispersión, aunque aún persiste la presencia de puntos con una dispersión significativa.

par(mfrow=c(2,2))
plot(modelo_1)

En lo que respecta a los supuestos de normalidad y varianza constante de los residuos, es evidente que este modelo no cumple con ninguno de estos principios.

Modelo ‘1/ raiz(y)’

vivienda4$precio_transf_2 <- 1 / sqrt(vivienda4$preciom)

modelo_2 = lm(formula = precio_transf_2 ~ areaconst, data = vivienda4)
summary(modelo_2)
## 
## Call:
## lm(formula = precio_transf_2 ~ areaconst, data = vivienda4)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.022689 -0.006035  0.000169  0.004798  0.033685 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  9.707e-02  7.061e-04  137.47   <2e-16 ***
## areaconst   -3.231e-04  8.963e-06  -36.05   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.007464 on 1361 degrees of freedom
## Multiple R-squared:  0.4884, Adjusted R-squared:  0.488 
## F-statistic:  1299 on 1 and 1361 DF,  p-value: < 2.2e-16

Observamos que, para este modelo, tanto el intercepto como el coeficiente de área de construcción siguen siendo significativos, y la prueba de bondad se mantiene muy cerca del valor que teníamos con el modelo original.

ggplot(data = vivienda4, aes(x = areaconst, y = precio_transf_2)) +
  geom_point(color = "gray52", shape = 19) +
  labs(
    title = "Precio transformado 1/raiz(y) vs Área Construcción",
    x = "Áreas de construcción (m2)",
    y = "1/raiz(Precio)"
  ) +
  theme_minimal()+
  theme(plot.background = element_rect(fill = "white"),
        panel.grid = element_blank(),
        panel.border = element_blank(),
        plot.title = element_text(size = 16, hjust = 0.5),
        axis.line = element_line(size = 1, color = "#515354"))

Se nota que el gráfico de dispersión mejora la linealidad de los datos, aunque a diferencia de los otros dos modelos, parece invertir la pendiente. Sin embargo, aún persiste la presencia de puntos muy dispersos en los datos.

par(mfrow=c(2,2))
plot(modelo_2)

En relación a los supuestos de normalidad y varianza constante de los residuos, este modelo no satisface ninguno de estos principios.

Conclusion punto 8.2

En todos los modelos, notamos que el ajuste no mejora de manera significativa, pero en términos de la distribución de puntos, se asemejan a un modelo lineal. Sin embargo, lo más importante es que ninguno de los modelos cumple con los principios de linealidad, lo que significa que no podemos recomendar ninguno de estos modelos para pronosticar el precio de la vivienda.

8.3 Empleamos funciones linealizables

Observamos que no obtuvimos resultados satisfactorios con las transformaciones recomendadas por Box-Cox, pero tenemos la opción de considerar otras cuatro funciones linealizables que podrían proporcionar soluciones.

‘Modelo Lin - Log’

vivienda4$areaconst_transf_1 <- log(vivienda4$areaconst)

modelo_3 = lm(formula = preciom ~ areaconst_transf_1, data = vivienda4)
summary(modelo_3)
## 
## Call:
## lm(formula = preciom ~ areaconst_transf_1, data = vivienda4)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -196.252  -21.338   -1.579   22.096  261.436 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        -635.532     19.092  -33.29   <2e-16 ***
## areaconst_transf_1  195.419      4.445   43.97   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 41.98 on 1361 degrees of freedom
## Multiple R-squared:  0.5868, Adjusted R-squared:  0.5865 
## F-statistic:  1933 on 1 and 1361 DF,  p-value: < 2.2e-16

‘Modelo Log - Log’

modelo_4 = lm(formula = precio_transf_1 ~ areaconst_transf_1, data = vivienda4)
summary(modelo_4)
## 
## Call:
## lm(formula = precio_transf_1 ~ areaconst_transf_1, data = vivienda4)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.8890 -0.1119  0.0028  0.1343  0.7538 
## 
## Coefficients:
##                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)         1.48373    0.08703   17.05   <2e-16 ***
## areaconst_transf_1  0.88175    0.02026   43.52   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1914 on 1361 degrees of freedom
## Multiple R-squared:  0.5819, Adjusted R-squared:  0.5816 
## F-statistic:  1894 on 1 and 1361 DF,  p-value: < 2.2e-16

‘Modelo 1/Lin - 1/Lin’

vivienda4$areaconst_transf_3 <- 1/vivienda4$areaconst
vivienda4$precio_transf_3 <- 1 /vivienda4$preciom

modelo_5 = lm(formula = precio_transf_3 ~ areaconst_transf_3, data = vivienda4)
summary(modelo_5)
## 
## Call:
## lm(formula = precio_transf_3 ~ areaconst_transf_3, data = vivienda4)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -0.0040604 -0.0006786 -0.0001167  0.0005261  0.0054855 
## 
## Coefficients:
##                     Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        0.0004085  0.0001190   3.433 0.000614 ***
## areaconst_transf_3 0.3520871  0.0081927  42.976  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.0009848 on 1361 degrees of freedom
## Multiple R-squared:  0.5757, Adjusted R-squared:  0.5754 
## F-statistic:  1847 on 1 and 1361 DF,  p-value: < 2.2e-16

‘Modelo Ln - Lin’

vivienda4$precio_transf_4 <- log(vivienda4$preciom, base = exp(1))

modelo_6 = lm(formula = precio_transf_4 ~ areaconst, data = vivienda4)
summary(modelo_6)
## 
## Call:
## lm(formula = precio_transf_4 ~ areaconst, data = vivienda4)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.98857 -0.13188 -0.01249  0.15595  0.66387 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 4.5512586  0.0194001  234.60   <2e-16 ***
## areaconst   0.0094530  0.0002463   38.38   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2051 on 1361 degrees of freedom
## Multiple R-squared:  0.5198, Adjusted R-squared:  0.5195 
## F-statistic:  1473 on 1 and 1361 DF,  p-value: < 2.2e-16

9 Comparación entre modelos

Veamos el resumen de nuestros modelos que llevamos hasta el momento

los_nombres <- c('lineal (Lin - Lin)','Logaritmo (Log - Lin)',' 1/raiz - Lin', 'Lin - Log','Log - Log','1/Lin - 1/Lin','Ln - Lin','lambda')
R_valores <- c(summary(modelo_ln)$r.squared,
                 summary(modelo_1)$r.squared,
                 summary(modelo_2)$r.squared,
                 summary(modelo_3)$r.squared,
                 summary(modelo_4)$r.squared,
                 summary(modelo_5)$r.squared,
                 summary(modelo_6)$r.squared,
                 summary(modelo_7)$r.squared)
Normalidad<- c(shapiro.test(modelo_ln$residuals)$p.value>0.05,
                 shapiro.test(modelo_1$residuals)$p.value>0.05,
                 shapiro.test(modelo_2$residuals)$p.value>0.05,
                 shapiro.test(modelo_3$residuals)$p.value>0.05,
                 shapiro.test(modelo_4$residuals)$p.value>0.05,
                 shapiro.test(modelo_5$residuals)$p.value>0.05,
                 shapiro.test(modelo_6$residuals)$p.value>0.05,
                 shapiro.test(modelo_7$residuals)$p.value>0.05)
Var_constante<- c(bptest(modelo_ln)$p.value>0.05,
                 bptest(modelo_1)$p.value>0.05,
                 bptest(modelo_2)$p.value>0.05,
                 bptest(modelo_3)$p.value>0.05,
                 bptest(modelo_4)$p.value>0.05,
                 bptest(modelo_5)$p.value>0.05,
                 bptest(modelo_6)$p.value>0.05,
                 bptest(modelo_7)$p.value>0.05)
kable(do.call(data.frame, data.frame(los_nombres, R_valores,Normalidad,Var_constante)),
      format = "markdown",  
      caption = "Comparativo de modelos explorados",
      align = "c", escape = FALSE,
      row.names = FALSE,
      booktabs = TRUE)
Comparativo de modelos explorados
los_nombres R_valores Normalidad Var_constante
lineal (Lin - Lin) 0.5597117 FALSE FALSE
Logaritmo (Log - Lin) 0.5198320 FALSE FALSE
1/raiz - Lin 0.4883996 FALSE FALSE
Lin - Log 0.5868495 FALSE FALSE
Log - Log 0.5819110 FALSE FALSE
1/Lin - 1/Lin 0.5757379 FALSE TRUE
Ln - Lin 0.5198320 FALSE FALSE
lambda 0.5120700 FALSE FALSE

Observamos que nuestros modelos tienen una similitud notable en términos de bondad de ajuste, pero ninguno de ellos cumple con los supuestos críticos de normalidad y varianza constante. Por lo tanto, no podemos recomendar ninguno de estos modelos de regresión en base a los resultados obtenidos en esta exploración.

10 Estimación de otros modelos

Al analizar los datos, observamos que explicar el precio de la vivienda únicamente a través del área de construcción abarca solo el 55% de la variabilidad en los precios. Sin embargo, ¿qué resultados obtendríamos si incorporamos otro factor, como la variable estrato?

#vivienda4_norte <- subset(vivienda4, zona == "Zona Norte")
modelo_ln_norte = lm(preciom ~ areaconst + zona_index, data=vivienda4)
summary(modelo_ln_norte)
## 
## Call:
## lm(formula = preciom ~ areaconst + zona_index, data = vivienda4)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -225.583  -23.822   -4.756   25.595  210.276 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 36.34697    6.03991   6.018 2.27e-09 ***
## areaconst    2.16487    0.05206  41.588  < 2e-16 ***
## zona_index   1.42876    2.34675   0.609    0.543    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 43.35 on 1360 degrees of freedom
## Multiple R-squared:  0.5598, Adjusted R-squared:  0.5592 
## F-statistic: 864.9 on 2 and 1360 DF,  p-value: < 2.2e-16

Al incluir las zonas en el modelo, como lo indicaba la correlación, observamos que este campo no contribuye significativamente a explicar el precio de la vivienda. En consecuencia, la adición de nuevos campos al modelo no parece mejorar de manera significativa su capacidad explicativa.

10.1 Modelos de regresión lineal pero sin datos atipicos extremos

Como hemos observado en los gráficos de dispersión desde el inicio, los puntos extremos son una presencia constante en nuestros datos y pueden ejercer una influencia directa en la estimación de nuestra regresión. Sin embargo, surge la pregunta: ¿qué tan significativos serían los cambios en nuestros modelos si tratamos estos valores atípicos?

Es importante recordar que ninguno de los modelos cumplió con los supuestos de normalidad y varianza constante en los residuos. Por lo tanto, definir qué valores se consideran atípicos o no atípicos dependerá de una revisión y consulta con la gerencia y expertos en el negocio para determinar cuáles valores son realmente atípicos y cómo deben ser tratados.

Para fines de investigación y basándonos en el modelo \(1/Lin - 1/Lin\), que ha demostrado cumplir con la hipótesis de varianza constante, planteamos una suposición: consideraremos un valor de residuo como sospechoso si supera en tres veces la desviación estándar. Esto se refleja en el siguiente gráfico dentro del modelo:

residuos_modelo <- residuals(modelo_5)
desviacion_estandar_residuos <- sd(residuos_modelo)
vivienda4$es_atipico <- ifelse(abs(residuos_modelo) > 3 * desviacion_estandar_residuos, "Sí", "No")

ggplot(data = vivienda4, aes(x = areaconst_transf_3, y = precio_transf_3)) +
  geom_point(aes(color = es_atipico), shape = 19)  +
  labs(
    title = "1/ Precio vs 1/ Área Construcción",
    x = "1/Áreas de construcción (m2)",
    y = "1/Precio"
  ) +
  theme_minimal()+
  theme(plot.background = element_rect(fill = "white"),
        panel.grid = element_blank(),
        panel.border = element_blank(),
        plot.title = element_text(size = 16, hjust = 0.5),
        axis.line = element_line(size = 1, color = "#515354"))

Ahora, al considerar la exclusión de los datos atípicos, analicemos cómo se comportaría el modelo \(1/Lin - 1/Lin\) en términos de su bondad de ajuste y el comportamiento de los residuos en la versión que utiliza únicamente datos no atípicos. Veamos:

vivienda4_sin_atipicos <- vivienda4[vivienda4$es_atipico == "No", ]

modelo_5_sin_atipicos = lm(formula = precio_transf_3 ~ areaconst_transf_3, data = vivienda4_sin_atipicos)
summary(modelo_5_sin_atipicos)
## 
## Call:
## lm(formula = precio_transf_3 ~ areaconst_transf_3, data = vivienda4_sin_atipicos)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -2.730e-03 -6.624e-04 -9.521e-05  5.337e-04  2.862e-03 
## 
## Coefficients:
##                     Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        0.0003339  0.0001117   2.989  0.00285 ** 
## areaconst_transf_3 0.3552398  0.0076956  46.161  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.000916 on 1348 degrees of freedom
## Multiple R-squared:  0.6125, Adjusted R-squared:  0.6122 
## F-statistic:  2131 on 1 and 1348 DF,  p-value: < 2.2e-16

Vemos que el ajuste de bondad mejoró a 0.61 y mantiene ambos coeficientes con un nivel de significancia.

par(mfrow=c(2,2))
plot(modelo_5_sin_atipicos)

Basándonos en los gráficos, podemos notar una mejora en los datos después de la exclusión de valores atípicos. Sin embargo, la normalidad de los datos aún no se aprecia claramente en forma de una nube dispersa. Ahora, exploremos cómo se comportaría la prueba de hipótesis para evaluar la normalidad.

#Normalidad
shapiro.test(modelo_5_sin_atipicos$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo_5_sin_atipicos$residuals
## W = 0.98083, p-value = 2.074e-12

Observamos que, según la prueba de hipótesis, con este nuevo tratamiento de datos, no podemos llegar a la conclusión de que nuestro modelo genere residuos con una distribución normal. Por lo tanto, no se considera un modelo adecuado.

11. Conclusiones para la gerencia

Después de llevar a cabo una exhaustiva búsqueda y analizar diversos modelos de regresión, llegamos a las siguientes conclusiones:

  • Los datos exhiben una aparente linealidad, respaldada por un fuerte indicador de coeficiente de correlación lineal de Pearson de 0.7481.

  • Al examinar los análisis univariados, notamos un sesgo a la derecha en ambas variables, con la presencia de dos picos, lo que da la impresión de tener dos muestras en un solo conjunto de datos.

  • Exploramos varios modelos de regresión con el objetivo de encontrar uno que se ajustara adecuadamente a los datos, pero lamentablemente no tuvimos éxito, ya que ninguno cumplía con los supuestos de normalidad y varianza constante.

  • También consideramos la posibilidad de incluir otras variables en el modelo, pero ninguna de ellas resultó significativa.

  • Intentamos realizar un tratamiento de valores atípicos, incluso explorando suposiciones más allá de los enfoques convencionales, pero tampoco obtuvimos resultados satisfactorios.

Por lo tanto, recomendamos a la gerencia que continúe proporcionando más variables al estudio, como el número de habitaciones, el número de baños, el piso y la disponibilidad de parqueadero, tal como se indicó en la actividad1. Esto podría contribuir a mejorar la capacidad explicativa del precio de las viviendas y permitir una mayor precisión en el modelo solicitado.