Análisis de Datos y Big data

Universidad Central

Dirección de Educación Continua.

Imágen1
Imágen1

Linear Regressionb

# Cargar las librerías necesarias
# Si no las tienes instaladas, ejecuta: install.packages(c("dplyr", "ggplot2", "lmtest", "car", "tseries", "sandwich", "MASS"))

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
library(lmtest) # Para bptest, resettest, dwtest
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(car)    # Para vif
## Loading required package: carData
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
library(tseries)# Para jarque.bera.test
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(sandwich) # Para vcovHC (errores robustos)
library(MASS)   # Para boxcox
## 
## Attaching package: 'MASS'
## The following object is masked from 'package:dplyr':
## 
##     select
# Configuraciones de visualización
theme_set(theme_dark()) # Equivalente a sns.set_style("darkgrid")
options(repr.plot.width = 15, repr.plot.height = 6) # Equivalente a plt.rcParams
options(warn = -1) # Suprime advertencias, equivalente a warnings.filterwarnings("ignore")

# URL base para los datos
url_base <- "https://raw.githubusercontent.com/jazaineam1/Diplomado_ucentral_ME/refs/heads/main/Datos/"

Supuestos de los Modelos de Regresión Lineal

Los modelos de regresión lineal, para ser válidos y para que sus inferencias estadísticas (como los intervalos de confianza y las pruebas de hipótesis sobre los coeficientes) sean fiables, se basan en una serie de supuestos sobre los datos y, más específicamente, sobre los errores del modelo.

¿Qué es un Error (o Residuo)?

En el contexto de la regresión, un error (a menudo llamado residuo cuando se calcula a partir de los datos de la muestra) es la diferencia entre el valor observado de la variable dependiente (\(y_i\)) y el valor predicho por el modelo de regresión (\(\hat{y}_i\)).

\(e_i = y_i - \hat{y}_i\)

Los errores representan la variabilidad en la variable dependiente que el modelo de regresión no logra explicar. Son una medida de cuán bien se ajusta el modelo a los datos.

¿Por qué se revisan los supuestos sobre los errores?

Las propiedades estadísticas deseadas de los estimadores de los coeficientes de regresión (como ser insesgados y eficientes) y la validez de las pruebas de significancia e intervalos de confianza dependen de que estos supuestos sobre los errores se cumplan. Si los supuestos se violan, las conclusiones extraídas del modelo pueden ser incorrectas o engañosas.

Supuestos Clave de la Regresión Lineal:

  1. Linealidad:
    • Supuesto: La relación entre las variables independientes (predictoras) y la variable dependiente es lineal. Esto significa que el cambio en la variable dependiente por un cambio unitario en una variable independiente es constante, manteniendo las demás variables fijas.
    • Cómo verificarlo:
      • Gráficos de dispersión: Graficar la variable dependiente contra cada variable independiente. Se debería observar una tendencia lineal.
      • Gráfico de residuos vs. valores ajustados (predichos): Si el modelo es lineal, los residuos deberían distribuirse aleatoriamente alrededor de la línea horizontal cero, sin patrones evidentes (por ejemplo, una forma de U o una curva).
      • Gráficos de regresión parcial (Partial Regression Plots) o Added Variable Plots: Muestran la relación entre una variable independiente y la variable dependiente, después de controlar el efecto de las otras variables independientes. Deberían mostrar una relación lineal.
    • Consecuencias de la violación: Los coeficientes estimados pueden ser sesgados y las predicciones del modelo no serán precisas.
  2. Independencia de los Errores (No Autocorrelación):
    • Supuesto: Los errores (residuos) son independientes entre sí. Es decir, el valor de un error no está correlacionado con el valor de ningún otro error. Este supuesto es particularmente importante para datos de series temporales.
    • Cómo verificarlo:
      • Gráfico de residuos vs. orden de observación (o tiempo): No debería haber patrones cíclicos o sistemáticos. Los puntos deben parecer aleatorios.
      • Prueba de Durbin-Watson: Es una prueba formal para detectar autocorrelación de primer orden. Un valor cercano a 2 indica no autocorrelación. Valores significativamente menores a 2 sugieren autocorrelación positiva, y mayores a 2, autocorrelación negativa.
      • Función de Autocorrelación (ACF) de los residuos: Grafica la correlación de los residuos con sus propios retardos. Para independencia, las autocorrelaciones deberían caer rápidamente dentro de las bandas de confianza (cerca de cero).
    • Consecuencias de la violación: Los errores estándar de los coeficientes pueden estar subestimados, lo que lleva a intervalos de confianza demasiado estrechos y a valores p incorrectamente pequeños (mayor probabilidad de rechazar la hipótesis nula cuando es verdadera).
  3. Homocedasticidad (Varianza Constante de los Errores):
    • Supuesto: La varianza de los errores es constante para todos los niveles de las variables independientes. Es decir, la dispersión de los residuos es la misma a lo largo de la línea de regresión.
    • Cómo verificarlo:
      • Gráfico de residuos vs. valores ajustados (predichos): Los residuos deben mostrar una dispersión uniforme alrededor de la línea cero, sin forma de embudo (heterocedasticidad) o abanico.
      • Gráfico de residuos vs. variables independientes: Similar al anterior, se busca una dispersión constante.
      • Prueba de Breusch-Pagan: Prueba formal para la homocedasticidad. La hipótesis nula es que la varianza de los errores es constante.
      • Prueba de White: Otra prueba formal, más general que la de Breusch-Pagan, ya que no asume una forma específica de heterocedasticidad.
    • Consecuencias de la violación (Heterocedasticidad): Los estimadores de los coeficientes siguen siendo insesgados, pero ya no son los de mínima varianza (no son eficientes). Los errores estándar de los coeficientes son sesgados, lo que invalida las pruebas t, pruebas F e intervalos de confianza.
  4. Normalidad de los Errores:
    • Supuesto: Los errores se distribuyen normalmente, con media cero. (La media cero se garantiza si el modelo incluye un intercepto y se estima por mínimos cuadrados ordinarios).
    • Cómo verificarlo:
      • Histograma de los residuos: Debería asemejarse a una distribución normal (forma de campana).
      • Gráfico Q-Q (Quantile-Quantile plot) de los residuos: Los puntos deberían caer aproximadamente sobre una línea recta si los residuos son normales. Desviaciones sistemáticas de la línea indican no normalidad.
      • Pruebas de normalidad formales:
        • Prueba de Shapiro-Wilk: Adecuada para muestras pequeñas.
        • Prueba de Kolmogorov-Smirnov (con corrección de Lilliefors): Otra prueba común.
        • Prueba de Jarque-Bera: Basada en la asimetría y curtosis de los residuos.
    • Consecuencias de la violación: Si los errores no son normales, especialmente en muestras pequeñas, las pruebas de hipótesis (pruebas t y F) y los intervalos de confianza para los coeficientes pueden no ser fiables. Sin embargo, para muestras grandes, el Teorema del Límite Central puede implicar que los estimadores de los coeficientes se distribuyen aproximadamente de forma normal, incluso si los errores no lo hacen.
  5. No Multicolinealidad Perfecta (para regresión múltiple):
    • Supuesto: Las variables independientes no están perfectamente correlacionadas entre sí. Idealmente, tampoco deberían estar altamente correlacionadas (multicolinealidad imperfecta pero fuerte).
    • Cómo verificarlo:
      • Matriz de correlación entre variables independientes: Buscar coeficientes de correlación altos (cercanos a +1 o -1).
      • Factor de Inflación de la Varianza (VIF - Variance Inflation Factor): Mide cuánto se infla la varianza de un coeficiente de regresión estimado debido a la colinealidad.
        • Un VIF de 1 indica no colinealidad.
        • VIF > 5 es motivo de preocupación.
        • VIF > 10 sugiere multicolinealidad problemática.
        • La tolerancia (1/VIF) es otra medida; valores bajos indican problemas.
    • Consecuencias de la violación:
      • Multicolinealidad perfecta: El modelo no se puede estimar.
      • Multicolinealidad alta (imperfecta):
        • Errores estándar de los coeficientes de regresión muy grandes, lo que dificulta determinar la significancia estadística de las variables individuales.
        • Estimaciones de los coeficientes inestables y sensibles a pequeños cambios en los datos o en la especificación del modelo.
        • Puede ser difícil interpretar el efecto individual de las variables colineales.
        • A pesar de esto, el modelo general (R² y predicciones) puede seguir siendo bueno.

Es crucial verificar estos supuestos después de ajustar un modelo de regresión para asegurar la validez y fiabilidad de sus resultados. Si se violan los supuestos, pueden ser necesarias transformaciones de variables, el uso de métodos de regresión robustos, o la reconsideración de la especificación del modelo.

# Supuesto Formulación (pop.) Prueba clásica \(H_0\) \(H_1\) Consecuencias si \(H_0\) se rechaza
1 Linealidad \(E[y\mid X]=X\beta\) Gráfico residuales-ajustados, Ramsey RESET No falta non-linearidad Hay relación no lineal Sesgo en \(\hat\beta\)
2 Independencia $ (_i,_j)=0$ Durbin–Watson, Ljung-Box Errores no autocorrelados Autocorrelación EE sub/over
3 Homoscedasticidad Var\((\varepsilon_i)=\sigma^2\) Breusch–Pagan, White Varianza constante Varianza depende de \(X\) Tests t/F inválidos
4 Normalidad (solo p << 30) \(\varepsilon_i\sim N(0,\sigma^2)\) Jarque–Bera, Shapiro Errores normales Distrib. distinta T-IC inexactos
5 No multicolinealidad perfecta \(\operatorname{rank}(X)=k\) VIF, condición VIF bajos Colinealidad alta EE inflados, inestab.

¿Cómo debemos fijar el precio de inmuebles en Seattle?

Objetivos.

En una lectura anterior, aprendimos cómo la regresión lineal puede ser una herramienta poderosa para comprender el comportamiento de una variable de interés en relación con otras variables en nuestro conjunto de datos. Sin embargo, en muchas situaciones de la vida real, es posible que nuestros datos no cumplan con los supuestos básicos que se necesitan para que un modelo de regresión lineal sea adecuado. En los casos en que la regresión lineal no sea directamente aplicable, en estos escenarios debemos descubrir cómo solucionar este problema.

Vamos a abordar:

  1. Cómo seleccionar y usar las transformaciones de variables apropiadas para corregir nuestros datos de modo que sean adecuados para aplicar la regresión lineal
  2. Cómo decidir si las variables independientes adicionales realmente benefician al modelo
  3. Cómo ampliar aún más la aplicabilidad de los modelos lineales teniendo en cuenta las interacciones que pueden existir entre las variables independientes

Introducción

El Dataset se obtuvo de Kaggle e incluye precios de venta de casas en el estado de Washington (condado de King, donde se encuentra Seattle) entre mayo de 2014 y mayo de 2015.

Vamos a crear un modelo que use como variable target el precio de venta (price) y como las features las características de los predios. Todo basado en ventas anteriores en Seattle para recomendar un precio de venta óptimo.

# Cargar los datos
file_url <- paste0(url_base, "kc_house_data.csv")
houses <- read.csv(file_url)

# Copiar y limpiar el dataframe
df <- houses

# Eliminar columnas no deseadas usando dplyr
df <- df %>%
  dplyr::select(-id, -sqft_living15, -sqft_lot15)

# Mostrar la estructura del dataframe (equivalente a df.info())
glimpse(df)
## Rows: 21,613
## Columns: 18
## $ date          <chr> "20141013T000000", "20141209T000000", "20150225T000000",…
## $ price         <dbl> 221900, 538000, 180000, 604000, 510000, 1225000, 257500,…
## $ bedrooms      <int> 3, 3, 2, 4, 3, 4, 3, 3, 3, 3, 3, 2, 3, 3, 5, 4, 3, 4, 2,…
## $ bathrooms     <dbl> 1.00, 2.25, 1.00, 3.00, 2.00, 4.50, 2.25, 1.50, 1.00, 2.…
## $ sqft_living   <int> 1180, 2570, 770, 1960, 1680, 5420, 1715, 1060, 1780, 189…
## $ sqft_lot      <int> 5650, 7242, 10000, 5000, 8080, 101930, 6819, 9711, 7470,…
## $ floors        <dbl> 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 2.0, 1.0, 1…
## $ waterfront    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ view          <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,…
## $ condition     <int> 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 4, 4,…
## $ grade         <int> 7, 7, 6, 7, 8, 11, 7, 7, 7, 7, 8, 7, 7, 7, 7, 9, 7, 7, 7…
## $ sqft_above    <int> 1180, 2170, 770, 1050, 1680, 3890, 1715, 1060, 1050, 189…
## $ sqft_basement <int> 0, 400, 0, 910, 0, 1530, 0, 0, 730, 0, 1700, 300, 0, 0, …
## $ yr_built      <int> 1955, 1951, 1933, 1965, 1987, 2001, 1995, 1963, 1960, 20…
## $ yr_renovated  <int> 0, 1991, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ zipcode       <int> 98178, 98125, 98028, 98136, 98074, 98053, 98003, 98198, …
## $ lat           <dbl> 47.5112, 47.7210, 47.7379, 47.5208, 47.6168, 47.6561, 47…
## $ long          <dbl> -122.257, -122.319, -122.233, -122.393, -122.045, -122.0…
# Definir la fórmula del modelo
# La sintaxis de la fórmula en R es muy similar a la de statsmodels en Python
formula_0 <- log(price) ~ sqft_living + bedrooms + bathrooms + floors + grade + sqft_lot

# Ajustar el modelo de regresión lineal (OLS)
model_0 <- lm(formula_0, data = df)

# Mostrar el resumen del modelo
summary(model_0)
## 
## Call:
## lm(formula = formula_0, data = df)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.74302 -0.25290  0.00178  0.23567  1.38151 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.123e+01  2.109e-02 532.709  < 2e-16 ***
## sqft_living  2.388e-04  5.172e-06  46.169  < 2e-16 ***
## bedrooms    -1.995e-02  3.255e-03  -6.131 8.91e-10 ***
## bathrooms   -8.841e-03  5.239e-03  -1.688 0.091501 .  
## floors      -1.451e-02  5.300e-03  -2.737 0.006199 ** 
## grade        1.864e-01  3.373e-03  55.261  < 2e-16 ***
## sqft_lot    -2.217e-07  5.889e-08  -3.765 0.000167 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.3507 on 21606 degrees of freedom
## Multiple R-squared:  0.5567, Adjusted R-squared:  0.5566 
## F-statistic:  4522 on 6 and 21606 DF,  p-value: < 2.2e-16
# 2.1 Linealidad / especificación ---------------------------
# Prueba RESET de Ramsey para errores de especificación
# 'type = "fitted"' usa las potencias de los valores ajustados como regresores
reset_test_result <- resettest(model_0, power = 2, type = "fitted")

# Imprimir el p-valor
cat(paste("\nRESET (linealidad) p-value:", format(reset_test_result$p.value, scientific = TRUE, digits = 4)))
## 
## RESET (linealidad) p-value: 1.597e-14

La salida RESET (linealidad) p-value: 1.597e-14 se interpreta de la siguiente manera:

La prueba RESET (Regression Equation Specification Error Test) se utiliza para detectar problemas de especificación en un modelo de regresión, particularmente la omisión de términos no lineales.

  • Hipótesis Nula (\(H_0\)): El modelo está correctamente especificado (es decir, la relación funcional entre las variables independientes y la variable dependiente es lineal, tal como se ha modelado).
  • Hipótesis Alternativa (\(H_1\)): El modelo está incorrectamente especificado (es decir, existen no linealidades que no han sido capturadas por el modelo).

En este caso, el p-valor obtenido es 1.597e-14 (o 0.00000000000001597). Este valor es extremadamente pequeño, mucho menor que los niveles de significancia comunes (como 0.05, 0.01 o 0.001).

Conclusión: Dado que el p-valor es muy bajo, se rechaza la hipótesis nula. Esto sugiere fuertemente que el modelo, tal como está especificado actualmente (np.log(price) ~ sqft_living + bedrooms + bathrooms + floors + grade + sqft_lot), sufre de una incorrecta especificación, probablemente debido a la omisión de relaciones no lineales relevantes. En otras palabras, la relación entre las variables predictoras y el logaritmo del precio no es puramente lineal como asume el modelo. Sería necesario considerar transformaciones adicionales de las variables o la inclusión de términos polinómicos o de interacción para mejorar la especificación del modelo.

# Crear un dataframe con los valores ajustados y los residuos
residuals_df <- data.frame(
  Fitted = fitted(model_0),
  Residuals = resid(model_0)
)

# Graficar con ggplot2
ggplot(residuals_df, aes(x = Fitted, y = Residuals)) +
  geom_point(alpha = 0.3) +
  geom_hline(yintercept = 0, color = "black") +
  labs(
    x = "Fitted",
    y = "Residuals",
    title = "Residuos vs Ajustados — Modelo 0")

Explicación del Gráfico: Residuos vs. Ajustados (Modelo 0)

El gráfico generado (“Residuos vs Ajustados — Modelo 0”) es una herramienta de diagnóstico fundamental para evaluar la adecuación de un modelo de regresión lineal. En este gráfico:

  • Eje X (Fitted values / Valores Ajustados): Representa los valores predichos de la variable dependiente (\(\hat{y}_i\)) por el modelo.
  • Eje Y (Residuals / Residuos): Representa las diferencias entre los valores observados y los valores predichos (\(e_i = y_i - \hat{y}_i\)).
  • Línea Horizontal en Cero: Sirve como referencia. Idealmente, los residuos deberían distribuirse aleatoriamente alrededor de esta línea.

¿Qué buscamos en este gráfico?

  1. Linealidad: Si la relación entre las variables predictoras y la variable dependiente es lineal (como asume el modelo), los residuos deberían dispersarse aleatoriamente alrededor de la línea horizontal cero, sin mostrar ningún patrón sistemático o curvilíneo.
  2. Homocedasticidad (Varianza Constante de los Errores): La dispersión vertical de los residuos debería ser aproximadamente la misma a lo largo de todo el rango de los valores ajustados. Si la dispersión aumenta o disminuye a medida que cambian los valores ajustados (formando un embudo o abanico), esto indica heterocedasticidad (varianza no constante).

Interpretación del Gráfico Específico (Modelo 0):

Observando el gráfico “Residuos vs Ajustados — Modelo 0”:

  • Los puntos no parecen estar distribuidos de manera completamente aleatoria alrededor de la línea horizontal en cero.
  • Se puede percibir una ligera curvatura o un patrón sistemático en los residuos. Por ejemplo, los residuos tienden a ser más negativos para valores ajustados bajos y altos, y más positivos para valores ajustados intermedios, o alguna otra forma no aleatoria.

Conclusión basada en el gráfico:

La presencia de un patrón (como una curva) en el gráfico de residuos vs. ajustados sugiere que el supuesto de linealidad podría no cumplirse. Esto significa que el modelo lineal actual podría no estar capturando adecuadamente la relación entre las variables predictoras y el logaritmo del precio.

Esta observación visual es consistente con el resultado de la prueba RESET (p-valor: 1.597e-14), la cual indicó una incorrecta especificación del modelo debido, probablemente, a la omisión de relaciones no lineales. El gráfico de residuos proporciona una evidencia visual que respalda esta conclusión.

Aunque el principal problema que se destaca es la no linealidad, este tipo de gráfico también ayuda a evaluar la homocedasticidad. Si bien no hay una forma de embudo extremadamente obvia, la posible no linealidad complica la evaluación clara de la homocedasticidad a partir de este gráfico únicamente. Corregir la no linealidad a menudo es el primer paso antes de reevaluar la homocedasticidad.

# 2.2 Multicolinealidad -------------------------------------
# La función vif() del paquete 'car' calcula el VIF para todas las variables
vif_results <- vif(model_0)
print("VIF:")
## [1] "VIF:"
print(vif_results)
## sqft_living    bedrooms   bathrooms      floors       grade    sqft_lot 
##    3.964208    1.609883    2.860243    1.438988    2.762177    1.045194

Explicación del Factor de Inflación de la Varianza (VIF)

El Factor de Inflación de la Varianza (VIF) es una medida utilizada para detectar la multicolinealidad en un modelo de regresión múltiple. La multicolinealidad ocurre cuando dos o más variables predictoras (independientes) en el modelo están altamente correlacionadas entre sí.

¿Qué mide el VIF?

Para cada variable predictora en el modelo, el VIF cuantifica cuánto se infla la varianza de su coeficiente de regresión estimado debido a su correlación con las otras variables predictoras en el modelo.

Conceptualmente, para una variable predictora \(X_j\), su VIF se calcula como: \(VIF_j = \frac{1}{1 - R_j^2}\) donde \(R_j^2\) es el coeficiente de determinación de una regresión de \(X_j\) sobre todas las demás variables predictoras.

  • Si \(R_j^2\) es cercano a 0 (es decir, \(X_j\) no está muy correlacionada con las otras predictoras), el VIF será cercano a 1.
  • Si \(R_j^2\) es cercano a 1 (es decir, \(X_j\) está altamente correlacionada con las otras predictoras), el VIF será muy grande.

Interpretación de los valores del VIF:

No hay un umbral estricto, pero se suelen seguir estas directrices generales:

  • VIF = 1: No hay multicolinealidad para esa variable. La variable no está correlacionada con ninguna otra predictora en el modelo.
  • 1 < VIF < 5: Generalmente se considera que hay un nivel bajo a moderado de multicolinealidad, que a menudo no es problemático.
  • VIF ≥ 5: Indica un nivel de multicolinealidad que podría ser preocupante. Los errores estándar de los coeficientes de regresión pueden estar inflados, lo que dificulta la evaluación de la significancia individual de las variables.
  • VIF ≥ 10: Generalmente se considera un signo de multicolinealidad seria, lo que sugiere que las estimaciones de los coeficientes pueden ser inestables y poco fiables.
# 2.3 Observaciones influyentes ------------------------------
# Calcular la distancia de Cook para cada observación
cooks_d <- cooks.distance(model_0)

# Encontrar el valor máximo
cook_max <- max(cooks_d)
cat(paste("\nMáx Cook's D:", format(cook_max, digits = 4)))
## 
## Máx Cook's D: 0.1664

Explicación del valor máximo de la Distancia de Cook

La salida Máx Cook's D: 0.1664 se refiere al valor máximo de la Distancia de Cook (Cook’s D) en tu modelo.

Interpretación del resultado:

La Distancia de Cook mide la influencia de cada observación individual en los coeficientes estimados del modelo. Un valor alto indica que esa observación tiene un impacto desproporcionado en los resultados. Se suelen considerar dos umbrales principales:

  1. \(D_i > 4/n\): Donde \(n\) es el número de observaciones. Las observaciones que superan este umbral merecen una investigación más detallada.
    • En tu caso, \(n = 21613\).
    • Por lo tanto, \(4/n = 4 / 21613 \approx 0.000185\).
    • Tu valor cook_max de 0.1664 es significativamente mayor que este umbral.
  2. \(D_i > 1\): Las observaciones que superan este umbral se consideran altamente influyentes y pueden distorsionar gravemente los resultados del modelo.
    • Tu valor cook_max de 0.1664 es menor que 1.

Conclusión sobre la influencia:

El hecho de que el cook_max (0.1664) supere el umbral de \(4/n\) sugiere que hay al menos una observación (y posiblemente más) que ejerce una influencia considerable en tu modelo. Aunque no alcanza el nivel de “altamente influyente” (D > 1), estas observaciones tienen un impacto desproporcionado en las estimaciones de los coeficientes en comparación con la mayoría de los otros puntos de datos.

¿Qué debes hacer?

Dado que existen puntos con influencia notable, es recomendable investigar más a fondo:

  1. Identificar las Observaciones Influyentes: No solo te fijes en el máximo. Obtén una lista o un gráfico de las Distancias de Cook para todas las observaciones e identifica todas aquellas cuyo Cook’s D supere el umbral de \(4/n\).

  2. Examinar las Observaciones Identificadas: Revisa estas observaciones en tu conjunto de datos original. Pregúntate:

    • ¿Son errores de entrada de datos (p. ej., un precio incorrecto, un área desproporcionada)?
    • ¿Representan casos genuinos pero atípicos o extremos (p. ej., una propiedad única, una venta bajo circunstancias especiales)?
  3. Tomar Decisiones:

    • Si son errores: Corrige los datos si es posible. Si no, considera eliminar estas observaciones y reajustar el modelo.
    • Si son datos genuinos pero atípicos:
      • Considerar transformaciones: A veces, transformar variables puede mitigar la influencia de puntos extremos.
      • Usar modelos robustos: La regresión robusta es menos sensible a observaciones atípicas.
      • Mantener y reportar: Si decides mantenerlas, es importante ser consciente de su influencia y mencionarlo al reportar los resultados.
  4. Reevaluar el Modelo: Después de cualquier corrección, reajusta el modelo y vuelve a verificar todos los supuestos.

# 2.4 Homoscedasticidad --------------------------------------
# Prueba de Breusch-Pagan del paquete lmtest
bp_test_result <- bptest(model_0)
cat(paste("Breusch-Pagan p-value:", format(bp_test_result$p.value, scientific = TRUE, digits = 4)))
## Breusch-Pagan p-value: 4.937e-55

Explicación de la Prueba de Breusch-Pagan (Homoscedasticidad)

La salida Breusch-Pagan p-value: 4.937e-55 se interpreta de la siguiente manera:

La prueba de Breusch-Pagan se utiliza para detectar la heterocedasticidad en un modelo de regresión lineal. La heterocedasticidad ocurre cuando la varianza de los errores (residuos) no es constante a lo largo de todos los niveles de las variables independientes. El supuesto de homoscedasticidad (varianza constante de los errores) es crucial para la validez de las pruebas de significancia estándar (pruebas t y F) y los intervalos de confianza de los coeficientes de regresión.

  • Hipótesis Nula (\(H_0\)): Existe homocedasticidad (la varianza de los errores es constante).
  • Hipótesis Alternativa (\(H_1\)): Existe heterocedasticidad (la varianza de los errores no es constante y depende de al menos una de las variables independientes).

En este caso, el p-valor obtenido es 4.937e-55 (un número extremadamente pequeño, prácticamente cero).

Conclusión: Dado que el p-valor (4.937e-55) es mucho menor que cualquier nivel de significancia convencional (por ejemplo, 0.05, 0.01, 0.001), se rechaza la hipótesis nula de homocedasticidad.

Esto indica que hay una fuerte evidencia de heterocedasticidad en el modelo. Es decir, la varianza de los errores del modelo no es constante, sino que varía con los niveles de las variables predictoras.

Consecuencias de la Heterocedasticidad: * Los estimadores de los coeficientes de regresión (\(\hat\beta\)) siguen siendo insesgados, pero ya no son los de mínima varianza (no son eficientes). * Los errores estándar de los coeficientes de regresión están sesgados. Esto invalida las pruebas t, las pruebas F y los intervalos de confianza calculados de la manera usual.

Para abordar este problema, se podrían considerar soluciones como: * Transformar la variable dependiente (aunque ya se usó np.log(price), podría explorarse más). * Utilizar errores estándar robustos a la heterocedasticidad (por ejemplo, estimadores de White, Huber-White o HC0, HC1, etc.). * Aplicar Mínimos Cuadrados Ponderados (WLS) si se conoce la forma de la heterocedasticidad.

# 2.5 Normalidad ---------------------------------------------
# Prueba de Jarque-Bera del paquete tseries
jb_test_result <- jarque.bera.test(resid(model_0))
cat(paste("Jarque-Bera  p-value:", format(jb_test_result$p.value, scientific = TRUE, digits = 4)))
## Jarque-Bera  p-value: 1.087e-09

Explicación de la Prueba de Jarque-Bera (Normalidad de los Residuos)

La salida Jarque-Bera p-value: 1.087e-09 se interpreta de la siguiente manera:

La prueba de Jarque-Bera es una prueba de bondad de ajuste para verificar si los datos de la muestra (en este caso, los residuos del modelo) tienen la asimetría (skewness) y la curtosis (kurtosis) que coinciden con una distribución normal.

  • Hipótesis Nula (\(H_0\)): Los residuos se distribuyen normalmente.
  • Hipótesis Alternativa (\(H_1\)): Los residuos no se distribuyen normalmente.

En este caso, el p-valor obtenido es 1.087e-09 (un número extremadamente pequeño, mucho menor que 0.001).

Conclusión: Dado que el p-valor (1.087e-09) es significativamente menor que los niveles de significancia comunes (por ejemplo, 0.05, 0.01), se rechaza la hipótesis nula.

Esto indica que hay una fuerte evidencia de que los residuos del modelo no siguen una distribución normal.

Consecuencias de la No Normalidad de los Residuos: * Muestras Pequeñas: Si los errores no son normales y el tamaño de la muestra es pequeño, las pruebas de hipótesis (pruebas t y F) y los intervalos de confianza para los coeficientes de regresión pueden no ser fiables. Sus distribuciones teóricas (t y F) dependen del supuesto de normalidad. * Muestras Grandes: Para muestras grandes (como es el caso aquí, con más de 21,000 observaciones), el Teorema del Límite Central a menudo entra en juego. Este teorema sugiere que los estimadores de los coeficientes de regresión (\(\hat\beta\)) tienden a distribuirse aproximadamente de forma normal, incluso si los errores originales no lo hacen. Por lo tanto, en muestras grandes, la violación del supuesto de normalidad de los errores suele ser menos preocupante para la validez de las inferencias sobre los coeficientes. Sin embargo, la no normalidad aún podría indicar otros problemas subyacentes en el modelo, como la omisión de variables importantes o una forma funcional incorrecta, que ya fueron señalados por la prueba RESET.

Aunque la no normalidad es estadísticamente significativa, dado el gran tamaño de la muestra, su impacto en la fiabilidad de las pruebas t y F para los coeficientes podría ser limitado. No obstante, es una pieza más de evidencia que sugiere que el modelo actual podría beneficiarse de mejoras en su especificación.

# 2.6 Independencia ------------------------------------------
# Prueba de Durbin-Watson del paquete lmtest
dw_test_result <- dwtest(model_0)
cat(paste("Durbin-Watson statistic:", format(dw_test_result$statistic, digits = 4)))
## Durbin-Watson statistic: 1.976

Explicación del Estadístico de Durbin-Watson (Independencia de los Errores)

La salida Durbin-Watson statistic: 1.976 se interpreta de la siguiente manera:

El estadístico de Durbin-Watson (DW) se utiliza para detectar la presencia de autocorrelación en los residuos de un modelo de regresión. Este supuesto es particularmente importante para datos de series temporales, pero también puede ser relevante en datos de corte transversal si hay algún ordenamiento inherente en las observaciones.

  • Hipótesis Nula (\(H_0\)): No hay autocorrelación entre los residuos.
  • Hipótesis Alternativa (\(H_1\)): Existe autocorrelación.

Interpretación del valor del estadístico DW:

El estadístico varía entre 0 y 4: * DW ≈ 2: Indica que no hay autocorrelación. * DW < 2 (hacia 0): Sugiere autocorrelación positiva. * DW > 2 (hacia 4): Sugiere autocorrelación negativa.

Como regla general, valores entre 1.5 y 2.5 se consideran aceptables.

Conclusión para el Modelo Actual:

El estadístico de Durbin-Watson es 1.976. Este valor está muy cerca de 2.0 y dentro del rango aceptable, lo que sugiere una ausencia de autocorrelación de primer orden significativa en los residuos del modelo. Por lo tanto, el supuesto de independencia de los errores parece cumplirse razonablemente bien.

Orden Prueba (R packages) Hipótesis nula H₀ Cómo leer el p-value
1 resettest (lmtest) El modelo es lineal y no faltan potencias ni interacciones p > 0.05 ⇒ forma adecuada. p ≤ 0.05 ⇒ agregar polinomios, logs o variables omitidas.
2 vif (car) No hay multicolinealidad grave VIF < 10 (ideal < 5) = OK. Valores grandes ⇒ remover/comprimir variables.
3 cooks.distance (stats) Ningún punto influye excesivamente Regla práctica: Cook > 4/n indica outlier influyente; considerar revisarlo o usar robust SE/WLS.
4 bptest (lmtest) Homoscedasticidad (Var(ε) constante) p > 0.05 ⇒ varianza constante; p ≤ 0.05 ⇒ heteroscedasticidad ⇒ log/Box-Cox, WLS o SE robustas.
5 jarque.bera.test (tseries) Normalidad de errores p > 0.05 ⇒ residuos ~ normales; p ≤ 0.05 ⇒ asimetría/colas ⇒ transformar y o usar bootstrap/robust SE.
6 dwtest (lmtest) No autocorrelación DW ≈ 2 indica independencia; valores ≪ 2 o ≫ 2 indican autocorrelación positiva o negativa.

Orden lógico: forma → estabilidad → outliers → varianza → distribución → dependencia. Corriges lo que falla y vuelves a correr las pruebas, avanzando secuencialmente hasta obtener un modelo cuyos supuestos estén (al menos) mitigados o tratados con métodos robustos.

# 1. Datos y transformaciones usando dplyr::mutate
df <- df %>%
  mutate(
    log_sqft = log(sqft_living),
    log_lot = log(sqft_lot),
    sqft2 = log_sqft^2,
    grade2 = grade^2,
    age = 2015 - yr_built,
    age2 = age^2,
    sqft_grade = log_sqft * grade,
    renovated = as.integer(yr_renovated > 0)
  )

# Transformación de Box-Cox para la variable dependiente
# La función boxcox de MASS ayuda a encontrar el lambda óptimo
bc_result <- boxcox(df$price ~ 1, plotit = FALSE)
lambda <- bc_result$x[which.max(bc_result$y)]

# Aplicar la transformación con el lambda encontrado
df$bc_price <- (df$price^lambda - 1) / lambda
# Definir la fórmula para el nuevo modelo
formula_1 <- bc_price ~ log_sqft + sqft2 + bedrooms + bathrooms + floors +
             waterfront + view + grade + grade2 + condition +
             log_lot + sqft_grade + age + age2 + renovated
# 2. OLS preliminar para obtener los pesos
ols_pre <- lm(formula_1, data = df)

# Calcular los pesos. pmax es el equivalente a np.maximum
weights <- 1 / pmax(fitted(ols_pre), 0.1)^2
head(weights)
##          1          2          3          4          5          6 
## 0.04721073 0.04650500 0.04756456 0.04672165 0.04681600 0.04517597
# 3. Ajustar el modelo WLS (Mínimos Cuadrados Ponderados)
# y calcular errores estándar robustos HC3
# Usaremos lm() con el argumento 'weights'
wls_model <- lm(formula_1, data = df, weights = weights)

# Para obtener un resumen con errores robustos, combinamos lmtest y sandwich
# coeftest aplica la corrección de la matriz de covarianza (vcovHC)
wls_summary_robust <- coeftest(wls_model, vcov = vcovHC(wls_model, "HC3"))

# Para un resumen más completo similar al de Python, imprimimos varias partes:
print("Resumen de Coeficientes WLS con Errores Robustos HC3")
## [1] "Resumen de Coeficientes WLS con Errores Robustos HC3"
print(wls_summary_robust)
## 
## t test of coefficients:
## 
##                Estimate  Std. Error  t value  Pr(>|t|)    
## (Intercept)  4.7117e+00  5.4431e-02  86.5634 < 2.2e-16 ***
## log_sqft    -1.1822e-01  1.7316e-02  -6.8270 8.902e-12 ***
## sqft2        1.1301e-02  1.4653e-03   7.7120 1.292e-14 ***
## bedrooms    -2.4624e-03  4.0546e-04  -6.0730 1.276e-09 ***
## bathrooms    4.2182e-03  3.8782e-04  10.8767 < 2.2e-16 ***
## floors       2.1572e-03  4.0964e-04   5.2660 1.408e-07 ***
## waterfront   2.1494e-02  1.9958e-03  10.7697 < 2.2e-16 ***
## view         3.7860e-03  2.2181e-04  17.0691 < 2.2e-16 ***
## grade        4.4591e-02  5.2057e-03   8.5657 < 2.2e-16 ***
## grade2      -6.0630e-04  1.7585e-04  -3.4479  0.000566 ***
## condition    3.2456e-03  2.9950e-04  10.8366 < 2.2e-16 ***
## log_lot     -2.5839e-03  2.2839e-04 -11.3138 < 2.2e-16 ***
## sqft_grade  -2.4984e-03  9.0152e-04  -2.7713  0.005587 ** 
## age          1.2548e-04  2.7295e-05   4.5971 4.309e-06 ***
## age2         2.4262e-06  2.3227e-07  10.4455 < 2.2e-16 ***
## renovated    7.0713e-04  9.1021e-04   0.7769  0.437237    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
cat("\n--- Estadísticas del Modelo ---\n")
## 
## --- Estadísticas del Modelo ---
# R-cuadrado y otros estadísticos del modelo original wls_model
summary_wls <- summary(wls_model)
cat(paste("R-squared:", round(summary_wls$r.squared, 3), "\n"))
## R-squared: 0.631
cat(paste("Adj. R-squared:", round(summary_wls$adj.r.squared, 3), "\n"))
## Adj. R-squared: 0.631
cat(paste("F-statistic on", summary_wls$fstatistic[2], "and", summary_wls$fstatistic[3], "DF, p-value:", format.pval(pf(summary_wls$fstatistic[1], summary_wls$fstatistic[2], summary_wls$fstatistic[3], lower.tail = FALSE)), "\n"))
## F-statistic on 15 and 21597 DF, p-value: < 2.22e-16
cat(paste("AIC:", AIC(wls_model), "\n"))
## AIC: -101329.302359065
cat(paste("BIC:", BIC(wls_model), "\n"))
## BIC: -101193.624504568

Explicación de WLS y HC3

En el contexto de tu modelo, se utilizan Mínimos Cuadrados Ponderados (WLS) y errores estándar robustos HC3 para abordar el problema de la heterocedasticidad, que fue detectado previamente por la prueba de Breusch-Pagan (con un p-valor muy bajo, indicando varianza no constante de los errores).

WLS (Weighted Least Squares - Mínimos Cuadrados Ponderados)

  1. ¿Qué es y qué hace?
    • WLS es una variante de los Mínimos Cuadrados Ordinarios (OLS). Mientras que OLS asume que todos los errores tienen la misma varianza (homoscedasticidad), WLS permite que diferentes observaciones tengan diferentes varianzas.
    • WLS funciona asignando un peso a cada observación en el proceso de estimación. Las observaciones que se consideran más precisas (es decir, aquellas con menor varianza de error) reciben un peso mayor, y las observaciones menos precisas (con mayor varianza de error) reciben un peso menor.
  • El objetivo es minimizar la suma ponderada de los cuadrados de los residuos: $ w_i (y_i - _i)^2 $.
  1. ¿Por qué se usa?
    • Se utiliza principalmente para corregir la heterocedasticidad. Cuando la varianza de los errores no es constante, los estimadores OLS siguen siendo insesgados, pero ya no son los más eficientes (no tienen la mínima varianza). WLS puede producir estimadores de coeficientes más eficientes (con menor varianza) que OLS en presencia de heteroscedasticidad, siempre que los pesos se especifiquen correctamente.
  2. ¿Cuándo se usa?
    • Cuando hay evidencia de heterocedasticidad y se tiene una idea de cómo varía la varianza de los errores con las observaciones. Los pesos (\(w_i\)) suelen ser inversamente proporcionales a la varianza del error de cada observación (\(w_i \propto 1/\sigma_i^2\)).
    • En este código, los pesos se calculan como 1 / pmax(fitted(ols_pre), 0.1)^2. Esto implica una suposición de que la varianza del error es proporcional al cuadrado de los valores ajustados del modelo (una forma común de heterocedasticidad). Se usa pmax para evitar la división por cero o por valores muy pequeños.

HC3 (Errores Estándar Robustos a la Heteroscedasticidad - Tipo 3)

  1. ¿Qué es y qué hace?
    • HC3 se refiere a un tipo específico de estimador de la matriz de covarianza robusto a la heterocedasticidad (también conocidos como errores estándar de Eicker-Huber-White). “HC” significa “Heteroscedasticity-Consistent”.
    • Los errores estándar robustos (como HC0, HC1, HC2, HC3) ajustan el cálculo de los errores estándar para que sean consistentes (es decir, correctos en muestras grandes) incluso si hay heteroscedasticidad. No cambian los coeficientes estimados (\(\hat\beta\)), solo sus errores estándar y, por lo tanto, las inferencias estadísticas.
    • HC3 es una versión particular que aplica una corrección que tiende a ser más conservadora en muestras más pequeñas o cuando hay puntos de datos con alto apalancamiento (leverage).
  2. ¿Por qué se usa?
    • Para obtener inferencias estadísticas (pruebas t, p-valores, intervalos de confianza) válidas sobre los coeficientes del modelo cuando se sospecha o se ha detectado heteroscedasticidad.

¿Por qué se usan en este modelo ?

  1. Detección de Heteroscedasticidad: La prueba de Breusch-Pagan indicó una fuerte evidencia de heterocedasticidad en el modelo OLS inicial.
  2. Intento de Corrección con WLS: Se ajusta un modelo WLS para intentar modelar explícitamente la heterocedasticidad y obtener estimadores de coeficientes más eficientes.
  3. Asegurar Inferencias Válidas con HC3: Después de ajustar el modelo WLS, se calculan los errores estándar robustos HC3. Esto se hace porque la especificación de los pesos en WLS podría no ser perfecta, y HC3 proporciona una capa adicional de robustez para las inferencias.

En resumen, estás utilizando WLS para intentar obtener mejores estimaciones de los coeficientes, y luego utilizando errores estándar HC3 para asegurar que tus conclusiones estadísticas sobre esos coeficientes sean fiables.

# 4. Prueba de Breusch-Pagan en el modelo WLS
bp_p_wls <- bptest(wls_model)
cat("Breusch–Pagan p:", bp_p_wls$p.value)
## Breusch–Pagan p: 7.427567e-57
# 5. VIF en el modelo WLS
vif_wls <- vif(wls_model)
print("VIF (primeras 10 variables):")
## [1] "VIF (primeras 10 variables):"
print(head(vif_wls, 10))
##    log_sqft       sqft2    bedrooms   bathrooms      floors  waterfront 
## 1890.166353 3235.900572    1.792153    3.347972    2.145970    1.201251 
##        view       grade      grade2   condition 
##    1.347618 1178.213975  444.307748    1.253729

Modelo 2

Supuesto Resultado Interpretación
Linealidad (RESET) p ≈ 1.4 × 10⁻⁸ (aún rechaza) Queda curvatura menor; en práctica se tolera dada la elasticidad log/Box-Cox.
Homoscedasticidad (BP) p ≈ 7 × 10⁻²⁶⁵ → rechaza Heteroscedasticidad estructural, pero usamos pesos + HC3, por lo que EE son consistentes.
Normalidad (JB) p ≈ 0 → rechaza Con n ≫ 30 000, la ligera asimetría siempre se detecta; Box-Cox ya estiliza colas.
Colinealidad (VIF) VIF < 10 (log_sqft y sqft2 altos pero aceptables) Sin inestabilidad numérica severa.
Influencias (Cook D) Máx ≈ 0.17 (> 4/n) Algunos puntos caros influyen; HC3 penaliza su impacto.
Independencia (DW) ≈ 1.98 No hay autocorrelación.

Ejercicio (30 min)

Objetivo: construir un nuevo modelo lineal que mejore el AIC del modelo actual.

Nota:

  • La normalidad de los residuos puede ignorarse (n ≫ 30).
  • Si eliges WLS con errores robustos (HC3), la heteroscedasticidad deja de ser un problema práctico; los demás supuestos deben revisarse.

Pasos sugeridos

  1. Explora nuevas variables o transformaciones

    • Logs, cuadrados, interacciones, variables de ubicación, etc.
    • Elimina predictores redundantes (VIF > 10) para evitar colinealidad severa.
  2. Ajusta el modelo

    • Usa lm(...) o lm(..., weights=...) en R.
    • Aplica coeftest con vcovHC para obtener errores robustos.
  3. Diagnostica los supuestos clave

    • Linealidad / especificación → gráfico de residuos y resettest (p > 0.05 deseable).
    • Colinealidadvif (ideal < 10).
    • Autocorrelacióndwtest ≈ 2.
    • (Heteroscedasticidad solo si NO usas WLS) → bptest.
  4. Compara AIC

    • Registra el AIC(model).
    • El nuevo modelo es aceptable si AIC_new < AIC_prev y no viola los supuestos revisados en 3.
# Preparación de datos y pesos para el modelo final
df <- df %>%
  mutate(
    log_price = log(price),
    w = 1 / log_sqft^2,
    zipcode = as.factor(zipcode) # Asegurarse de que zipcode sea un factor
  )

# ---------- 1. Fórmula lineal completa ----------
formula_final_zip <- log_price ~ log_sqft + sqft2 + bedrooms + bathrooms + floors +
                     waterfront + view + grade + grade2 + condition + renovated +
                     log_lot + sqft_grade + age + age2 +
                     lat + long + zipcode

# ---------- 2. WLS con pesos fijos y errores robustos ----------
wls_w_zip <- lm(formula_final_zip, data = df, weights = w)
wls_w_zip_robust_summary <- coeftest(wls_w_zip, vcov = vcovHC(wls_w_zip, type = "HC3"))

# Imprimir el resumen
print(summary(wls_w_zip)) # Resumen estándar para R-cuadrado, etc.
## 
## Call:
## lm(formula = formula_final_zip, data = df, weights = w)
## 
## Weighted Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.185122 -0.012468  0.000989  0.013405  0.140334 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -8.260e+01  6.951e+00 -11.884  < 2e-16 ***
## log_sqft      4.763e-01  1.265e-01   3.766 0.000167 ***
## sqft2        -4.575e-02  1.103e-02  -4.146 3.40e-05 ***
## bedrooms     -8.418e-03  1.823e-03  -4.618 3.91e-06 ***
## bathrooms     1.961e-02  3.021e-03   6.490 8.78e-11 ***
## floors       -9.006e-03  3.458e-03  -2.604 0.009210 ** 
## waterfront    4.492e-01  1.677e-02  26.783  < 2e-16 ***
## view          6.475e-02  2.020e-03  32.062  < 2e-16 ***
## grade        -3.624e-01  3.661e-02  -9.900  < 2e-16 ***
## grade2       -1.200e-02  1.406e-03  -8.537  < 2e-16 ***
## condition     5.614e-02  2.173e-03  25.828  < 2e-16 ***
## renovated     7.318e-02  6.719e-03  10.891  < 2e-16 ***
## log_lot       8.132e-02  2.195e-03  37.056  < 2e-16 ***
## sqft_grade    8.546e-02  6.998e-03  12.213  < 2e-16 ***
## age          -4.693e-03  2.274e-04 -20.639  < 2e-16 ***
## age2          4.251e-05  1.869e-06  22.740  < 2e-16 ***
## lat           5.614e-01  7.221e-02   7.775 7.91e-15 ***
## long         -5.339e-01  5.106e-02 -10.458  < 2e-16 ***
## zipcode98002  2.510e-02  1.609e-02   1.560 0.118865    
## zipcode98003  1.386e-02  1.457e-02   0.951 0.341431    
## zipcode98004  1.028e+00  2.685e-02  38.290  < 2e-16 ***
## zipcode98005  6.646e-01  2.872e-02  23.141  < 2e-16 ***
## zipcode98006  5.996e-01  2.340e-02  25.623  < 2e-16 ***
## zipcode98007  5.970e-01  2.948e-02  20.247  < 2e-16 ***
## zipcode98008  6.087e-01  2.799e-02  21.744  < 2e-16 ***
## zipcode98010  3.477e-01  2.480e-02  14.023  < 2e-16 ***
## zipcode98011  2.714e-01  3.648e-02   7.439 1.05e-13 ***
## zipcode98014  2.894e-01  3.984e-02   7.265 3.85e-13 ***
## zipcode98019  2.486e-01  3.931e-02   6.324 2.59e-10 ***
## zipcode98022  2.285e-01  2.147e-02  10.645  < 2e-16 ***
## zipcode98023 -5.407e-02  1.339e-02  -4.037 5.43e-05 ***
## zipcode98024  4.546e-01  3.479e-02  13.066  < 2e-16 ***
## zipcode98027  5.273e-01  2.387e-02  22.093  < 2e-16 ***
## zipcode98028  2.061e-01  3.542e-02   5.820 5.98e-09 ***
## zipcode98029  6.384e-01  2.731e-02  23.375  < 2e-16 ***
## zipcode98030  7.668e-02  1.606e-02   4.774 1.81e-06 ***
## zipcode98031  8.701e-02  1.672e-02   5.205 1.96e-07 ***
## zipcode98032 -4.601e-02  1.918e-02  -2.400 0.016425 *  
## zipcode98033  6.475e-01  3.039e-02  21.304  < 2e-16 ***
## zipcode98034  3.776e-01  3.255e-02  11.601  < 2e-16 ***
## zipcode98038  2.718e-01  1.796e-02  15.132  < 2e-16 ***
## zipcode98039  1.173e+00  3.752e-02  31.269  < 2e-16 ***
## zipcode98040  8.093e-01  2.391e-02  33.846  < 2e-16 ***
## zipcode98042  1.264e-01  1.531e-02   8.258  < 2e-16 ***
## zipcode98045  4.922e-01  3.303e-02  14.902  < 2e-16 ***
## zipcode98052  5.451e-01  3.091e-02  17.632  < 2e-16 ***
## zipcode98053  5.203e-01  3.314e-02  15.701  < 2e-16 ***
## zipcode98055  1.231e-01  1.861e-02   6.618 3.73e-11 ***
## zipcode98056  2.768e-01  2.028e-02  13.650  < 2e-16 ***
## zipcode98058  1.738e-01  1.761e-02   9.873  < 2e-16 ***
## zipcode98059  3.309e-01  1.990e-02  16.628  < 2e-16 ***
## zipcode98065  5.274e-01  3.074e-02  17.156  < 2e-16 ***
## zipcode98070  8.873e-02  2.332e-02   3.805 0.000142 ***
## zipcode98072  3.219e-01  3.625e-02   8.881  < 2e-16 ***
## zipcode98074  5.328e-01  2.927e-02  18.200  < 2e-16 ***
## zipcode98075  5.745e-01  2.816e-02  20.400  < 2e-16 ***
## zipcode98077  3.133e-01  3.777e-02   8.295  < 2e-16 ***
## zipcode98092  8.659e-02  1.464e-02   5.914 3.38e-09 ***
## zipcode98102  8.047e-01  3.129e-02  25.715  < 2e-16 ***
## zipcode98103  6.035e-01  2.938e-02  20.538  < 2e-16 ***
## zipcode98105  7.777e-01  3.021e-02  25.739  < 2e-16 ***
## zipcode98106  1.893e-01  2.154e-02   8.788  < 2e-16 ***
## zipcode98107  6.179e-01  3.019e-02  20.468  < 2e-16 ***
## zipcode98108  2.213e-01  2.380e-02   9.299  < 2e-16 ***
## zipcode98109  8.003e-01  3.120e-02  25.652  < 2e-16 ***
## zipcode98112  8.854e-01  2.780e-02  31.854  < 2e-16 ***
## zipcode98115  6.246e-01  2.986e-02  20.918  < 2e-16 ***
## zipcode98116  5.715e-01  2.420e-02  23.611  < 2e-16 ***
## zipcode98117  5.720e-01  3.021e-02  18.936  < 2e-16 ***
## zipcode98118  3.498e-01  2.113e-02  16.555  < 2e-16 ***
## zipcode98119  7.710e-01  2.948e-02  26.150  < 2e-16 ***
## zipcode98122  6.507e-01  2.628e-02  24.759  < 2e-16 ***
## zipcode98125  3.572e-01  3.221e-02  11.089  < 2e-16 ***
## zipcode98126  3.813e-01  2.208e-02  17.269  < 2e-16 ***
## zipcode98133  2.140e-01  3.323e-02   6.440 1.22e-10 ***
## zipcode98136  5.172e-01  2.271e-02  22.770  < 2e-16 ***
## zipcode98144  5.223e-01  2.444e-02  21.377  < 2e-16 ***
## zipcode98146  1.330e-01  2.020e-02   6.586 4.63e-11 ***
## zipcode98148  8.730e-02  2.703e-02   3.230 0.001241 ** 
## zipcode98155  1.887e-01  3.458e-02   5.455 4.94e-08 ***
## zipcode98166  1.978e-01  1.863e-02  10.618  < 2e-16 ***
## zipcode98168 -3.600e-02  1.943e-02  -1.853 0.063930 .  
## zipcode98177  3.369e-01  3.481e-02   9.678  < 2e-16 ***
## zipcode98178  8.003e-02  2.019e-02   3.964 7.40e-05 ***
## zipcode98188  3.016e-02  2.065e-02   1.461 0.144062    
## zipcode98198  1.888e-02  1.563e-02   1.207 0.227338    
## zipcode98199  6.479e-01  2.874e-02  22.548  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.02418 on 21526 degrees of freedom
## Multiple R-squared:  0.8774, Adjusted R-squared:  0.8769 
## F-statistic:  1791 on 86 and 21526 DF,  p-value: < 2.2e-16
print(wls_w_zip_robust_summary) # Resumen con errores robustos para coeficientes
## 
## t test of coefficients:
## 
##                 Estimate  Std. Error  t value  Pr(>|t|)    
## (Intercept)  -8.2604e+01  8.2188e+00 -10.0507 < 2.2e-16 ***
## log_sqft      4.7627e-01  1.5691e-01   3.0354 0.0024053 ** 
## sqft2        -4.5748e-02  1.3014e-02  -3.5154 0.0004401 ***
## bedrooms     -8.4176e-03  2.2602e-03  -3.7244 0.0001963 ***
## bathrooms     1.9606e-02  3.3169e-03   5.9111 3.450e-09 ***
## floors       -9.0062e-03  3.4621e-03  -2.6014 0.0092919 ** 
## waterfront    4.4918e-01  2.3627e-02  19.0116 < 2.2e-16 ***
## view          6.4752e-02  2.3111e-03  28.0174 < 2.2e-16 ***
## grade        -3.6242e-01  4.5317e-02  -7.9973 1.335e-15 ***
## grade2       -1.2001e-02  1.6499e-03  -7.2737 3.617e-13 ***
## condition     5.6138e-02  2.6413e-03  21.2535 < 2.2e-16 ***
## renovated     7.3183e-02  8.1907e-03   8.9349 < 2.2e-16 ***
## log_lot       8.1323e-02  2.6966e-03  30.1582 < 2.2e-16 ***
## sqft_grade    8.5464e-02  8.1091e-03  10.5392 < 2.2e-16 ***
## age          -4.6927e-03  2.5075e-04 -18.7146 < 2.2e-16 ***
## age2          4.2508e-05  2.1785e-06  19.5130 < 2.2e-16 ***
## lat           5.6138e-01  7.9901e-02   7.0260 2.189e-12 ***
## long         -5.3392e-01  6.1562e-02  -8.6729 < 2.2e-16 ***
## zipcode98002  2.5098e-02  1.4611e-02   1.7178 0.0858525 .  
## zipcode98003  1.3858e-02  1.3085e-02   1.0591 0.2895716    
## zipcode98004  1.0283e+00  2.8724e-02  35.7982 < 2.2e-16 ***
## zipcode98005  6.6456e-01  2.9706e-02  22.3710 < 2.2e-16 ***
## zipcode98006  5.9959e-01  2.5088e-02  23.8999 < 2.2e-16 ***
## zipcode98007  5.9696e-01  2.9324e-02  20.3574 < 2.2e-16 ***
## zipcode98008  6.0865e-01  2.9295e-02  20.7770 < 2.2e-16 ***
## zipcode98010  3.4772e-01  3.6776e-02   9.4551 < 2.2e-16 ***
## zipcode98011  2.7140e-01  3.8189e-02   7.1068 1.224e-12 ***
## zipcode98014  2.8942e-01  4.8181e-02   6.0070 1.921e-09 ***
## zipcode98019  2.4861e-01  4.2364e-02   5.8685 4.462e-09 ***
## zipcode98022  2.2854e-01  2.2617e-02  10.1048 < 2.2e-16 ***
## zipcode98023 -5.4065e-02  1.2948e-02  -4.1754 2.986e-05 ***
## zipcode98024  4.5460e-01  3.7948e-02  11.9796 < 2.2e-16 ***
## zipcode98027  5.2734e-01  2.6457e-02  19.9317 < 2.2e-16 ***
## zipcode98028  2.0613e-01  3.7717e-02   5.4652 4.676e-08 ***
## zipcode98029  6.3839e-01  2.8896e-02  22.0924 < 2.2e-16 ***
## zipcode98030  7.6676e-02  1.4453e-02   5.3053 1.136e-07 ***
## zipcode98031  8.7012e-02  1.5209e-02   5.7211 1.072e-08 ***
## zipcode98032 -4.6014e-02  2.0521e-02  -2.2423 0.0249491 *  
## zipcode98033  6.4747e-01  3.3302e-02  19.4423 < 2.2e-16 ***
## zipcode98034  3.7764e-01  3.5183e-02  10.7336 < 2.2e-16 ***
## zipcode98038  2.7182e-01  1.9063e-02  14.2588 < 2.2e-16 ***
## zipcode98039  1.1732e+00  3.5899e-02  32.6793 < 2.2e-16 ***
## zipcode98040  8.0931e-01  2.4570e-02  32.9394 < 2.2e-16 ***
## zipcode98042  1.2645e-01  1.5696e-02   8.0562 8.279e-16 ***
## zipcode98045  4.9217e-01  3.7782e-02  13.0265 < 2.2e-16 ***
## zipcode98052  5.4509e-01  3.3451e-02  16.2953 < 2.2e-16 ***
## zipcode98053  5.2031e-01  3.6505e-02  14.2529 < 2.2e-16 ***
## zipcode98055  1.2314e-01  1.9705e-02   6.2489 4.212e-10 ***
## zipcode98056  2.7683e-01  2.1240e-02  13.0334 < 2.2e-16 ***
## zipcode98058  1.7385e-01  1.8152e-02   9.5774 < 2.2e-16 ***
## zipcode98059  3.3094e-01  2.0681e-02  16.0025 < 2.2e-16 ***
## zipcode98065  5.2738e-01  3.3500e-02  15.7428 < 2.2e-16 ***
## zipcode98070  8.8727e-02  2.8501e-02   3.1132 0.0018533 ** 
## zipcode98072  3.2193e-01  3.8876e-02   8.2809 < 2.2e-16 ***
## zipcode98074  5.3278e-01  3.1675e-02  16.8203 < 2.2e-16 ***
## zipcode98075  5.7448e-01  3.0388e-02  18.9049 < 2.2e-16 ***
## zipcode98077  3.1335e-01  4.0205e-02   7.7937 6.803e-15 ***
## zipcode98092  8.6594e-02  1.3647e-02   6.3454 2.263e-10 ***
## zipcode98102  8.0472e-01  3.3561e-02  23.9777 < 2.2e-16 ***
## zipcode98103  6.0345e-01  3.1939e-02  18.8937 < 2.2e-16 ***
## zipcode98105  7.7766e-01  3.2157e-02  24.1835 < 2.2e-16 ***
## zipcode98106  1.8926e-01  2.4042e-02   7.8718 3.661e-15 ***
## zipcode98107  6.1791e-01  3.1732e-02  19.4729 < 2.2e-16 ***
## zipcode98108  2.2132e-01  2.8313e-02   7.8169 5.660e-15 ***
## zipcode98109  8.0031e-01  3.7487e-02  21.3492 < 2.2e-16 ***
## zipcode98112  8.8545e-01  3.1433e-02  28.1693 < 2.2e-16 ***
## zipcode98115  6.2457e-01  3.2272e-02  19.3533 < 2.2e-16 ***
## zipcode98116  5.7150e-01  2.5556e-02  22.3624 < 2.2e-16 ***
## zipcode98117  5.7202e-01  3.2658e-02  17.5156 < 2.2e-16 ***
## zipcode98118  3.4980e-01  2.4563e-02  14.2409 < 2.2e-16 ***
## zipcode98119  7.7102e-01  3.2608e-02  23.6453 < 2.2e-16 ***
## zipcode98122  6.5069e-01  2.8858e-02  22.5480 < 2.2e-16 ***
## zipcode98125  3.5718e-01  3.5131e-02  10.1670 < 2.2e-16 ***
## zipcode98126  3.8134e-01  2.4329e-02  15.6742 < 2.2e-16 ***
## zipcode98133  2.1399e-01  3.6041e-02   5.9373 2.942e-09 ***
## zipcode98136  5.1721e-01  2.3599e-02  21.9165 < 2.2e-16 ***
## zipcode98144  5.2235e-01  2.6385e-02  19.7973 < 2.2e-16 ***
## zipcode98146  1.3300e-01  2.5030e-02   5.3136 1.085e-07 ***
## zipcode98148  8.7300e-02  3.3631e-02   2.5958 0.0094428 ** 
## zipcode98155  1.8867e-01  3.7418e-02   5.0423 4.637e-07 ***
## zipcode98166  1.9783e-01  2.1001e-02   9.4198 < 2.2e-16 ***
## zipcode98168 -3.6002e-02  2.2389e-02  -1.6080 0.1078505    
## zipcode98177  3.3692e-01  3.8341e-02   8.7875 < 2.2e-16 ***
## zipcode98178  8.0030e-02  2.1655e-02   3.6956 0.0002199 ***
## zipcode98188  3.0160e-02  2.1403e-02   1.4091 0.1588095    
## zipcode98198  1.8875e-02  1.6859e-02   1.1196 0.2628986    
## zipcode98199  6.4795e-01  3.0746e-02  21.0739 < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# ---------- 3. Diagnósticos esenciales ----------

# AJUSTE: Crear un modelo OLS solo para las pruebas que no soportan WLS
ols_for_diag <- lm(formula_final_zip, data = df)

reset_p <- resettest(wls_w_zip, power = 2, type = "fitted")$p.value
bp_p    <- bptest(wls_w_zip)$p.value
jb_p    <- jarque.bera.test(resid(wls_w_zip))$p.value
# AJUSTE: Usar el modelo OLS para la prueba de Durbin-Watson
dw      <- dwtest(ols_for_diag)$statistic

cat(paste("\nRESET p-value        :", format(reset_p, scientific = TRUE, digits = 4)))
## 
## RESET p-value        : 4.547e-07
cat(paste("\nBreusch–Pagan p-value:", bp_p))
## 
## Breusch–Pagan p-value: 0.148661146926444
cat(paste("\nJarque–Bera p-value  :", jb_p))
## 
## Jarque–Bera p-value  : 0
cat(paste("\nDurbin–Watson        :", round(dw, 3)))
## 
## Durbin–Watson        : 2.006
# ---------- 4. VIF numéricas ----------
# El cálculo de VIF ya se hacía correctamente sobre un modelo OLS, así que no hay cambios aquí.
vif_model_zip <- lm(log_price ~ log_sqft + sqft2 + bedrooms + bathrooms + floors +
                     waterfront + view + grade + grade2 + condition + renovated +
                     log_lot + sqft_grade + age + age2 + lat + long, 
                   data = df)
vif_values_zip <- vif(vif_model_zip)
cat("\nMáx VIF numéricas:", max(vif_values_zip))
## 
## Máx VIF numéricas: 4283.198
# La selección hacia adelante (Forward Selection) en R se puede hacer eficientemente
# con la función step(). Compara modelos usando el Criterio de Información de Akaike (AIC).

# Crear un modelo base (solo intercepto) para la selección de variables
model_base <- lm(log_price ~ 1, data = df, weights = w)

# Crear un modelo completo con todas las variables candidatas
# zipcode se trata como un solo bloque
candidatas_formula <- log_price ~ log_sqft + sqft2 + bedrooms + bathrooms + floors +
                      waterfront + view + grade + grade2 + condition + renovated +
                      log_lot + sqft_grade + age + age2 + lat + long + zipcode

model_full <- lm(candidatas_formula, data = df, weights = w)

# Ejecutar la selección hacia adelante
# 'scope' define los modelos mínimo y máximo a considerar.
# 'direction' especifica que es una selección hacia adelante.
# 'trace = 1' muestra los pasos del proceso. En R Markdown, a veces la salida puede ser voluminosa,
# por lo que podrías usar 'trace = 0' para no mostrar los pasos y solo ver el resultado final.
modelo_final_stepwise <- step(model_base,
                              scope = list(lower = model_base, upper = model_full),
                              direction = "forward",
                              trace = 1)
## Start:  AIC=-115618
## log_price ~ 1
## 
##              Df Sum of Sq     RSS     AIC
## + sqft_grade  1    53.971  48.695 -131737
## + zipcode    69    54.250  48.417 -131725
## + grade2      1    49.282  53.384 -129750
## + grade       1    49.233  53.434 -129730
## + sqft2       1    45.927  56.740 -128433
## + log_sqft    1    45.085  57.582 -128114
## + bathrooms   1    29.985  72.682 -123081
## + lat         1    21.112  81.555 -120592
## + bedrooms    1    12.145  90.522 -118337
## + view        1    11.389  91.278 -118157
## + floors      1     9.849  92.817 -117796
## + waterfront  1     2.727  99.940 -116198
## + log_lot     1     1.400 101.266 -115913
## + renovated   1     1.216 101.451 -115873
## + age         1     0.708 101.959 -115766
## + long        1     0.214 102.453 -115661
## + condition   1     0.185 102.482 -115655
## + age2        1     0.044 102.623 -115625
## <none>                    102.667 -115618
## 
## Step:  AIC=-131737.3
## log_price ~ sqft_grade
## 
##              Df Sum of Sq    RSS     AIC
## + zipcode    69   29.2847 19.411 -151478
## + lat         1   15.3042 33.391 -139890
## + age2        1    8.1332 40.562 -135685
## + age         1    7.3878 41.308 -135291
## + view        1    2.3564 46.339 -132807
## + condition   1    1.7196 46.976 -132512
## + long        1    1.4291 47.266 -132379
## + waterfront  1    1.1226 47.573 -132239
## + grade       1    1.0655 47.630 -132213
## + sqft2       1    0.9265 47.769 -132150
## + renovated   1    0.8529 47.843 -132117
## + log_sqft    1    0.8291 47.866 -132106
## + grade2      1    0.7080 47.988 -132052
## + log_lot     1    0.1745 48.521 -131813
## + floors      1    0.0524 48.643 -131759
## + bathrooms   1    0.0415 48.654 -131754
## + bedrooms    1    0.0213 48.674 -131745
## <none>                    48.695 -131737
## 
## Step:  AIC=-151478
## log_price ~ sqft_grade + zipcode
## 
##              Df Sum of Sq    RSS     AIC
## + grade       1    3.3255 16.085 -155538
## + sqft2       1    2.9828 16.428 -155082
## + log_sqft    1    2.8492 16.562 -154907
## + grade2      1    2.4059 17.005 -154336
## + view        1    1.8399 17.571 -153628
## + log_lot     1    1.8355 17.575 -153623
## + waterfront  1    1.2314 18.179 -152893
## + age2        1    1.0894 18.321 -152724
## + age         1    1.0816 18.329 -152715
## + condition   1    0.8660 18.545 -152462
## + bedrooms    1    0.4445 18.966 -151977
## + bathrooms   1    0.3952 19.016 -151921
## + renovated   1    0.2532 19.158 -151760
## + floors      1    0.2045 19.206 -151705
## + long        1    0.0273 19.383 -151506
## + lat         1    0.0108 19.400 -151488
## <none>                    19.411 -151478
## 
## Step:  AIC=-155537.6
## log_price ~ sqft_grade + zipcode + grade
## 
##              Df Sum of Sq    RSS     AIC
## + view        1   1.41521 14.670 -157526
## + waterfront  1   1.13276 14.953 -157114
## + log_lot     1   0.85266 15.233 -156713
## + condition   1   0.50697 15.578 -156228
## + age2        1   0.41414 15.671 -156099
## + age         1   0.40533 15.680 -156087
## + renovated   1   0.14583 15.940 -155732
## + floors      1   0.12835 15.957 -155709
## + bedrooms    1   0.04192 16.043 -155592
## + long        1   0.04159 16.044 -155592
## + lat         1   0.01607 16.069 -155557
## + grade2      1   0.01205 16.073 -155552
## + bathrooms   1   0.00228 16.083 -155539
## <none>                    16.085 -155538
## + sqft2       1   0.00031 16.085 -155536
## + log_sqft    1   0.00012 16.085 -155536
## 
## Step:  AIC=-157526
## log_price ~ sqft_grade + zipcode + grade + view
## 
##              Df Sum of Sq    RSS     AIC
## + log_lot     1   0.66560 14.005 -158528
## + waterfront  1   0.43694 14.233 -158178
## + condition   1   0.42432 14.246 -158158
## + age2        1   0.28145 14.389 -157943
## + age         1   0.23689 14.433 -157876
## + renovated   1   0.08981 14.580 -157657
## + floors      1   0.06413 14.606 -157619
## + grade2      1   0.04432 14.626 -157589
## + long        1   0.03273 14.637 -157572
## + lat         1   0.02313 14.647 -157558
## + sqft2       1   0.01841 14.652 -157551
## + log_sqft    1   0.01786 14.652 -157550
## + bedrooms    1   0.00916 14.661 -157538
## <none>                    14.670 -157526
## + bathrooms   1   0.00005 14.670 -157524
## 
## Step:  AIC=-158527.6
## log_price ~ sqft_grade + zipcode + grade + view + log_lot
## 
##              Df Sum of Sq    RSS     AIC
## + waterfront  1   0.45095 13.553 -159233
## + condition   1   0.31578 13.689 -159018
## + age2        1   0.09730 13.907 -158676
## + grade2      1   0.08932 13.915 -158664
## + long        1   0.07491 13.930 -158641
## + renovated   1   0.07245 13.932 -158638
## + sqft2       1   0.05917 13.945 -158617
## + log_sqft    1   0.05836 13.946 -158616
## + bathrooms   1   0.05185 13.953 -158606
## + age         1   0.02893 13.976 -158570
## + lat         1   0.02740 13.977 -158568
## + floors      1   0.00573 13.999 -158534
## + bedrooms    1   0.00397 14.001 -158532
## <none>                    14.005 -158528
## 
## Step:  AIC=-159233
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront
## 
##             Df Sum of Sq    RSS     AIC
## + condition  1   0.31681 13.237 -159742
## + grade2     1   0.10281 13.451 -159396
## + age2       1   0.08543 13.468 -159368
## + sqft2      1   0.06764 13.486 -159339
## + log_sqft   1   0.06722 13.486 -159338
## + long       1   0.06667 13.487 -159338
## + renovated  1   0.05254 13.501 -159315
## + bathrooms  1   0.05079 13.503 -159312
## + lat        1   0.03234 13.521 -159283
## + age        1   0.02390 13.530 -159269
## + floors     1   0.00282 13.551 -159235
## + bedrooms   1   0.00132 13.552 -159233
## <none>                   13.553 -159233
## 
## Step:  AIC=-159742.2
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition
## 
##             Df Sum of Sq    RSS     AIC
## + grade2     1  0.083800 13.153 -159877
## + renovated  1  0.079262 13.158 -159870
## + bathrooms  1  0.065188 13.171 -159847
## + long       1  0.061574 13.175 -159841
## + sqft2      1  0.051545 13.185 -159824
## + log_sqft   1  0.050420 13.186 -159823
## + lat        1  0.037248 13.200 -159801
## + age2       1  0.028182 13.209 -159786
## + floors     1  0.024137 13.213 -159780
## + bedrooms   1  0.004166 13.233 -159747
## <none>                   13.237 -159742
## + age        1  0.000123 13.237 -159740
## 
## Step:  AIC=-159877.4
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2
## 
##             Df Sum of Sq    RSS     AIC
## + renovated  1  0.073098 13.080 -159996
## + long       1  0.056456 13.097 -159968
## + age2       1  0.048151 13.105 -159955
## + bathrooms  1  0.047753 13.105 -159954
## + lat        1  0.037673 13.115 -159937
## + floors     1  0.021643 13.131 -159911
## + bedrooms   1  0.017506 13.135 -159904
## + sqft2      1  0.005474 13.147 -159884
## + log_sqft   1  0.003344 13.150 -159881
## <none>                   13.153 -159877
## + age        1  0.001011 13.152 -159877
## 
## Step:  AIC=-159995.9
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated
## 
##             Df Sum of Sq    RSS     AIC
## + long       1  0.057386 13.022 -160089
## + bathrooms  1  0.043395 13.036 -160066
## + lat        1  0.036738 13.043 -160055
## + age2       1  0.024533 13.055 -160034
## + floors     1  0.021737 13.058 -160030
## + bedrooms   1  0.016748 13.063 -160022
## + sqft2      1  0.006176 13.074 -160004
## + log_sqft   1  0.003686 13.076 -160000
## + age        1  0.001785 13.078 -159997
## <none>                   13.080 -159996
## 
## Step:  AIC=-160088.9
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated + long
## 
##             Df Sum of Sq    RSS     AIC
## + bathrooms  1  0.045933 12.976 -160163
## + lat        1  0.031562 12.991 -160139
## + floors     1  0.024889 12.998 -160128
## + age2       1  0.020897 13.002 -160122
## + bedrooms   1  0.016989 13.005 -160115
## + sqft2      1  0.006369 13.016 -160097
## + log_sqft   1  0.003846 13.019 -160093
## + age        1  0.003438 13.019 -160093
## <none>                   13.022 -160089
## 
## Step:  AIC=-160163.3
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated + long + bathrooms
## 
##            Df Sum of Sq    RSS     AIC
## + age2      1  0.048001 12.928 -160241
## + lat       1  0.032906 12.944 -160216
## + bedrooms  1  0.026102 12.950 -160205
## + floors    1  0.012223 12.964 -160182
## + sqft2     1  0.007478 12.969 -160174
## + log_sqft  1  0.004149 12.972 -160168
## <none>                  12.976 -160163
## + age       1  0.000445 12.976 -160162
## 
## Step:  AIC=-160241.4
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated + long + bathrooms + age2
## 
##            Df Sum of Sq    RSS     AIC
## + age       1  0.275721 12.653 -160705
## + lat       1  0.032828 12.896 -160294
## + bedrooms  1  0.031082 12.897 -160291
## + floors    1  0.019066 12.909 -160271
## + sqft2     1  0.005314 12.923 -160248
## + log_sqft  1  0.002812 12.926 -160244
## <none>                  12.928 -160241
## 
## Step:  AIC=-160705.3
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated + long + bathrooms + age2 + 
##     age
## 
##            Df Sum of Sq    RSS     AIC
## + lat       1  0.037032 12.616 -160767
## + bedrooms  1  0.014416 12.638 -160728
## + floors    1  0.005526 12.647 -160713
## + sqft2     1  0.004036 12.649 -160710
## + log_sqft  1  0.001515 12.651 -160706
## <none>                  12.653 -160705
## 
## Step:  AIC=-160766.6
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated + long + bathrooms + age2 + 
##     age + lat
## 
##            Df Sum of Sq    RSS     AIC
## + bedrooms  1 0.0140326 12.602 -160789
## + floors    1 0.0046092 12.611 -160773
## + sqft2     1 0.0040340 12.612 -160772
## + log_sqft  1 0.0015628 12.614 -160767
## <none>                  12.616 -160767
## 
## Step:  AIC=-160788.7
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated + long + bathrooms + age2 + 
##     age + lat + bedrooms
## 
##            Df Sum of Sq    RSS     AIC
## + floors    1 0.0042812 12.597 -160794
## + sqft2     1 0.0027519 12.599 -160791
## <none>                  12.602 -160789
## + log_sqft  1 0.0008281 12.601 -160788
## 
## Step:  AIC=-160794
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated + long + bathrooms + age2 + 
##     age + lat + bedrooms + floors
## 
##            Df  Sum of Sq    RSS     AIC
## + sqft2     1 0.00240110 12.595 -160796
## <none>                   12.597 -160794
## + log_sqft  1 0.00064215 12.597 -160793
## 
## Step:  AIC=-160796.2
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated + long + bathrooms + age2 + 
##     age + lat + bedrooms + floors + sqft2
## 
##            Df Sum of Sq    RSS     AIC
## + log_sqft  1 0.0082911 12.587 -160808
## <none>                  12.595 -160796
## 
## Step:  AIC=-160808.4
## log_price ~ sqft_grade + zipcode + grade + view + log_lot + waterfront + 
##     condition + grade2 + renovated + long + bathrooms + age2 + 
##     age + lat + bedrooms + floors + sqft2 + log_sqft
# Mostrar el resumen del modelo final seleccionado por step()
# con errores robustos para una inferencia más fiable
print("Modelo final:")
## [1] "Modelo final:"
summary_stepwise <- summary(modelo_final_stepwise)
print(summary_stepwise) # Resumen estándar
## 
## Call:
## lm(formula = log_price ~ sqft_grade + zipcode + grade + view + 
##     log_lot + waterfront + condition + grade2 + renovated + long + 
##     bathrooms + age2 + age + lat + bedrooms + floors + sqft2 + 
##     log_sqft, data = df, weights = w)
## 
## Weighted Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.185122 -0.012468  0.000989  0.013405  0.140334 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -8.260e+01  6.951e+00 -11.884  < 2e-16 ***
## sqft_grade    8.546e-02  6.998e-03  12.213  < 2e-16 ***
## zipcode98002  2.510e-02  1.609e-02   1.560 0.118865    
## zipcode98003  1.386e-02  1.457e-02   0.951 0.341431    
## zipcode98004  1.028e+00  2.685e-02  38.290  < 2e-16 ***
## zipcode98005  6.646e-01  2.872e-02  23.141  < 2e-16 ***
## zipcode98006  5.996e-01  2.340e-02  25.623  < 2e-16 ***
## zipcode98007  5.970e-01  2.948e-02  20.247  < 2e-16 ***
## zipcode98008  6.087e-01  2.799e-02  21.744  < 2e-16 ***
## zipcode98010  3.477e-01  2.480e-02  14.023  < 2e-16 ***
## zipcode98011  2.714e-01  3.648e-02   7.439 1.05e-13 ***
## zipcode98014  2.894e-01  3.984e-02   7.265 3.85e-13 ***
## zipcode98019  2.486e-01  3.931e-02   6.324 2.59e-10 ***
## zipcode98022  2.285e-01  2.147e-02  10.645  < 2e-16 ***
## zipcode98023 -5.407e-02  1.339e-02  -4.037 5.43e-05 ***
## zipcode98024  4.546e-01  3.479e-02  13.066  < 2e-16 ***
## zipcode98027  5.273e-01  2.387e-02  22.093  < 2e-16 ***
## zipcode98028  2.061e-01  3.542e-02   5.820 5.98e-09 ***
## zipcode98029  6.384e-01  2.731e-02  23.375  < 2e-16 ***
## zipcode98030  7.668e-02  1.606e-02   4.774 1.81e-06 ***
## zipcode98031  8.701e-02  1.672e-02   5.205 1.96e-07 ***
## zipcode98032 -4.601e-02  1.918e-02  -2.400 0.016425 *  
## zipcode98033  6.475e-01  3.039e-02  21.304  < 2e-16 ***
## zipcode98034  3.776e-01  3.255e-02  11.601  < 2e-16 ***
## zipcode98038  2.718e-01  1.796e-02  15.132  < 2e-16 ***
## zipcode98039  1.173e+00  3.752e-02  31.269  < 2e-16 ***
## zipcode98040  8.093e-01  2.391e-02  33.846  < 2e-16 ***
## zipcode98042  1.264e-01  1.531e-02   8.258  < 2e-16 ***
## zipcode98045  4.922e-01  3.303e-02  14.902  < 2e-16 ***
## zipcode98052  5.451e-01  3.091e-02  17.632  < 2e-16 ***
## zipcode98053  5.203e-01  3.314e-02  15.701  < 2e-16 ***
## zipcode98055  1.231e-01  1.861e-02   6.618 3.73e-11 ***
## zipcode98056  2.768e-01  2.028e-02  13.650  < 2e-16 ***
## zipcode98058  1.738e-01  1.761e-02   9.873  < 2e-16 ***
## zipcode98059  3.309e-01  1.990e-02  16.628  < 2e-16 ***
## zipcode98065  5.274e-01  3.074e-02  17.156  < 2e-16 ***
## zipcode98070  8.873e-02  2.332e-02   3.805 0.000142 ***
## zipcode98072  3.219e-01  3.625e-02   8.881  < 2e-16 ***
## zipcode98074  5.328e-01  2.927e-02  18.200  < 2e-16 ***
## zipcode98075  5.745e-01  2.816e-02  20.400  < 2e-16 ***
## zipcode98077  3.133e-01  3.777e-02   8.295  < 2e-16 ***
## zipcode98092  8.659e-02  1.464e-02   5.914 3.38e-09 ***
## zipcode98102  8.047e-01  3.129e-02  25.715  < 2e-16 ***
## zipcode98103  6.035e-01  2.938e-02  20.538  < 2e-16 ***
## zipcode98105  7.777e-01  3.021e-02  25.739  < 2e-16 ***
## zipcode98106  1.893e-01  2.154e-02   8.788  < 2e-16 ***
## zipcode98107  6.179e-01  3.019e-02  20.468  < 2e-16 ***
## zipcode98108  2.213e-01  2.380e-02   9.299  < 2e-16 ***
## zipcode98109  8.003e-01  3.120e-02  25.652  < 2e-16 ***
## zipcode98112  8.854e-01  2.780e-02  31.854  < 2e-16 ***
## zipcode98115  6.246e-01  2.986e-02  20.918  < 2e-16 ***
## zipcode98116  5.715e-01  2.420e-02  23.611  < 2e-16 ***
## zipcode98117  5.720e-01  3.021e-02  18.936  < 2e-16 ***
## zipcode98118  3.498e-01  2.113e-02  16.555  < 2e-16 ***
## zipcode98119  7.710e-01  2.948e-02  26.150  < 2e-16 ***
## zipcode98122  6.507e-01  2.628e-02  24.759  < 2e-16 ***
## zipcode98125  3.572e-01  3.221e-02  11.089  < 2e-16 ***
## zipcode98126  3.813e-01  2.208e-02  17.269  < 2e-16 ***
## zipcode98133  2.140e-01  3.323e-02   6.440 1.22e-10 ***
## zipcode98136  5.172e-01  2.271e-02  22.770  < 2e-16 ***
## zipcode98144  5.223e-01  2.444e-02  21.377  < 2e-16 ***
## zipcode98146  1.330e-01  2.020e-02   6.586 4.63e-11 ***
## zipcode98148  8.730e-02  2.703e-02   3.230 0.001241 ** 
## zipcode98155  1.887e-01  3.458e-02   5.455 4.94e-08 ***
## zipcode98166  1.978e-01  1.863e-02  10.618  < 2e-16 ***
## zipcode98168 -3.600e-02  1.943e-02  -1.853 0.063930 .  
## zipcode98177  3.369e-01  3.481e-02   9.678  < 2e-16 ***
## zipcode98178  8.003e-02  2.019e-02   3.964 7.40e-05 ***
## zipcode98188  3.016e-02  2.065e-02   1.461 0.144062    
## zipcode98198  1.888e-02  1.563e-02   1.207 0.227338    
## zipcode98199  6.479e-01  2.874e-02  22.548  < 2e-16 ***
## grade        -3.624e-01  3.661e-02  -9.900  < 2e-16 ***
## view          6.475e-02  2.020e-03  32.062  < 2e-16 ***
## log_lot       8.132e-02  2.195e-03  37.056  < 2e-16 ***
## waterfront    4.492e-01  1.677e-02  26.783  < 2e-16 ***
## condition     5.614e-02  2.173e-03  25.828  < 2e-16 ***
## grade2       -1.200e-02  1.406e-03  -8.537  < 2e-16 ***
## renovated     7.318e-02  6.719e-03  10.891  < 2e-16 ***
## long         -5.339e-01  5.106e-02 -10.458  < 2e-16 ***
## bathrooms     1.961e-02  3.021e-03   6.490 8.78e-11 ***
## age2          4.251e-05  1.869e-06  22.740  < 2e-16 ***
## age          -4.693e-03  2.274e-04 -20.639  < 2e-16 ***
## lat           5.614e-01  7.221e-02   7.775 7.91e-15 ***
## bedrooms     -8.418e-03  1.823e-03  -4.618 3.91e-06 ***
## floors       -9.006e-03  3.458e-03  -2.604 0.009210 ** 
## sqft2        -4.575e-02  1.103e-02  -4.146 3.40e-05 ***
## log_sqft      4.763e-01  1.265e-01   3.766 0.000167 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.02418 on 21526 degrees of freedom
## Multiple R-squared:  0.8774, Adjusted R-squared:  0.8769 
## F-statistic:  1791 on 86 and 21526 DF,  p-value: < 2.2e-16
# Coeficientes con errores robustos
coeftest(modelo_final_stepwise, vcov. = vcovHC(modelo_final_stepwise, type = "HC3"))
## 
## t test of coefficients:
## 
##                 Estimate  Std. Error  t value  Pr(>|t|)    
## (Intercept)  -8.2604e+01  8.2188e+00 -10.0507 < 2.2e-16 ***
## sqft_grade    8.5464e-02  8.1091e-03  10.5392 < 2.2e-16 ***
## zipcode98002  2.5098e-02  1.4611e-02   1.7178 0.0858525 .  
## zipcode98003  1.3858e-02  1.3085e-02   1.0591 0.2895716    
## zipcode98004  1.0283e+00  2.8724e-02  35.7982 < 2.2e-16 ***
## zipcode98005  6.6456e-01  2.9706e-02  22.3710 < 2.2e-16 ***
## zipcode98006  5.9959e-01  2.5088e-02  23.8999 < 2.2e-16 ***
## zipcode98007  5.9696e-01  2.9324e-02  20.3574 < 2.2e-16 ***
## zipcode98008  6.0865e-01  2.9295e-02  20.7770 < 2.2e-16 ***
## zipcode98010  3.4772e-01  3.6776e-02   9.4551 < 2.2e-16 ***
## zipcode98011  2.7140e-01  3.8189e-02   7.1068 1.224e-12 ***
## zipcode98014  2.8942e-01  4.8181e-02   6.0070 1.921e-09 ***
## zipcode98019  2.4861e-01  4.2364e-02   5.8685 4.462e-09 ***
## zipcode98022  2.2854e-01  2.2617e-02  10.1048 < 2.2e-16 ***
## zipcode98023 -5.4065e-02  1.2948e-02  -4.1754 2.986e-05 ***
## zipcode98024  4.5460e-01  3.7948e-02  11.9796 < 2.2e-16 ***
## zipcode98027  5.2734e-01  2.6457e-02  19.9317 < 2.2e-16 ***
## zipcode98028  2.0613e-01  3.7717e-02   5.4652 4.676e-08 ***
## zipcode98029  6.3839e-01  2.8896e-02  22.0924 < 2.2e-16 ***
## zipcode98030  7.6676e-02  1.4453e-02   5.3053 1.136e-07 ***
## zipcode98031  8.7012e-02  1.5209e-02   5.7211 1.072e-08 ***
## zipcode98032 -4.6014e-02  2.0521e-02  -2.2423 0.0249491 *  
## zipcode98033  6.4747e-01  3.3302e-02  19.4423 < 2.2e-16 ***
## zipcode98034  3.7764e-01  3.5183e-02  10.7336 < 2.2e-16 ***
## zipcode98038  2.7182e-01  1.9063e-02  14.2588 < 2.2e-16 ***
## zipcode98039  1.1732e+00  3.5899e-02  32.6793 < 2.2e-16 ***
## zipcode98040  8.0931e-01  2.4570e-02  32.9394 < 2.2e-16 ***
## zipcode98042  1.2645e-01  1.5696e-02   8.0562 8.279e-16 ***
## zipcode98045  4.9217e-01  3.7782e-02  13.0265 < 2.2e-16 ***
## zipcode98052  5.4509e-01  3.3451e-02  16.2953 < 2.2e-16 ***
## zipcode98053  5.2031e-01  3.6505e-02  14.2529 < 2.2e-16 ***
## zipcode98055  1.2314e-01  1.9705e-02   6.2489 4.212e-10 ***
## zipcode98056  2.7683e-01  2.1240e-02  13.0334 < 2.2e-16 ***
## zipcode98058  1.7385e-01  1.8152e-02   9.5774 < 2.2e-16 ***
## zipcode98059  3.3094e-01  2.0681e-02  16.0025 < 2.2e-16 ***
## zipcode98065  5.2738e-01  3.3500e-02  15.7428 < 2.2e-16 ***
## zipcode98070  8.8727e-02  2.8501e-02   3.1132 0.0018533 ** 
## zipcode98072  3.2193e-01  3.8876e-02   8.2809 < 2.2e-16 ***
## zipcode98074  5.3278e-01  3.1675e-02  16.8203 < 2.2e-16 ***
## zipcode98075  5.7448e-01  3.0388e-02  18.9049 < 2.2e-16 ***
## zipcode98077  3.1335e-01  4.0205e-02   7.7937 6.803e-15 ***
## zipcode98092  8.6594e-02  1.3647e-02   6.3454 2.263e-10 ***
## zipcode98102  8.0472e-01  3.3561e-02  23.9777 < 2.2e-16 ***
## zipcode98103  6.0345e-01  3.1939e-02  18.8937 < 2.2e-16 ***
## zipcode98105  7.7766e-01  3.2157e-02  24.1835 < 2.2e-16 ***
## zipcode98106  1.8926e-01  2.4042e-02   7.8718 3.661e-15 ***
## zipcode98107  6.1791e-01  3.1732e-02  19.4729 < 2.2e-16 ***
## zipcode98108  2.2132e-01  2.8313e-02   7.8169 5.660e-15 ***
## zipcode98109  8.0031e-01  3.7487e-02  21.3492 < 2.2e-16 ***
## zipcode98112  8.8545e-01  3.1433e-02  28.1693 < 2.2e-16 ***
## zipcode98115  6.2457e-01  3.2272e-02  19.3533 < 2.2e-16 ***
## zipcode98116  5.7150e-01  2.5556e-02  22.3624 < 2.2e-16 ***
## zipcode98117  5.7202e-01  3.2658e-02  17.5156 < 2.2e-16 ***
## zipcode98118  3.4980e-01  2.4563e-02  14.2409 < 2.2e-16 ***
## zipcode98119  7.7102e-01  3.2608e-02  23.6453 < 2.2e-16 ***
## zipcode98122  6.5069e-01  2.8858e-02  22.5480 < 2.2e-16 ***
## zipcode98125  3.5718e-01  3.5131e-02  10.1670 < 2.2e-16 ***
## zipcode98126  3.8134e-01  2.4329e-02  15.6742 < 2.2e-16 ***
## zipcode98133  2.1399e-01  3.6041e-02   5.9373 2.942e-09 ***
## zipcode98136  5.1721e-01  2.3599e-02  21.9165 < 2.2e-16 ***
## zipcode98144  5.2235e-01  2.6385e-02  19.7973 < 2.2e-16 ***
## zipcode98146  1.3300e-01  2.5030e-02   5.3136 1.085e-07 ***
## zipcode98148  8.7300e-02  3.3631e-02   2.5958 0.0094428 ** 
## zipcode98155  1.8867e-01  3.7418e-02   5.0423 4.637e-07 ***
## zipcode98166  1.9783e-01  2.1001e-02   9.4198 < 2.2e-16 ***
## zipcode98168 -3.6002e-02  2.2389e-02  -1.6080 0.1078505    
## zipcode98177  3.3692e-01  3.8341e-02   8.7875 < 2.2e-16 ***
## zipcode98178  8.0030e-02  2.1655e-02   3.6956 0.0002199 ***
## zipcode98188  3.0160e-02  2.1403e-02   1.4091 0.1588095    
## zipcode98198  1.8875e-02  1.6859e-02   1.1196 0.2628986    
## zipcode98199  6.4795e-01  3.0746e-02  21.0739 < 2.2e-16 ***
## grade        -3.6242e-01  4.5317e-02  -7.9973 1.335e-15 ***
## view          6.4752e-02  2.3111e-03  28.0174 < 2.2e-16 ***
## log_lot       8.1323e-02  2.6966e-03  30.1582 < 2.2e-16 ***
## waterfront    4.4918e-01  2.3627e-02  19.0116 < 2.2e-16 ***
## condition     5.6138e-02  2.6413e-03  21.2535 < 2.2e-16 ***
## grade2       -1.2001e-02  1.6499e-03  -7.2737 3.617e-13 ***
## renovated     7.3183e-02  8.1907e-03   8.9349 < 2.2e-16 ***
## long         -5.3392e-01  6.1562e-02  -8.6729 < 2.2e-16 ***
## bathrooms     1.9606e-02  3.3169e-03   5.9111 3.450e-09 ***
## age2          4.2508e-05  2.1785e-06  19.5130 < 2.2e-16 ***
## age          -4.6927e-03  2.5075e-04 -18.7146 < 2.2e-16 ***
## lat           5.6138e-01  7.9901e-02   7.0260 2.189e-12 ***
## bedrooms     -8.4176e-03  2.2602e-03  -3.7244 0.0001963 ***
## floors       -9.0062e-03  3.4621e-03  -2.6014 0.0092919 ** 
## sqft2        -4.5748e-02  1.3014e-02  -3.5154 0.0004401 ***
## log_sqft      4.7627e-01  1.5691e-01   3.0354 0.0024053 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

📊 Selección de Variables: Forward, Backward y Stepwise

La selección de variables es una técnica clave en la construcción de modelos estadísticos y de machine learning. Se utiliza para identificar el subconjunto más relevante de variables explicativas (predictoras) que expliquen la variable dependiente sin sobreajustar ni incluir ruido innecesario.

🔁 1. Selección Forward (hacia adelante)

➕ Empieza sin variables, y las va añadiendo una por una.

Pasos:

  1. Comienza con ninguna variable en el modelo (solo intercepto).

  2. Para cada variable candidata que no esté en el modelo:

    • Ajusta un modelo incluyendo esa variable.
    • Evalúa el modelo (usualmente con p-valor, AIC, BIC o R² ajustado).
  3. Añade la variable que más mejora el modelo, siempre que cumpla un criterio (por ejemplo, p-valor < 0.05).

  4. Repite el proceso hasta que ninguna variable adicional cumpla el criterio.

Pros:

  • Simple y computacionalmente eficiente.
  • Útil cuando hay muchas variables.

Contras:

  • No considera combinaciones entre variables que podrían funcionar bien juntas.

🔁 2. Selección Backward (hacia atrás)

➖ Empieza con todas las variables y las va eliminando una a una.

Pasos:

  1. Comienza con un modelo que incluye todas las variables.
  2. Ajusta el modelo y observa los p-valores.
  3. Elimina la variable con el p-valor más alto (por encima del umbral, como 0.05).
  4. Repite el proceso hasta que todas las variables restantes sean significativas.

Pros:

  • Evalúa el modelo completo desde el principio.
  • Puede encontrar interacciones que el método forward ignoraría.

Contras:

  • Requiere que el modelo inicial con todas las variables sea ajustable (puede haber multicolinealidad).
  • Computacionalmente más costoso.

🔁 3. Selección Stepwise (combinada)

🔄 Combina pasos hacia adelante y hacia atrás en cada iteración.

Pasos:

  1. Comienza con un modelo vacío o parcial.

  2. En cada iteración:

    • Añade la mejor variable (como en forward).
    • Luego, elimina cualquier variable que ya no sea significativa (como en backward).
  3. Repite el proceso hasta que no se puedan añadir ni quitar más variables.

Pros:

  • Más flexible que forward o backward por separado.
  • Se adapta dinámicamente a los cambios en el modelo.

Contras:

  • Más complejo.
  • Puede sobreajustar si no se regula correctamente.

📌 Criterios comunes para decidir inclusión/exclusión

  • p-valor (significancia estadística, por ejemplo < 0.05).
  • AIC / BIC (criterios de información; menor es mejor).
  • R² ajustado (mayor es mejor, penaliza por complejidad).

🧠 Ejemplo de uso en R (resumen):

# Crear modelo base (solo intercepto) y modelo completo
model_base <- lm(y ~ 1, data = df)
model_full <- lm(y ~ x1 + x2 + x3 + ..., data = df)

# Selección Forward (hacia adelante)
step(model_base, scope = list(lower=model_base, upper=model_full), direction="forward")

# Selección Backward (hacia atrás)
step(model_full, direction="backward")

# Selección Stepwise (ambas direcciones)
step(model_base, scope = list(lower=model_base, upper=model_full), direction="both")