Problema

Con base en los datos de ofertas de vivienda descargadas del portal Fincaraiz para apartamentos de estrato 4 con área construida menor a \(200\: m^{2}\) (vivienda4.RDS) la inmobiliaria A&C requiere el apoyo de un científico de datos en la construcción de un modelo que lo oriente sobre los precios de inmuebles. Con este propósito el equipo de asesores a diseñado los siguientes pasos para obtener un modelo y así poder a futuro determinar los precios de los inmuebles a negociar.

  • Realice un análisis exploratorio de las variables precio de vivienda (millones de pesos COP) y área de la vivienda (metros cuadrados) - incluir gráficos e indicadores apropiados interpretados.
  • Realice un análisis exploratorio bivariado de datos, enfocado en la relación entre la variable respuesta (precio) en función de la variable predictora (área construida) - incluir gráficos e indicadores apropiados interpretados.
  • Estime el modelo de regresión lineal simple entre \(precio=f(area)+ε\)
  • Interprete los coeficientes del modelo \(β_{0}\) y \(β_{1}\) en caso de ser correcto.
  • Construir un intervalo de confianza (95%) para el coeficiente \(β_{1}\), interpretar y concluir si el coeficiente es igual a cero o no. Compare este resultado con una prueba de hipótesis t.
  • Calcule e interprete el indicador de bondad \(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?.
  • Realice la validación de los supuestos del modelo por medio de gráficos apropiados, interpretarlos y sugerir posibles soluciones si se violan algunos de ellos. Utilice las pruebas de hipótesis para la validación de supuestos y compare los resultados con lo observado en los gráficos asociados.
  • De ser necesario realice una transformación apropiada para mejorar el ajuste y supuestos del modelo.
  • De ser necesario compare el ajuste y supuestos del modelo inicial y el transformado.
  • Estime varios modelos y compare los resultados obtenidos. En el mejor de los modelos, ¿se cumplen los supuestos sobre los errores?
  • Con los resultados obtenidos construya un informe para los directivos de la inmobiliaria, indicando el modelo apropiado y sus principales características. A este informe se deben añadir los anexos como evidencia de la realización de los pasos anteriores.

 

Solución

suppressMessages(suppressWarnings(library(knitr)))
suppressMessages(suppressWarnings(library(rmarkdown)))
suppressMessages(suppressWarnings(library(paqueteMETODOS)))
suppressMessages(suppressWarnings(library(naniar)))
suppressMessages(suppressWarnings(library(mice)))
suppressMessages(suppressWarnings(library(ggmice)))
suppressMessages(suppressWarnings(library(pastecs)))
suppressMessages(suppressWarnings(library(stringr)))
suppressMessages(suppressWarnings(library(stringi)))
suppressMessages(suppressWarnings(library(dplyr)))
suppressMessages(suppressWarnings(library(tidyverse)))
suppressMessages(suppressWarnings(library(kableExtra)))
suppressMessages(suppressWarnings(library(reticulate)))
suppressMessages(suppressWarnings(library(lsr)))
suppressMessages(suppressWarnings(library(tibble)))
suppressMessages(suppressWarnings(library(patchwork)))
suppressMessages(suppressWarnings(library(sf)))
suppressMessages(suppressWarnings(library(osmdata)))
suppressMessages(suppressWarnings(library(mapview)))
suppressMessages(suppressWarnings(library(leaflet)))
suppressMessages(suppressWarnings(library(heatmaply)))
suppressMessages(suppressWarnings(library(ggplot2)))
suppressMessages(suppressWarnings(library(stats)))
suppressMessages(suppressWarnings(library(e1071)))
suppressMessages(suppressWarnings(library(ggstatsplot)))
suppressMessages(suppressWarnings(library(grid)))
suppressMessages(suppressWarnings(library(gridExtra)))
suppressMessages(suppressWarnings(library(moments)))
suppressMessages(suppressWarnings(library(diptest)))
suppressMessages(suppressWarnings(library(LaplacesDemon)))
suppressMessages(suppressWarnings(library(ggExtra)))
suppressMessages(suppressWarnings(library(RColorBrewer)))
suppressMessages(suppressWarnings(library(hexbin)))
suppressMessages(suppressWarnings(library(MASS)))
suppressMessages(suppressWarnings(library(ggfortify)))
suppressMessages(suppressWarnings(library(latex2exp)))
suppressMessages(suppressWarnings(library(lmtest)))
suppressMessages(suppressWarnings(library(interactions)))

data(vivienda4)

Análisis Exploratorio

Numéricas

df <- subset(vivienda4, select = -c(zona, estrato, tipo))
options(scipen = 999)
skewness_values <- sapply(df, skewness)

summary_df <- stat.desc(df) 
summary_df <- round(summary_df, 2)
summary_df <- rbind(summary_df, round(skewness_values, 2))
rownames(summary_df)[nrow(summary_df)] <- "Skewness"

shapiro_results <- sapply(df, function(column) {
  test_result <- shapiro.test(column)
  c(W = round(test_result$statistic,2), p_value = formatC(test_result$p.value, format="e", digits=2))
})

summary_df <- rbind(summary_df, shapiro_results)
rownames(summary_df)[(nrow(summary_df) - 1):nrow(summary_df)] <- c("Shapiro W", "Shapiro p-value")

quartiles <- sapply(df, function(column) {
  quantiles <- quantile(column, probs = c(0.25, 0.75))
  c(Q1 = quantiles[1], Q3 = quantiles[2])
})

summary_df <- rbind(summary_df, round(quartiles, 2))
rownames(summary_df)[(nrow(summary_df) - 1):nrow(summary_df)] <- c("Q1 (25%)", "Q3 (75%)")

kurtosis_values <- sapply(df, kurtosis)
summary_df <- rbind(summary_df, round(kurtosis_values, 2))
rownames(summary_df)[nrow(summary_df)] <- "Kurtosis"

mad_values <- sapply(df, mad)
summary_df <- rbind(summary_df, round(mad_values, 2))
rownames(summary_df)[nrow(summary_df)] <- "Mean Absolute Deviation"

# Define the order of the rows
row_order <- c("mean", "std.dev", "var", "coef.var", "Mean Absolute Deviation", "Q1 (25%)", "median", "Q3 (75%)", "min", "max", "range", "sum", "SE.mean", "CI.mean.0.95", "Skewness", "Kurtosis", "Shapiro W", "Shapiro p-value")

# Order the rows in summary_df
summary_df <- summary_df[match(row_order, rownames(summary_df)), ]

paged_table(summary_df, options = list(rows.print = 20)) %>%
  kable(caption = 'Variables Numéricas')
Variables Numéricas
preciom areaconst
mean 225.37 87.63
std.dev 85.89 36.35
var 7376.27 1321.07
coef.var 0.38 0.41
Mean Absolute Deviation 75.61 22.24
Q1 (25%) 160 60
median 210 75
Q3 (75%) 265 98
min 78 40
max 760 200
range 682 160
sum 384489 149496
SE.mean 2.08 0.88
CI.mean.0.95 4.08 1.73
Skewness 1.49 1.53
Kurtosis 6.57 4.68
Shapiro W 0.89 0.82
Shapiro p-value 2.84e-33 2.51e-40

preciom

# Run the dip test and store the result
dip_test_result <- dip.test(vivienda4$preciom)

# Extract the D statistic and p-value
D_statistic <- dip_test_result$statistic
p_value <- dip_test_result$p.value

#is.unimodal(vivienda4$preciom)
#is.multimodal(vivienda4$preciom)

# Print the results in markdown
cat(paste0("Como podemos observar en los valores de la tabla anterior y en las gráficas a continuación, los valores de `preciom` se distribuyen con asimetría positiva, principalmente para valores menores a 400 millones de pesos con Q1=160 y Q3=265 millones de pesos. El estadístico D del Hartigans' dip test para uni- y multimodalidad sobre la columna de `preciom` es **", round(D_statistic, 6), "**. El valor p es menor a **", format(2.2e-15, scientific = TRUE), "**. La hipótesis alternativa es que la distribución no es unimodal. Del mismo modo, en la tabla anterior se presentan los valores de la prueba Shapiro-Wilks obteniendo que la distribución tampoco es normal para un valor de p de **", format(2.84e-33, scientific = TRUE), "** y un valor del estadístico W de**", 0.89,"**"))

Como podemos observar en los valores de la tabla anterior y en las gráficas a continuación, los valores de preciom se distribuyen con asimetría positiva, principalmente para valores menores a 400 millones de pesos con Q1=160 y Q3=265 millones de pesos. El estadístico D del Hartigans’ dip test para uni- y multimodalidad sobre la columna de preciom es 0.027806. El valor p es menor a 2.2e-15. La hipótesis alternativa es que la distribución no es unimodal. Del mismo modo, en la tabla anterior se presentan los valores de la prueba Shapiro-Wilks obteniendo que la distribución tampoco es normal para un valor de p de 2.84e-33 y un valor del estadístico W de0.89

df <- subset(vivienda4, select = c(preciom))

# for reproducibility
set.seed(123)

# creating a plot
p <- gghistostats(
  data            = df,
  x               = preciom,
  xlab            = "preciom",
  centrality.type = "np"
)

p2 <- ggplot(df, aes(x="", y=preciom)) +
geom_violin(trim = T, fill = "gray", width=0.3) + 
geom_jitter(height = 0, width = 0.1, alpha=0.1, size=1, colour="#20263d") +
geom_boxplot(notch = TRUE, width=0.1)+
stat_summary(fun = "mean", geom = "point", shape = 23, size = 3, fill = "#20263d")+
xlab("")+
theme_bw()+
theme(axis.title.y = element_text(face = "bold", size=10))

grid.arrange(p, p2, nrow = 2, top = textGrob("Descripción de preciom", gp = gpar(fontface = "bold")))

areaconst

# Run the dip test and store the result
dip_test_result <- dip.test(vivienda4$areaconst)
# Extract the D statistic and p-value
D_statistic <- dip_test_result$statistic
p_value <- dip_test_result$p.value

# Print the results in markdown
cat(paste0("Al igual que `preciom`, los valores de `areaconst` se distribuyen con asimetría positiva, principalmente para valores menores a 100 $m^{2}$ con Q1=60 y Q3=98 $m^{2}$. El estadístico D del Hartigans' dip test para uni- y multimodalidad sobre la columna de `preciom` es **", round(D_statistic, 6), "**. El valor p es menor a **", format(2.2e-15, scientific = TRUE), "**. La hipótesis alternativa es que la distribución no es unimodal, como también se puede apreciar en el histograma aunque no de forma tan definida como `preciom`. Del mismo modo, en la tabla anterior se presentan los valores de la prueba Shapiro-Wilks obteniendo que la distribución tampoco es normal para un valor de p de **", format(2.51e-40, scientific = TRUE), "** y un valor del estadístico W de**", 0.82,"**"))

Al igual que preciom, los valores de areaconst se distribuyen con asimetría positiva, principalmente para valores menores a 100 \(m^{2}\) con Q1=60 y Q3=98 \(m^{2}\). El estadístico D del Hartigans’ dip test para uni- y multimodalidad sobre la columna de preciom es 0.024439. El valor p es menor a 2.2e-15. La hipótesis alternativa es que la distribución no es unimodal, como también se puede apreciar en el histograma aunque no de forma tan definida como preciom. Del mismo modo, en la tabla anterior se presentan los valores de la prueba Shapiro-Wilks obteniendo que la distribución tampoco es normal para un valor de p de 2.51e-40 y un valor del estadístico W de0.82

df <- subset(vivienda4, select = c(areaconst))

# for reproducibility
set.seed(123)

# creating a plot
p <- gghistostats(
  data            = df,
  x               = areaconst,
  xlab            = "areaconst",
  centrality.type = "np"
)

p2 <- ggplot(df, aes(x="", y=areaconst)) +
geom_violin(trim = T, fill = "gray", width=0.3) + 
geom_jitter(height = 0, width = 0.1, alpha=0.1, size=1, colour="#20263d") +
geom_boxplot(notch = TRUE, width=0.1)+
stat_summary(fun = "mean", geom = "point", shape = 23, size = 3, fill = "#20263d")+
xlab("")+
theme_bw()+
theme(axis.title.y = element_text(face = "bold", size=10))

grid.arrange(p, p2, nrow = 2, top = textGrob("Descripción de areaconst", gp = gpar(fontface = "bold")))

Categóricas

Tipo

df <- data.table::copy(vivienda4)
counts <- table(df$tipo)


percentages <- prop.table(counts) * 100

mode_value <- names(which.max(counts))

result <- data.frame(Value = names(counts),
                     Mode = ifelse(names(counts) == mode_value, mode_value, NA),
                     Count = as.integer(counts),
                     Prc = round(percentages, 2))

result <-  subset(result, select = c(Value, Mode, Count, Prc.Freq))
paged_table(result, options = list(rows.print = 15)) %>%
  kable(caption = 'Variables Categóricas - Tipo')
Variables Categóricas - Tipo
Value Mode Count Prc.Freq
Apartamento Apartamento 1363 79.89
Casa NA 343 20.11
categorical_df <- subset(df, select = c(tipo))
for (i in names(categorical_df)) {
  x <- categorical_df[, i]
  
  if (i == 'barrio') {
    counts <- table(x)
    top_counts <- counts[order(-counts)][1:5]
    barplot(top_counts, xlab = 'barrio', ylab = 'Frequencia', main = paste('Barplot', i), lwd = 2, col=c("#003049","#d62828", "#f77f00", "#fcbf49", "#eae2b7"))
  } else {
    barplot(table(x), xlab = i, ylab = 'Frequencia', main = paste('Barplot', i), lwd = 2, col=c("#003049", "#d62828", "#E75414", "#F77F00", "#FA9F25", "#FCBF49", "#F8C865", "#F3D180"))
  }
}

Zona

counts <- table(df$zona)


percentages <- prop.table(counts) * 100

mode_value <- names(which.max(counts))

result <- data.frame(Value = names(counts),
                     Mode = ifelse(names(counts) == mode_value, mode_value, NA),
                     Count = as.integer(counts),
                     Prc = round(percentages, 2))

result <-  subset(result, select = c(Value, Mode, Count, Prc.Freq))
paged_table(result, options = list(rows.print = 15)) %>%
  kable(caption = 'Variables Categóricas - Zona')
Variables Categóricas - Zona
Value Mode Count Prc.Freq
Zona Centro NA 8 0.47
Zona Norte NA 288 16.88
Zona Oeste NA 60 3.52
Zona Oriente NA 6 0.35
Zona Sur Zona Sur 1344 78.78
categorical_df <- subset(df, select = c(zona))
for (i in names(categorical_df)) {
  x <- categorical_df[, i]
  
  if (i == 'barrio') {
    counts <- table(x)
    top_counts <- counts[order(-counts)][1:5]
    barplot(top_counts, xlab = 'barrio', ylab = 'Frequencia', main = paste('Barplot', i), lwd = 2, col=c("#003049","#d62828", "#f77f00", "#fcbf49", "#eae2b7"))
  } else {
    barplot(table(x), xlab = i, ylab = 'Frequencia', main = paste('Barplot', i), lwd = 2, col=c("#003049", "#6B2C39","#d62828", "#E75414", "#F77F00", "#FA9F25", "#FCBF49", "#F8C865", "#F3D180"))
  }
}

Análisis Exploratorio Bivariado

areaconst vs preciom

Al graficar preciom en función de areaconst encontramos una acumulación de valores menos a 200 millones de pesos para preciom y de áreas construidas menores a 100 \(m^{2}\). Por otro lado, para esta misma región se aprecia una relación proporcional entre el precio y el área pero después de 100 \(m^{2}\) la tendencia no es tan marcada. Finalmente, se encuentra la acumulación de datos para dos sectores, los primeros para áreas entre 59 a 61 \(m^2\) con precios de 160 a 162 millones de pesos y una segunda región para áreas de 72 a 75 \(m^2\) con precios entre 215 a 226 millones.

# classic plot :
p <- ggplot(vivienda4, aes(x=areaconst, y=preciom)) +
      geom_point(color="#20263d", alpha=0.2) +
      #ggtitle("Área construida vs Precio")
      theme_bw()+
      theme(legend.position="none")
            #plot.title = element_text(face = "bold", hjust=0.5)) 

p3 <- ggMarginal(p, margins, color="#20263d", size=7, 
                 xparams = list(linewidth = 1), 
                 yparams=list(linewidth=1))


# Create data
x <- vivienda4$areaconst
y <- vivienda4$preciom

# Create the hexbin object
bin <- hexbin(x, y, xbins=40)
# Convert the hexbin object to a data frame
bin_df <- data.frame (hcell2xy (bin), counts = bin@count)

# Plot the hexbin object using ggplot
p_hex <- ggplot(bin_df, aes(x=x, y=y, fill=counts)) +
  geom_hex(stat="identity") +
  theme_minimal() +
  scale_fill_gradientn(colours = rev(brewer.pal(11,'Spectral'))) +
  labs(x="areaconst", y="preciom", fill="Counts")


# Arrange the plots in a grid
grid.arrange(p3, p_hex, nrow = 1, top = textGrob("areaconst vs preciom", gp = gpar(fontface = "bold")))

areaconst vs preciom - tipo

# classic plot

filtered_df <- vivienda4 %>%
                  filter(tipo == "Casa")

p_1 <- ggplot(filtered_df, aes(x=areaconst, y=preciom)) +
      geom_point(alpha=0.2, size=2, color="#6ea16a") +
      theme_bw()

p_1 <- p_1 +
       annotate("text", x = 60, y = 750, label = "Casa", fontface =2)


filtered_df <- vivienda4 %>%
                  filter(tipo == "Apartamento")

# classic plot :
p_2 <- ggplot(filtered_df, aes(x=areaconst, y=preciom)) +
      geom_point(alpha=0.2, size=2, color="#e3665d") +
      theme_bw()

p_2 <- p_2 +
       annotate("text", x = 65, y = 750, label = "Apartamento", fontface =2)

grid.arrange(p_1, p_2, nrow = 1, top = textGrob("areaconst vs preciom - tipo", gp = gpar(fontface = "bold")))

areaconst vs preciom - zona

filtered_df <- vivienda4 %>%
                  filter(zona == "Zona Centro")

p_1 <- ggplot(filtered_df, aes(x=areaconst, y=preciom, colour=tipo)) +
      geom_point(alpha=0.5, size=2) +
      ylim(c(0,800))+
   xlim(c(40,200))+
      theme_bw()+
      theme(legend.position="none")

p_1 <- p_1 +
       annotate("text", x = 65, y = 780, label = "Zona Centro", fontface =2)


filtered_df <- vivienda4 %>%
                  filter(zona == "Zona Norte")

# classic plot :
p_2 <- ggplot(filtered_df, aes(x=areaconst, y=preciom, colour=tipo)) +
      geom_point(alpha=0.2, size=2) +
   ylim(c(0,800))+
  xlim(c(40,200))+
      theme_bw()+
      theme(legend.position="none")

p_2 <- p_2 +
       annotate("text",x = 65, y = 780, label = "Zona Norte", fontface =2)

filtered_df <- vivienda4 %>%
                  filter(zona == "Zona Oeste")

# classic plot :
p_3 <- ggplot(filtered_df, aes(x=areaconst, y=preciom, colour=tipo)) +
      geom_point(alpha=0.5, size=2) +
   ylim(c(0,800))+
  xlim(c(40,200))+
      theme_bw()+
      theme(legend.position="none")

p_3 <- p_3 +
       annotate("text", x = 64, y = 780, label = "Zona Oeste", fontface =2)

filtered_df <- vivienda4 %>%
                  filter(zona == "Zona Oriente")

# classic plot :
p_4 <- ggplot(filtered_df, aes(x=areaconst, y=preciom, colour=tipo)) +
      geom_point(alpha=0.5, size=2) +
   ylim(c(0,800))+
  xlim(c(40,200))+
      theme_bw()+
      theme(legend.position="none")

p_4 <- p_4 +
       annotate("text", x = 67, y = 780, label = "Zona Oriente", fontface =2)

filtered_df <- vivienda4 %>%
                  filter(zona == "Zona Sur")

# classic plot :
p_5 <- ggplot(filtered_df, aes(x=areaconst, y=preciom, colour=tipo)) +
      geom_point(alpha=0.2, size=2) +
   ylim(c(0,800))+
  xlim(c(40,200))+
      theme_bw()+
      theme(legend.position="none")

p_5 <- p_5 +
       annotate("text",x = 60, y = 780, label = "Zona Sur", fontface =2)


grid.arrange(p_2, p_5, p_3, p_4, p_1, nrow = 3, top = textGrob("areaconst vs preciom - zona", gp = gpar(fontface = "bold")))

areaconst vs Categóricas

suppressWarnings({

plt <- ggbetweenstats(
  data = vivienda4,
  x = tipo,
  y = areaconst
)

plt_2 <- ggbetweenstats(
  data = vivienda4,
  x = zona,
  y = areaconst
)

grid.arrange(plt, plt_2, nrow = 2, top = textGrob("areaconst vs Variables categóricas", gp = gpar(fontface = "bold")))})

precio vs Categóricas

suppressWarnings({

plt <- ggbetweenstats(
  data = vivienda4,
  x = tipo,
  y = preciom
)

plt_2 <- ggbetweenstats(
  data = vivienda4,
  x = zona,
  y = preciom
)

grid.arrange(plt, plt_2, nrow = 2, top = textGrob("preciom vs Variables categóricas", gp = gpar(fontface = "bold")))})

Correlaciones

Spearman - Theil

Kendall - Theil

 

 

 

 

Modelos

Modelo Lineal Base

p <- ggplot(vivienda4, aes(x=areaconst, y=preciom)) +
      geom_point(color="#20263d", alpha=0.2) +
      ggtitle("Área construida vs Precio")+
      theme_bw()+
      theme(legend.position="none")+
      geom_smooth(
      aes(color = "y ~ x", fill = "y ~ x"),
      method = "lm", 
      formula = y~x, 
      se = TRUE, 
      fullrange = TRUE)

# Fit a linear model
fit <- lm(preciom ~ areaconst, data = vivienda4)
conf_int <- confint(fit, level=0.95)
ci_areaconst <- conf_int["areaconst", ]


r_squared <- summary(fit)$r.squared
spearman <- cor(vivienda4$areaconst, vivienda4$preciom,  method = "spearman")
kendall <- cor(vivienda4$areaconst, vivienda4$preciom,  method = "kendall")

# Get the coefficients of the linear model
intercept <- round(coef(fit)[1],3)
slope <- round(coef(fit)[2],3)

# Get the summary of the model
summary_fit <- summary(fit)
coefficients_table <- summary_fit$coefficients
coefficients_df <- as.data.frame(coefficients_table)
coefficients_df$`Pr(>|t|)` <- formatC(coefficients_df$`Pr(>|t|)`, format="e", digits=2)
coefficients_df$Estimate <- round(coefficients_df$Estimate, 3)
coefficients_df$`Std. Error` <- round(coefficients_df$`Std. Error`, 3)
coefficients_df$`t value` <- round(coefficients_df$`t value`, 3)
paged_table(coefficients_df, options = list(rows.print = 20)) %>%
  kable(caption = 'Resumen coeficientes Modelo Base')
Resumen coeficientes Modelo Base
Estimate Std. Error t value Pr(>|t|)
(Intercept) 67.381 3.510 19.197 1.65e-74
areaconst 1.803 0.037 48.728 0.00e+00
# Get the R-squared value
cat(paste0("**Resultados**\n\n

- La función obtenida para el ajuste lineal es $preciom =", slope, "(areaconst)+", intercept, "$. En el caso de $β_{1}$ podemos decir que por cada $m^2$ de área construida se tiene un aumento de $", slope, "$ millones de pesos.\n\n
           
- En la tabla anterior podemos ver los valores de `t-value` y `Pr(>|t|)`. Para el caso de $β_{0}$ y $β_{1}$ encontramos valores menores a $2e-16$ por lo que para una nivel de significancia de 0.05 se niega la hipótesis nula. Esto nos permite concluir que ambos coeficientes son diferentes de 0.\n\n
           
- El valor del coeficiente de Pearson ($R^2$) es $", round(r_squared, 4), "$ indicando una relación lineal positiva moderada. Por otro lado los coeficientes de Spearman y Kendall son $", round(spearman,4),"$ y $", round(kendall,4), "$ respectivamente. De ambos, el más interesante es el coeficiente de Spearman que indica una relación monotónica entre las variables de `preciom` y `areaconst` por lo que podríamos explorar una ecuación polinómica para esta relación.\n\n

- Respecto al intervalo de confianza ($95$%) se encontró que este corresponde con: $", round(ci_areaconst[1], 4), "$ a $", round(ci_areaconst[2], 4), "$ lo que implica que el valor de la pendiente ($β_{1}$) y por tanto `preciom` por  $m^2$ puede variar entre $", round(ci_areaconst[1], 4), "$ a $", round(ci_areaconst[2], 4), "$ millones de pesos."))

Resultados

  • La función obtenida para el ajuste lineal es \(preciom =1.803(areaconst)+67.381\). En el caso de \(β_{1}\) podemos decir que por cada \(m^2\) de área construida se tiene un aumento de \(1.803\) millones de pesos.

  • En la tabla anterior podemos ver los valores de t-value y Pr(>|t|). Para el caso de \(β_{0}\) y \(β_{1}\) encontramos valores menores a \(2e-16\) por lo que para una nivel de significancia de 0.05 se niega la hipótesis nula. Esto nos permite concluir que ambos coeficientes son diferentes de 0.

  • El valor del coeficiente de Pearson (\(R^2\)) es \(0.5822\) indicando una relación lineal positiva moderada. Por otro lado los coeficientes de Spearman y Kendall son \(0.8277\) y \(0.648\) respectivamente. De ambos, el más interesante es el coeficiente de Spearman que indica una relación monotónica entre las variables de preciom y areaconst por lo que podríamos explorar una ecuación polinómica para esta relación.

  • Respecto al intervalo de confianza (\(95\)%) se encontró que este corresponde con: \(1.7304\) a \(1.8755\) lo que implica que el valor de la pendiente (\(β_{1}\)) y por tanto preciom por \(m^2\) puede variar entre \(1.7304\) a \(1.8755\) millones de pesos.

p <- p +
  annotate("text", x = 68, y = 720, label = paste0(" preciom = ", slope, " (areaconst) + ", intercept)) +
  annotate("text", x = 49, y = 679, label = paste0(" R^2 = ", round(r_squared, 4)))
p

cat(paste0("**Validación de supuestos**\n\n

- **Linealidad y Homoscedasticidad:** Los gráficos de Residuals vs Fitted y Scale - Location muestran a primera vista no linealidad y heterosquedasticidad respectivamente.\n\n

- **Normalidad:** El Normal Q-Q muestra que los puntos no siguen una distribución normal especialemente en la cola superior que puede deberse a la presencia de outliers o que los residuos tienen una distribución con colas más pesadas que la distribución normal.\n\n

- **Presencia de valores extremos y de alta influencia:** Los gráficos Result vs Leverage, Cook's distance y Cook's dist vs leverage permiten determinar los outliers y los puntos de alta influencia en el modelo cuando al ser incluidos o excluidos, estos alteran los resultados de la regresión. Estos valores, usualmente están relacionados con valores altos de residuales. En el gráfico de Result vs Leverage, todos los puntos están dentro de las líneas de distancia de Cook por lo que los datos parecen no mostrar puntos de alta influencia pero si se presentan outliers con índices 961, 957 y 1050.

"))

Validación de supuestos

  • Linealidad y Homoscedasticidad: Los gráficos de Residuals vs Fitted y Scale - Location muestran a primera vista no linealidad y heterosquedasticidad respectivamente.

  • Normalidad: El Normal Q-Q muestra que los puntos no siguen una distribución normal especialemente en la cola superior que puede deberse a la presencia de outliers o que los residuos tienen una distribución con colas más pesadas que la distribución normal.

  • Presencia de valores extremos y de alta influencia: Los gráficos Result vs Leverage, Cook’s distance y Cook’s dist vs leverage permiten determinar los outliers y los puntos de alta influencia en el modelo cuando al ser incluidos o excluidos, estos alteran los resultados de la regresión. Estos valores, usualmente están relacionados con valores altos de residuales. En el gráfico de Result vs Leverage, todos los puntos están dentro de las líneas de distancia de Cook por lo que los datos parecen no mostrar puntos de alta influencia pero si se presentan outliers con índices 961, 957 y 1050.

autoplot(fit, which = 1:6)

test <- predict(fit, list(areaconst=110), interval="confidence" )

pred_value <- round(test[,"fit"],3)
lwr_value <- round(test[,"lwr"],3)
upr_value <- round(test[,"upr"],3)

cat(paste0("**Precio promedio estimado**\n\n

- El precio promedio estimado para un apartamento de $110 m^2$ es $", pred_value, "$ millones de pesos con un intervalo de confianza $",lwr_value,"$ - $",upr_value,"$ por lo que un apartamento en la misma zona a $200$ millones de pesos puede ser una buena oferta al ahorrar aproximadamente $66$ millones de pesos.\n\n 

- Como consideraciones adicionales para éste conjunto de datos, debería tenerse en cuenta la Zona en la que está ubicado el apartamento dado que las zonas Norte, Sur, Oeste, Oriente y Centro poseen valores promedio de $204.59$, $201.71$, $200.77$, $262.50$ y $236.00$ millones de pesos respectivamente. Como variables adicionales, se puede pensar en cantidad de habitaciones, baños, si posee o no parqueadero, la antigüedad de la propiedad y si se ha renovado."))

Precio promedio estimado

  • El precio promedio estimado para un apartamento de \(110 m^2\) es \(265.708\) millones de pesos con un intervalo de confianza \(262.611\) - \(268.805\) por lo que un apartamento en la misma zona a \(200\) millones de pesos puede ser una buena oferta al ahorrar aproximadamente \(66\) millones de pesos.

  • Como consideraciones adicionales para éste conjunto de datos, debería tenerse en cuenta la Zona en la que está ubicado el apartamento dado que las zonas Norte, Sur, Oeste, Oriente y Centro poseen valores promedio de \(204.59\), \(201.71\), \(200.77\), \(262.50\) y \(236.00\) millones de pesos respectivamente. Como variables adicionales, se puede pensar en cantidad de habitaciones, baños, si posee o no parqueadero, la antigüedad de la propiedad y si se ha renovado.

shapiro.test(fit$residuals)
Shapiro-Wilk normality test

data: fit$residuals W = 0.92671, p-value < 0.00000000000000022

normtest::jb.norm.test(fit$residuals)
Jarque-Bera test for normality

data: fit$residuals JB = 3069.4, p-value < 0.00000000000000022

nortest::ad.test(fit$residuals)
Anderson-Darling normality test

data: fit$residuals A = 22.455, p-value < 0.00000000000000022

nortest::lillie.test(fit$residuals)
Lilliefors (Kolmogorov-Smirnov) normality test

data: fit$residuals D = 0.077968, p-value < 0.00000000000000022

lmtest::bptest(fit)
studentized Breusch-Pagan test

data: fit BP = 152.8, df = 1, p-value < 0.00000000000000022

lmtest::gqtest(fit)
Goldfeld-Quandt test

data: fit GQ = 0.78143, df1 = 851, df2 = 851, p-value = 0.9998 alternative hypothesis: variance increases from segment 1 to 2

lmtest::dwtest(fit)
Durbin-Watson test

data: fit DW = 1.6713, p-value = 0.000000000005124 alternative hypothesis: true autocorrelation is greater than 0

 

 

Modelo Box-Cox preciom

suppressWarnings({
  
fit <- lm(preciom ~ areaconst, data = vivienda4)
bc <- boxcox(fit, lambda = seq(-2, 5, 0.05), plotit=FALSE)
bc_data <- data.frame(
  lambda = bc$x,
  log_likelihood = bc$y)

# The optimal lambda is the one that maximizes the log-likelihood
lambda_optimal <- bc$x[which.max(bc$y)]
vivienda4$preciom_transformed <- (vivienda4$preciom^lambda_optimal - 1) / lambda_optimal


fit_transformed <- lm(preciom_transformed ~ areaconst, data = vivienda4)
summary_fit <- summary(fit_transformed)
coefficients_table <- summary_fit$coefficients
coefficients_df <- as.data.frame(coefficients_table)
coefficients_df$`Pr(>|t|)` <- formatC(coefficients_df$`Pr(>|t|)`, format="e", digits=2)
coefficients_df$Estimate <- round(coefficients_df$Estimate, 3)
coefficients_df$`Std. Error` <- round(coefficients_df$`Std. Error`, 3)
coefficients_df$`t value` <- round(coefficients_df$`t value`, 3)
paged_table(coefficients_df, options = list(rows.print = 20)) %>%
  kable(caption = 'Resumen coeficientes Modelo Box-Cox')})
Resumen coeficientes Modelo Box-Cox
Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.777 0.008 450.118 0.00e+00
areaconst 0.004 0.000 47.127 4.71e-311
# Plot lambda vs log_likelihood
p<-ggplot(bc_data, aes(x = lambda, y = log_likelihood)) +
  geom_line(color = "gray", linewidth=1) +
  geom_point(aes(x = lambda_optimal, y = max(log_likelihood)), color = "red", size=3) +
  geom_vline(aes(xintercept = lambda_optimal), linetype="dashed", color = "black") +
  labs(title = TeX("$\\lambda$ vs Log-Likelihood"),
       x = TeX("$\\lambda$"),
       y = "Log-Likelihood") +
  theme_bw()

p <- p +
  annotate("text", x = 3.6, y = -3960, label = paste0("Optimal Lambda: ", lambda_optimal))
p
## Warning in geom_point(aes(x = lambda_optimal, y = max(log_likelihood)), : All aesthetics have length 1, but the data has 141 rows.
## ℹ Did you mean to use `annotate()`?

suppressWarnings({
p <- ggplot(vivienda4, aes(x=areaconst, y=preciom_transformed)) +
      geom_point(color="#20263d", alpha=0.2) +
      ggtitle("Área construida vs Precio transformado")+
      theme_bw()+
      theme(legend.position="none")+
      stat_smooth(method='lm', formula = y ~ x, se=TRUE, level=0.95)

conf_int <- confint(fit_transformed, level=0.95)
ci_areaconst <- conf_int["areaconst", ]

# Get the coefficients of the linear model
intercept <- round(coef(fit_transformed)[1],3)
slope <- round(coef(fit_transformed)[2],3)

# Get the R-squared value
r_squared <- summary(fit_transformed)$r.squared
x <- vivienda4$areaconst
y <- vivienda4$preciom_transformed


cat(paste0("**Resultados**\n\n

- La función obtenida para el ajuste lineal es $preciom\\_transformed =", slope, "(areaconst)+", intercept, "$. En el caso de $β_{1}$ podemos decir que por cada $m^2$ de área construida se tiene un aumento de $", round((lambda_optimal * slope + 1)^(1/lambda_optimal)),4), "$ millones de pesos.\n\n
           
- En la tabla anterior podemos ver los valores de `t-value` y `Pr(>|t|)`. Para el caso de $β_{0}$ y $β_{1}$ encontramos valores menores a $2e-16$ por lo que para una nivel de significancia de 0.05 se niega la hipótesis nula. Esto nos permite concluir que ambos coeficientes son diferentes de 0.\n\n
           
- El valor del coeficiente de Pearson ($R^2$) es ", round(r_squared, 4), " indicando una relación lineal positiva moderada.\n\n

- Respecto al intervalo de confianza ($95$%) se encontró que este corresponde con: ", round(ci_areaconst[1], 4), " a ", round(ci_areaconst[2], 4), " lo que implica que el valor de la pendiente ($β_{1}$) y por tanto `preciom` por  $m^2$ puede variar entre ", round((lambda_optimal * ci_areaconst[1] + 1)^(1/lambda_optimal), 4), " a ", round((lambda_optimal * ci_areaconst[2] + 1)^(1/lambda_optimal), 4), " millones de pesos.")

p <- p +
  annotate("text", x = 79, y = 4.85, label = paste0(" preciom_transformed = ", slope, " (areaconst) + ", intercept)) +
  annotate("text", x = 72, y = 4.75, label = TeX("preciom=($\\lambda\\cdot$ preciom_transformed+ 1)$^{1/\\lambda}$"))+

  #preciom_prediction <- (lambda_optimal * prediction + 1)^(1/lambda_optimal)
  annotate("text", x = 49, y = 4.65, label = paste0(" R^2 = ", round(r_squared, 4)))})

Resultados

  • La función obtenida para el ajuste lineal es \(preciom\_transformed =0.004(areaconst)+3.777\). En el caso de \(β_{1}\) podemos decir que por cada \(m^2\) de área construida se tiene un aumento de $14 $ millones de pesos.

  • En la tabla anterior podemos ver los valores de t-value y Pr(>|t|). Para el caso de \(β_{0}\) y \(β_{1}\) encontramos valores menores a \(2e-16\) por lo que para una nivel de significancia de 0.05 se niega la hipótesis nula. Esto nos permite concluir que ambos coeficientes son diferentes de 0.

  • El valor del coeficiente de Pearson (\(R^2\)) es 0.5659 indicando una relación lineal positiva moderada.

  • Respecto al intervalo de confianza (\(95\)%) se encontró que este corresponde con: 0.004 a 0.0043 lo que implica que el valor de la pendiente (\(β_{1}\)) y por tanto preciom por \(m^2\) puede variar entre 1.004 a 1.0044 millones de pesos.

p
## Warning in is.na(x): is.na() aplicado a un objeto que no es (lista o vector) de
## tipo 'expression

cat(paste0("**Validación de supuestos**\n\n

- **Linealidad y Homoscedasticidad:** Los gráficos de Residuals vs Fitted y Scale - Location muestran a primera vista no linealidad y heterosquedasticidad respectivamente.\n\n

- **Normalidad:** El Normal Q-Q muestra que los puntos siguen una distribución más cercana a la normal respecto al anterior modelo.\n\n

- **Presencia de valores extremos y de alta influencia:**En el gráfico de Result vs Leverage, todos los puntos están dentro de las líneas de distancia de Cook por lo que los datos parecen no mostrar puntos de alta influencia pero si se presentan outliers con índices 531, 696 y 1562.

"))

Validación de supuestos

  • Linealidad y Homoscedasticidad: Los gráficos de Residuals vs Fitted y Scale - Location muestran a primera vista no linealidad y heterosquedasticidad respectivamente.

  • Normalidad: El Normal Q-Q muestra que los puntos siguen una distribución más cercana a la normal respecto al anterior modelo.

  • Presencia de valores extremos y de alta influencia:En el gráfico de Result vs Leverage, todos los puntos están dentro de las líneas de distancia de Cook por lo que los datos parecen no mostrar puntos de alta influencia pero si se presentan outliers con índices 531, 696 y 1562.

autoplot(fit_transformed, which = 1:6)

shapiro.test(fit_transformed$residuals)
Shapiro-Wilk normality test

data: fit_transformed$residuals W = 0.99384, p-value = 0.000001556

normtest::jb.norm.test(fit_transformed$residuals)
Jarque-Bera test for normality

data: fit_transformed$residuals JB = 7.6144, p-value = 0.033

nortest::ad.test(fit_transformed$residuals)
Anderson-Darling normality test

data: fit_transformed$residuals A = 3.9255, p-value = 0.00000000089

nortest::lillie.test(fit_transformed$residuals)
Lilliefors (Kolmogorov-Smirnov) normality test

data: fit_transformed$residuals D = 0.048457, p-value = 0.0000000005191

lmtest::bptest(fit_transformed)
studentized Breusch-Pagan test

data: fit_transformed BP = 39.604, df = 1, p-value = 0.0000000003111

lmtest::gqtest(fit_transformed)
Goldfeld-Quandt test

data: fit_transformed GQ = 0.81143, df1 = 851, df2 = 851, p-value = 0.9988 alternative hypothesis: variance increases from segment 1 to 2

lmtest::dwtest(fit_transformed)
Durbin-Watson test

data: fit_transformed DW = 1.4876, p-value < 0.00000000000000022 alternative hypothesis: true autocorrelation is greater than 0

 

 

Modelo Box-Cox + polinomio

vivienda4$tipo <- as.factor(vivienda4$tipo)
vivienda4$zona <- as.factor(vivienda4$zona)
fit_transformed_3 <- lm(preciom_transformed ~ poly(areaconst,3)*tipo+tipo*zona, data = vivienda4)
r_squared <- summary(fit_transformed_3)$r.squared
summary_fit <- summary(fit_transformed_3)
coefficients_table <- summary_fit$coefficients
coefficients_df <- as.data.frame(coefficients_table)
coefficients_df$`Pr(>|t|)` <- formatC(coefficients_df$`Pr(>|t|)`, format="e", digits=2)
coefficients_df$Estimate <- round(coefficients_df$Estimate, 3)
coefficients_df$`Std. Error` <- round(coefficients_df$`Std. Error`, 3)
coefficients_df$`t value` <- round(coefficients_df$`t value`, 3)
paged_table(coefficients_df, options = list(rows.print = 20)) %>%
  kable(caption = 'Resumen coeficientes Modelo Box-Cox - Polinomio grado 3')
Resumen coeficientes Modelo Box-Cox - Polinomio grado 3
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.057 0.044 93.124 0.00e+00
poly(areaconst, 3)1 6.402 0.260 24.633 9.91e-115
poly(areaconst, 3)2 -2.113 0.218 -9.701 1.09e-21
poly(areaconst, 3)3 1.345 0.184 7.326 3.66e-13
tipoCasa 0.384 0.124 3.100 1.97e-03
zonaZona Norte 0.069 0.044 1.547 1.22e-01
zonaZona Oeste 0.087 0.046 1.876 6.09e-02
zonaZona Oriente 0.145 0.092 1.574 1.16e-01
zonaZona Sur 0.088 0.044 1.997 4.60e-02
poly(areaconst, 3)1:tipoCasa -1.018 0.519 -1.964 4.97e-02
poly(areaconst, 3)2:tipoCasa 0.124 0.450 0.276 7.83e-01
poly(areaconst, 3)3:tipoCasa -0.284 0.316 -0.898 3.69e-01
tipoCasa:zonaZona Norte -0.368 0.124 -2.969 3.03e-03
tipoCasa:zonaZona Oeste -0.142 0.130 -1.086 2.77e-01
tipoCasa:zonaZona Oriente -0.469 0.158 -2.971 3.01e-03
tipoCasa:zonaZona Sur -0.345 0.123 -2.802 5.13e-03
suppressMessages(suppressWarnings(library(ggplot2)))

newdata <- data.frame(
  areaconst = seq(min(vivienda4$areaconst), max(vivienda4$areaconst), length.out = 100),
  tipo = factor(levels(vivienda4$tipo)[1], levels = levels(vivienda4$tipo)), # replace with the level you want
  zona = factor(levels(vivienda4$zona)[1], levels = levels(vivienda4$zona))  # replace with the level you want
)

predictions <- predict(fit_transformed_3, newdata = newdata, interval = "confidence")
newdata <- cbind(newdata, predictions)
ci_lower<- mean(newdata$lwr)
ci_upper<- mean(newdata$upr)
newdata <- tidyr::pivot_longer(newdata, c("fit", "lwr", "upr"), names_to = "type", values_to = "value")

suppressMessages(suppressWarnings({# Plot the original data and the predictions
p<-ggplot(vivienda4, aes(x = areaconst, y = preciom_transformed)) +
  theme_bw()+
  geom_point(aes(color = tipo, alpha=0.3)) +
  geom_line(data = newdata, aes(y = value, linetype = type)) +
  labs(title = "Modelo ajustado con CI=0.95",
       x = "areaconst",
       y = "preciom_transformed",
       color = "tipo",
       linetype = "Intervalo") +
  scale_alpha(guide = 'none')+
  suppressWarnings({annotate("text", x = 94, y = 4.85, label = TeX("$preciom\\_transformed=poly(areaconst,3)\\cdot tipo+tipo \\cdot zona$"))}) +
  suppressWarnings({annotate("text", x = 77, y = 4.75, label = TeX("preciom=($\\lambda\\cdot$ preciom_transformed+ 1)$^{1/\\lambda}$"))})+
  annotate("text", x = 49, y = 4.65, label = paste0(" R^2 = ", round(r_squared, 4)))}))

# Get the summary of your model
summary_fit <- summary(fit_transformed_3)

# Get the coefficients from the summary
coefficients <- summary_fit$coefficients

# Create an empty string to store your equation
equation <- "preciom_transformed = "

# Loop through each coefficient
for (i in 1:nrow(coefficients)) {
  # Get the coefficient value
  coef_value <- coefficients[i, 1]
  
  # Get the coefficient name
  coef_name <- rownames(coefficients)[i]
  
  # Add the coefficient to the equation string
  if (i == 1) {
    # If it's the intercept, just add the coefficient value
    equation <- paste(equation, round(coef_value, 2))
  } else {
    # If it's not the intercept, add the coefficient name and value
    equation <- paste(equation, " + (", round(coef_value, 2), ") * ", coef_name)
  }
}
cat(paste0("**Resultados**\n\n

- La función obtenida para el ajuste es:\n\n

preciom_transformed =  4.06  + ( 6.4 ) *  poly(areaconst, 3)1  + ( -2.11 ) *  poly(areaconst, 3)2  + ( 1.34 ) *  poly(areaconst, 3)3 \\
+ ( 0.38 ) *  tipoCasa  + ( 0.07 ) *  zonaZona Norte  + ( 0.09 ) *  zonaZona Oeste  + ( 0.14 ) *  zonaZona Oriente\\
+ ( 0.09 ) *  zonaZona Sur  + ( -1.02 ) *  poly(areaconst, 3)1:tipoCasa  + ( 0.12 ) *  poly(areaconst, 3)2:tipoCasa\\
+ ( -0.28 ) *  poly(areaconst, 3)3:tipoCasa  + ( -0.37 ) *  tipoCasa:zonaZona Norte  + ( -0.14 ) *  tipoCasa:zonaZona Oeste\\
+ ( -0.47 ) *  tipoCasa:zonaZona Oriente  + ( -0.34 ) *  tipoCasa:zonaZona Sur    
  
- En la tabla anterior podemos ver los valores de `t-value` y `Pr(>|t|)`. Los coeficientes con un nivel de significancia menor o igual a 0.05 son: poly(areaconst, 3)1, poly(areaconst, 3)2, poly(areaconst, 3)3, tipoCasa, zonaZona Norte, zonaZona Sur, poly(areaconst, 3)1:tipoCasa, tipoCasa:zonaZona Norte, tipoCasa:zonaZona Oriente y tipoCasa:zonaZona Sur.\n\n
           
- El valor del coeficiente de Pearson ($R^2$) es $", round(r_squared, 4), "$.\n\n

- Se resalta una mayor variación en CI=0.95 sobre las mayores áreas ($areaconst>=150$) que corresponden con viviendas de tipo casa."

))

Resultados

  • La función obtenida para el ajuste es:

preciom_transformed = 4.06 + ( 6.4 ) * poly(areaconst, 3)1 + ( -2.11 ) * poly(areaconst, 3)2 + ( 1.34 ) * poly(areaconst, 3)3
+ ( 0.38 ) * tipoCasa + ( 0.07 ) * zonaZona Norte + ( 0.09 ) * zonaZona Oeste + ( 0.14 ) * zonaZona Oriente
+ ( 0.09 ) * zonaZona Sur + ( -1.02 ) * poly(areaconst, 3)1:tipoCasa + ( 0.12 ) * poly(areaconst, 3)2:tipoCasa
+ ( -0.28 ) * poly(areaconst, 3)3:tipoCasa + ( -0.37 ) * tipoCasa:zonaZona Norte + ( -0.14 ) * tipoCasa:zonaZona Oeste
+ ( -0.47 ) * tipoCasa:zonaZona Oriente + ( -0.34 ) * tipoCasa:zonaZona Sur

  • En la tabla anterior podemos ver los valores de t-value y Pr(>|t|). Los coeficientes con un nivel de significancia menor o igual a 0.05 son: poly(areaconst, 3)1, poly(areaconst, 3)2, poly(areaconst, 3)3, tipoCasa, zonaZona Norte, zonaZona Sur, poly(areaconst, 3)1:tipoCasa, tipoCasa:zonaZona Norte, tipoCasa:zonaZona Oriente y tipoCasa:zonaZona Sur.

  • El valor del coeficiente de Pearson (\(R^2\)) es \(0.6797\).

  • Se resalta una mayor variación en CI=0.95 sobre las mayores áreas (\(areaconst>=150\)) que corresponden con viviendas de tipo casa.

p
## Warning in is.na(x): is.na() aplicado a un objeto que no es (lista o vector) de
## tipo 'expression

## Warning in is.na(x): is.na() aplicado a un objeto que no es (lista o vector) de
## tipo 'expression

El siguiente gráfico nos permite ver la influencia de las variables categóricas tipo y zona sobre el modelo de regresión. Para los valores con tipo==Casa se tienen precios más elevados lo que concuerda con el análisis de precio vs tipo en la sección de exploración de datos. Se puede apreciar el mismo efecto aunque en menor magnitud para la variable zona, donde los valores con zona==Zona Oriente y zona==Zona Sur corresponderían con las viviendas de mayor valor de acuerdo al modelo.

suppressWarnings({
a<-interact_plot(fit_transformed_3, pred=areaconst, modx=tipo, data = vivienda4, interval=TRUE)+
  theme_bw()
b<-interact_plot(fit_transformed_3, pred=areaconst, modx=zona, data = vivienda4, interval=TRUE)+
  theme_bw()
grid.arrange(a, b, nrow = 2, top = textGrob("Efecto de moderadores sobre regresión", gp = gpar(fontface = "bold")))})

# Create the model validation plots


cat(paste0("**Validación de supuestos**\n\n

- **Linealidad y Homoscedasticidad:** Los gráficos de Residuals vs Fitted y Scale - Location muestran linealidad dado que los residuos se distribuyen homogéneamente a lo largo del eje x. \n\n

- **Normalidad:** El Normal Q-Q muestra que los puntos siguen una distribución cercana a la normal respecto al modelo original. La distribuición en las colas se aleja en poco grado de la normalidad.\n\n

- **Presencia de valores extremos y de alta influencia:**En el gráfico de Residuals vs Leverage, todos los puntos están dentro de las líneas de distancia de Cook por lo que los datos parecen no mostrar puntos de alta influencia pero si se presentan outliers con índices 393, 831 y 1689.
"))

Validación de supuestos

  • Linealidad y Homoscedasticidad: Los gráficos de Residuals vs Fitted y Scale - Location muestran linealidad dado que los residuos se distribuyen homogéneamente a lo largo del eje x.

  • Normalidad: El Normal Q-Q muestra que los puntos siguen una distribución cercana a la normal respecto al modelo original. La distribuición en las colas se aleja en poco grado de la normalidad.

  • Presencia de valores extremos y de alta influencia:En el gráfico de Residuals vs Leverage, todos los puntos están dentro de las líneas de distancia de Cook por lo que los datos parecen no mostrar puntos de alta influencia pero si se presentan outliers con índices 393, 831 y 1689.

suppressWarnings({
autoplot(fit_transformed_3, which = 1:6)
})
## Warning: Removed 267 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_segment()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_line()`).

shapiro.test(fit_transformed_3$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  fit_transformed_3$residuals
## W = 0.9896, p-value = 0.000000001066
normtest::jb.norm.test(fit_transformed_3$residuals)
## 
##  Jarque-Bera test for normality
## 
## data:  fit_transformed_3$residuals
## JB = 86.415, p-value < 0.00000000000000022
nortest::ad.test(fit_transformed_3$residuals)
## 
##  Anderson-Darling normality test
## 
## data:  fit_transformed_3$residuals
## A = 4.2306, p-value = 0.0000000001631
nortest::lillie.test(fit_transformed_3$residuals)
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  fit_transformed_3$residuals
## D = 0.042555, p-value = 0.0000001298
lmtest::bptest(fit_transformed_3)
## 
##  studentized Breusch-Pagan test
## 
## data:  fit_transformed_3
## BP = 120.65, df = 15, p-value < 0.00000000000000022
lmtest::gqtest(fit_transformed_3)
## 
##  Goldfeld-Quandt test
## 
## data:  fit_transformed_3
## GQ = 0.78819, df1 = 837, df2 = 837, p-value = 0.9997
## alternative hypothesis: variance increases from segment 1 to 2
lmtest::dwtest(fit_transformed_3)
## 
##  Durbin-Watson test
## 
## data:  fit_transformed_3
## DW = 1.4975, p-value < 0.00000000000000022
## alternative hypothesis: true autocorrelation is greater than 0
# Fit the model with the transformed response variable and the categorical variables
newdata <- data.frame(areaconst = 100, tipo = "Apartamento", zona="Zona Sur")
levels(newdata$tipo) <- levels(vivienda4$tipo)
levels(newdata$zona) <- levels(vivienda4$zona)
prediction <- predict(fit_transformed_3, newdata)
preciom_prediction_1 <- (lambda_optimal * prediction + 1)^(1/lambda_optimal)

newdata <- data.frame(areaconst = 100, tipo = "Apartamento", zona="Zona Norte")
levels(newdata$tipo) <- levels(vivienda4$tipo)
levels(newdata$zona) <- levels(vivienda4$zona)
prediction <- predict(fit_transformed_3, newdata)
preciom_prediction_2 <- (lambda_optimal * prediction + 1)^(1/lambda_optimal)

newdata <- data.frame(areaconst = 100, tipo = "Apartamento", zona="Zona Oriente")
levels(newdata$tipo) <- levels(vivienda4$tipo)
levels(newdata$zona) <- levels(vivienda4$zona)
prediction <- predict(fit_transformed_3, newdata)
preciom_prediction_3 <- (lambda_optimal * prediction + 1)^(1/lambda_optimal)

newdata <- data.frame(areaconst = 100, tipo = "Apartamento", zona="Zona Centro")
levels(newdata$tipo) <- levels(vivienda4$tipo)
levels(newdata$zona) <- levels(vivienda4$zona)
prediction <- predict(fit_transformed_3, newdata)
preciom_prediction_4 <- (lambda_optimal * prediction + 1)^(1/lambda_optimal)

newdata <- data.frame(areaconst = 100, tipo = "Apartamento", zona="Zona Oeste")
levels(newdata$tipo) <- levels(vivienda4$tipo)
levels(newdata$zona) <- levels(vivienda4$zona)
prediction <- predict(fit_transformed_3, newdata)
preciom_prediction_5 <- (lambda_optimal * prediction + 1)^(1/lambda_optimal)

cat(paste0("**Precio promedio estimado**\n\n

  - Costo para un 'Apartamento' con areaconst=100, Zona Oriente: ",  round(preciom_prediction_3,3), ".\n
  - Costo para un 'Apartamento' con areaconst=100, Zona Sur: ", round(preciom_prediction_1,3), ".\n
  - Costo para un 'Apartamento' con areaconst=100, Zona Oeste: ",  round(preciom_prediction_5,3), ".\n
  - Costo para un 'Apartamento' con areaconst=100, Zona Norte: ",  round(preciom_prediction_2,3), ".\n
  - Costo para un 'Apartamento' con areaconst=100, Zona Centro: ",  round(preciom_prediction_4,3), ".\n
  
  "))

Precio promedio estimado

  • Costo para un ‘Apartamento’ con areaconst=100, Zona Oriente: 291.11.

  • Costo para un ‘Apartamento’ con areaconst=100, Zona Sur: 263.235.

  • Costo para un ‘Apartamento’ con areaconst=100, Zona Oeste: 262.994.

  • Costo para un ‘Apartamento’ con areaconst=100, Zona Norte: 254.652.

  • Costo para un ‘Apartamento’ con areaconst=100, Zona Centro: 226.186.

Otros modelos

modelo1=lm(preciom ~ areaconst, data=vivienda4)           # Lin - Lin
modelo2=lm(preciom ~ log(areaconst), data=vivienda4)      # Lin - Log
modelo3=lm(log(preciom) ~ areaconst, data=vivienda4)      # Log - Lin
modelo4=lm(log(preciom) ~ log(areaconst), data=vivienda4) # Log - Log

modelo5=lm(preciom ~ poly(areaconst,3)*tipo+zona*tipo, data=vivienda4)           # Lin - Lin
modelo6=lm(preciom ~ log(poly(areaconst,3))*tipo+zona*tipo, data=vivienda4)      # Lin - Log
## Warning in log(poly(areaconst, 3)): Se han producido NaNs
modelo7=lm(log(preciom) ~ poly(areaconst,3)*tipo+zona*tipo, data=vivienda4)      # Log - Lin
modelo8=lm(log(preciom) ~ log(poly(areaconst,3))*tipo+zona*tipo, data=vivienda4) # Log - Log
## Warning in log(poly(areaconst, 3)): Se han producido NaNs
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(modelo1, modelo2, modelo3, modelo4, ci=TRUE, ci.level=0.95, single.row=FALSE, type="text")
## 
## ===================================================================================================
##                                                         Dependent variable:                        
##                                 -------------------------------------------------------------------
##                                                preciom                        log(preciom)         
##                                       (1)                (2)               (3)            (4)      
## ---------------------------------------------------------------------------------------------------
## areaconst                           1.803***                             0.007***                  
##                                  (1.730, 1.875)                       (0.007, 0.007)               
##                                                                                                    
## log(areaconst)                                        189.708***                        0.780***   
##                                                   (182.573, 196.844)                 (0.752, 0.808)
##                                                                                                    
## Constant                           67.381***         -610.083***         4.724***       1.919***   
##                                 (60.501, 74.260) (-641.609, -578.557) (4.696, 4.752) (1.796, 2.042)
##                                                                                                    
## ---------------------------------------------------------------------------------------------------
## Observations                         1,706              1,706             1,706          1,706     
## R2                                   0.582              0.614             0.571          0.639     
## Adjusted R2                          0.582              0.614             0.571          0.638     
## Residual Std. Error (df = 1704)      55.531             53.347            0.227          0.208     
## F Statistic (df = 1; 1704)        2,374.452***       2,715.248***      2,267.022***   3,012.086*** 
## ===================================================================================================
## Note:                                                                   *p<0.1; **p<0.05; ***p<0.01
stargazer(modelo5, modelo6, modelo7, modelo8, ci=TRUE, ci.level=0.95, single.row=FALSE, type="text")
## 
## ==================================================================================================================================================
##                                                                                 Dependent variable:                                               
##                                   ----------------------------------------------------------------------------------------------------------------
##                                                             preciom                                               log(preciom)                    
##                                              (1)                           (2)                           (3)                        (4)           
## --------------------------------------------------------------------------------------------------------------------------------------------------
## poly(areaconst, 3)1                      2,859.257***                                                 11.088***                                   
##                                     (2,630.776, 3,087.738)                                         (10.211, 11.965)                               
##                                                                                                                                                   
## poly(areaconst, 3)2                      -438.598***                                                  -3.489***                                   
##                                      (-630.071, -247.125)                                          (-4.224, -2.754)                               
##                                                                                                                                                   
## poly(areaconst, 3)3                       326.532***                                                   2.216***                                   
##                                       (165.132, 487.932)                                            (1.596, 2.835)                                
##                                                                                                                                                   
## log(poly(areaconst, 3))1                                              3,391,040.000                                              7,052.899        
##                                                              (-3,179,895.000, 9,961,975.000)                             (-8,599.328, 22,705.130) 
##                                                                                                                                                   
## log(poly(areaconst, 3))2                                              -1,100,867.000                                            -2,289.914        
##                                                              (-3,224,580.000, 1,022,846.000)                              (-7,348.682, 2,768.855) 
##                                                                                                                                                   
## log(poly(areaconst, 3))3                                                77,848.570                                                161.990         
##                                                                 (-70,017.330, 225,714.500)                                  (-190.232, 514.213)   
##                                                                                                                                                   
## tipoCasa                                  224.858***                  -6,150,057.000                   0.681***                 -12,754.300       
##                                       (115.999, 333.716)     (-18,207,310.000, 5,907,196.000)       (0.264, 1.099)       (-41,475.150, 15,966.550)
##                                                                                                                                                   
## zonaZona Norte                              24.984                                                      0.117                                     
##                                       (-13.952, 63.921)                                            (-0.032, 0.266)                                
##                                                                                                                                                   
## zonaZona Oeste                             34.602*                      316.590***                      0.149*                    0.660**         
##                                        (-6.187, 75.390)             (113.945, 519.236)             (-0.007, 0.306)            (0.178, 1.143)      
##                                                                                                                                                   
## zonaZona Oriente                            53.682                                                      0.248                                     
##                                       (-27.247, 134.612)                                           (-0.063, 0.558)                                
##                                                                                                                                                   
## zonaZona Sur                                31.687                        41.429                       0.149**                     0.105          
##                                        (-6.855, 70.230)            (-128.687, 211.544)              (0.001, 0.297)            (-0.301, 0.510)     
##                                                                                                                                                   
## poly(areaconst, 3)1:tipoCasa              -403.066*                                                    -1.740*                                    
##                                       (-859.019, 52.886)                                           (-3.490, 0.010)                                
##                                                                                                                                                   
## poly(areaconst, 3)2:tipoCasa               -211.894                                                     0.120                                     
##                                      (-607.923, 184.134)                                           (-1.400, 1.641)                                
##                                                                                                                                                   
## poly(areaconst, 3)3:tipoCasa               151.168                                                      -0.381                                    
##                                      (-126.859, 429.196)                                           (-1.448, 0.686)                                
##                                                                                                                                                   
## tipoCasa:zonaZona Norte                  -224.561***                                                  -0.657***                                   
##                                      (-333.598, -115.524)                                          (-1.075, -0.238)                               
##                                                                                                                                                   
## log(poly(areaconst, 3))1:tipoCasa                                     -3,359,064.000                                            -6,967.900        
##                                                              (-9,931,173.000, 3,213,046.000)                             (-22,622.920, 8,687.124) 
##                                                                                                                                                   
## log(poly(areaconst, 3))2:tipoCasa                                     1,092,761.000                                              2,268.524        
##                                                              (-1,031,242.000, 3,216,765.000)                              (-2,790.937, 7,327.984) 
##                                                                                                                                                   
## log(poly(areaconst, 3))3:tipoCasa                                      -77,737.300                                               -161.752         
##                                                                 (-225,608.700, 70,134.130)                                  (-513.987, 190.484)   
##                                                                                                                                                   
## tipoCasa:zonaZona Oeste                    -58.473                                                      -0.245                                    
##                                       (-173.021, 56.074)                                           (-0.685, 0.195)                                
##                                                                                                                                                   
## tipoCasa:zonaZona Oriente                -275.076***                                                  -0.833***                                   
##                                      (-413.734, -136.418)                                          (-1.365, -0.301)                               
##                                                                                                                                                   
## tipoCasa:zonaZona Sur                    -211.942***                     -17.370                      -0.615***                   -0.057          
##                                      (-320.132, -103.753)          (-207.034, 172.293)             (-1.031, -0.200)           (-0.509, 0.395)     
##                                                                                                                                                   
## Constant                                  194.642***                  6,213,171.000                    5.209***                 12,927.220        
##                                       (156.343, 232.941)     (-5,841,760.000, 18,268,102.000)       (5.062, 5.356)       (-15,788.100, 41,642.540)
##                                                                                                                                                   
## --------------------------------------------------------------------------------------------------------------------------------------------------
## Observations                                1,706                           58                          1,706                       58            
## R2                                          0.645                         0.280                         0.679                      0.266          
## Adjusted R2                                 0.642                         0.127                         0.676                      0.110          
## Residual Std. Error                   51.364 (df = 1690)             93.750 (df = 47)             0.197 (df = 1690)           0.223 (df = 47)     
## F Statistic                       205.135*** (df = 15; 1690)       1.829* (df = 10; 47)       238.372*** (df = 15; 1690)    1.705 (df = 10; 47)   
## ==================================================================================================================================================
## Note:                                                                                                                  *p<0.1; **p<0.05; ***p<0.01

 

 

Conclusiones

En conclusión, el previo análisis para la inmobiliaria A&C nos permite obtener nuevas perspectivas sobre las dinámicas de precios para bienes inmuebles de estrato 4 en Cali. El análisis permitió encontrar que un modelo lineal ajustado a un polinomio de grado 3 e incorporando una transformación Box-Cox sobre la variable precio, resultó más efectivo para describir de la relación entre esta variable y el área construida.

El modelo, usó el área construida como principal predictor y se incluyeron términos de interacción para la zona y el tipo de vivienda (casa o apartamento), lo que permite describir aproximadamente el 68% de la variación en el precio (\(R^2=0.6797\)). Los términos de interacción implican una paso de un coeficiente \(R^2\) del \(0.5822\) al \(0.6797\) y como se puede apreciar en las gráficas de interacción se observa un aumento del precio respecto a las categorías de Tipo=Casa y Zona=Oriente.

Finalmente, la tarea de regresión podría mejorar usando otras estrategias de modelado así como la recopilación de datos para inmuebles en zonas con muy pocos registros, además de la incorporación y transformación de variables adicionales que permitan capturar más efectivamente las dinámicas del mercado.

Anexo

Filtro para evaluar sólo apartamentos.

Area construido y preciom respecto a Zona

filtered_data <- vivienda4 %>% filter(tipo == "Apartamento")
suppressWarnings({

plt <- ggbetweenstats(
  data = filtered_data,
  x = zona,
  y = preciom
)

plt_2 <- ggbetweenstats(
  data = filtered_data,
  x = zona,
  y = areaconst
)

grid.arrange(plt, plt_2, nrow = 2, top = textGrob("areaconst y precio vs zona", gp = gpar(fontface = "bold")))})

Modelo Base

p <- ggplot(filtered_data, aes(x=areaconst, y=preciom)) +
      geom_point(color="#20263d", alpha=0.2) +
      ggtitle("Área construida vs Precio")+
      theme_bw()+
      theme(legend.position="none")+
      geom_smooth(
      aes(color = "y ~ x", fill = "y ~ x"),
      method = "lm", 
      formula = y~x, 
      se = TRUE, 
      fullrange = TRUE)

# Fit a linear model
fit <- lm(preciom ~ areaconst, data = filtered_data)
conf_int <- confint(fit, level=0.95)
ci_areaconst <- conf_int["areaconst", ]


r_squared <- summary(fit)$r.squared
spearman <- cor(filtered_data$areaconst, filtered_data$preciom,  method = "spearman")
kendall <- cor(filtered_data$areaconst, filtered_data$preciom,  method = "kendall")

# Get the coefficients of the linear model
intercept <- round(coef(fit)[1],3)
slope <- round(coef(fit)[2],3)

# Get the summary of the model
summary_fit <- summary(fit)
coefficients_table <- summary_fit$coefficients
coefficients_df <- as.data.frame(coefficients_table)
coefficients_df$`Pr(>|t|)` <- formatC(coefficients_df$`Pr(>|t|)`, format="e", digits=2)
coefficients_df$Estimate <- round(coefficients_df$Estimate, 3)
coefficients_df$`Std. Error` <- round(coefficients_df$`Std. Error`, 3)
coefficients_df$`t value` <- round(coefficients_df$`t value`, 3)
paged_table(coefficients_df, options = list(rows.print = 20)) %>%
  kable(caption = 'Resumen coeficientes Modelo Base')
Resumen coeficientes Modelo Base
Estimate Std. Error t value Pr(>|t|)
(Intercept) 39.047 4.100 9.524 7.31e-21
areaconst 2.165 0.052 41.595 1.06e-244
p <- p +
  annotate("text", x = 68, y = 720, label = paste0(" preciom = ", slope, " (areaconst) + ", intercept)) +
  annotate("text", x = 49, y = 679, label = paste0(" R^2 = ", round(r_squared, 4)))
p

autoplot(fit, which = 1:6)

Otros modelos

modelo1=lm(preciom ~ areaconst, data=filtered_data)           # Lin - Lin
modelo2=lm(preciom ~ log(areaconst), data=filtered_data)      # Lin - Log
modelo3=lm(log(preciom) ~ areaconst, data=filtered_data)      # Log - Lin
modelo4=lm(log(preciom) ~ log(areaconst), data=filtered_data) # Log - Log

modelo5=lm(preciom ~ poly(areaconst,3)*zona, data=filtered_data)           # Lin - Lin
modelo7=lm(log(preciom) ~ poly(areaconst,3)*zona, data=filtered_data)      # Log - Lin

library(stargazer)
stargazer(modelo1, modelo2, modelo3, modelo4, ci=TRUE, ci.level=0.95, single.row=FALSE, type="text")
## 
## ===================================================================================================
##                                                         Dependent variable:                        
##                                 -------------------------------------------------------------------
##                                                preciom                        log(preciom)         
##                                       (1)                (2)               (3)            (4)      
## ---------------------------------------------------------------------------------------------------
## areaconst                           2.165***                             0.009***                  
##                                  (2.063, 2.267)                       (0.009, 0.010)               
##                                                                                                    
## log(areaconst)                                        195.419***                        0.882***   
##                                                   (186.708, 204.130)                 (0.842, 0.921)
##                                                                                                    
## Constant                           39.047***         -635.532***         4.551***       1.484***   
##                                 (31.011, 47.082) (-672.953, -598.112) (4.513, 4.589) (1.313, 1.654)
##                                                                                                    
## ---------------------------------------------------------------------------------------------------
## Observations                         1,363              1,363             1,363          1,363     
## R2                                   0.560              0.587             0.520          0.582     
## Adjusted R2                          0.559              0.587             0.519          0.582     
## Residual Std. Error (df = 1361)      43.339             41.982            0.205          0.191     
## F Statistic (df = 1; 1361)        1,730.157***       1,933.199***      1,473.424***   1,894.288*** 
## ===================================================================================================
## Note:                                                                   *p<0.1; **p<0.05; ***p<0.01
stargazer(modelo5, modelo7, ci=TRUE, ci.level=0.95, single.row=FALSE, type="text")
## 
## ================================================================================
##                                                  Dependent variable:            
##                                      -------------------------------------------
##                                               preciom            log(preciom)   
##                                                 (1)                   (2)       
## --------------------------------------------------------------------------------
## poly(areaconst, 3)1                          2,054.332               7.803      
##                                        (-462.588, 4,571.251)   (-3.449, 19.055) 
##                                                                                 
## poly(areaconst, 3)2                           973.395                2.676      
##                                        (-373.343, 2,320.134)    (-3.344, 8.697) 
##                                                                                 
## poly(areaconst, 3)3                           460.180                1.092      
##                                       (-2,057.023, 2,977.382)  (-10.162, 12.345)
##                                                                                 
## zonaZona Norte                                24.838                 0.119      
##                                          (-24.095, 73.771)      (-0.100, 0.337) 
##                                                                                 
## zonaZona Oeste                                24.038                 0.112      
##                                          (-26.415, 74.491)      (-0.114, 0.337) 
##                                                                                 
## zonaZona Oriente                               6.881                 0.127      
##                                         (-232.873, 246.634)     (-0.945, 1.199) 
##                                                                                 
## zonaZona Sur                                  30.338                 0.145      
##                                          (-18.364, 79.040)      (-0.072, 0.363) 
##                                                                                 
## poly(areaconst, 3)1:zonaZona Norte           -415.011               -0.479      
##                                       (-2,939.058, 2,109.037)  (-11.763, 10.805)
##                                                                                 
## poly(areaconst, 3)2:zonaZona Norte          -1,327.447*             -4.883      
##                                        (-2,688.314, 33.420)    (-10.966, 1.201) 
##                                                                                 
## poly(areaconst, 3)3:zonaZona Norte           -516.686               -0.926      
##                                       (-3,040.373, 2,007.001)  (-12.208, 10.356)
##                                                                                 
## poly(areaconst, 3)1:zonaZona Oeste          -1,629.250              -4.741      
##                                       (-4,323.193, 1,064.694)  (-16.784, 7.303) 
##                                                                                 
## poly(areaconst, 3)2:zonaZona Oeste         -3,670.245***          -12.921***    
##                                      (-5,705.775, -1,634.714)  (-22.021, -3.821)
##                                                                                 
## poly(areaconst, 3)3:zonaZona Oeste          -1,825.685              -5.059      
##                                        (-4,544.351, 892.981)   (-17.213, 7.095) 
##                                                                                 
## poly(areaconst, 3)1:zonaZona Oriente         5,151.248              18.521      
##                                      (-10,854.970, 21,157.470) (-53.036, 90.079)
##                                                                                 
## poly(areaconst, 3)2:zonaZona Oriente                                            
##                                                                                 
##                                                                                 
## poly(areaconst, 3)3:zonaZona Oriente                                            
##                                                                                 
##                                                                                 
## poly(areaconst, 3)1:zonaZona Sur             -210.975                0.166      
##                                       (-2,729.753, 2,307.803)  (-11.095, 11.426)
##                                                                                 
## poly(areaconst, 3)2:zonaZona Sur            -1,316.567*             -5.552*     
##                                        (-2,666.511, 33.376)    (-11.587, 0.483) 
##                                                                                 
## poly(areaconst, 3)3:zonaZona Sur             -168.705                0.679      
##                                       (-2,687.799, 2,350.388)  (-10.583, 11.941)
##                                                                                 
## Constant                                    173.281***             5.125***     
##                                         (124.642, 221.919)      (4.908, 5.343)  
##                                                                                 
## --------------------------------------------------------------------------------
## Observations                                   1,363                 1,363      
## R2                                             0.602                 0.613      
## Adjusted R2                                    0.597                 0.608      
## Residual Std. Error (df = 1345)               41.444                 0.185      
## F Statistic (df = 17; 1345)                 119.719***            125.149***    
## ================================================================================
## Note:                                                *p<0.1; **p<0.05; ***p<0.01

** Comentario ** Se obtienen valores menores para \(R^2\) que los que se muestran para los modelos de la base de datos completa (Casa y Apartamentos).