Modelos Lineales Generalizados

Modelos lineales

Author

Dante Conti, Sergi Ramirez, (c) IDEAI

Published

March 31, 2026

Modified

March 31, 2026

1 Introducción

Los modelos lineales constituyen una de las familias más importantes dentro de la estadística y del machine learning clásico. Aunque en ocasiones se presentan como herramientas “básicas”, en realidad son fundamentales por cuatro motivos:

  1. permiten explicar relaciones entre variables;
  2. ofrecen una base sólida para la inferencia estadística;
  3. sirven como punto de partida para modelos más complejos;
  4. son muy útiles en contextos de Data Mining, donde interesa tanto predecir como interpretar.

En este tutorial trabajaremos el caso de la regresión lineal, es decir, modelos donde una variable respuesta numérica se explica a partir de una o varias variables predictoras.

El objetivo no es solo aprender a ejecutar código, sino entender:

  • qué modelo se está ajustando;
  • qué significan sus parámetros;
  • cómo se interpreta la salida;
  • cuándo el modelo es razonable y cuándo no.

2 Objetivos de aprendizaje

Al finalizar este tema el estudiante debería ser capaz de:

  • entender la formulación matemática de un modelo lineal;
  • diferenciar entre regresión lineal simple y múltiple;
  • ajustar modelos lineales en R;
  • interpretar coeficientes, errores estándar, valores-p y \(R^2\);
  • detectar problemas de multicolinealidad, no linealidad y heterocedasticidad;
  • comparar modelos y evaluar capacidad predictiva;
  • incorporar variables cualitativas e interacciones;
  • utilizar modelos lineales dentro de un flujo de Data Mining.

3 ¿Qué es un modelo lineal?

Un modelo lineal relaciona una variable respuesta \(Y\) con un conjunto de predictores \(X_1, X_2, \dots, X_p\) mediante una expresión de la forma:

\[ Y_i = \beta_0 + \beta_1 X_{i1} + \beta_2 X_{i2} + \cdots + \beta_p X_{ip} + \varepsilon_i \]

donde:

  • \(\beta_0\) es el intercepto;
  • \(\beta_j\) es el efecto asociado al predictor \(X_j\);
  • \(\varepsilon_i\) es el error aleatorio de la observación \(i\).

La palabra lineal no significa necesariamente que la relación entre una variable y la respuesta sea “una recta” en sentido visual simple, sino que el modelo es lineal en los parámetros \(\beta\).

Por ejemplo, el siguiente modelo sigue siendo lineal:

\[ Y = \beta_0 + \beta_1 X + \beta_2 X^2 + \varepsilon \]

porque los parámetros aparecen linealmente.

4 Perspectiva de Data Mining

En Data Mining, un modelo lineal puede utilizarse con dos propósitos principales:

4.1 Propósito explicativo

Queremos entender qué variables influyen sobre una respuesta y en qué dirección:

  • si aumenta el precio, ¿bajan las ventas?
  • si aumenta la inversión publicitaria, ¿suben los ingresos?
  • ¿qué perfil de variables se asocia a una mayor puntuación?

4.2 Propósito predictivo

Queremos predecir el valor de una variable numérica para nuevos individuos.

Ejemplos:

  • estimar el precio de una vivienda;
  • predecir ventas;
  • anticipar consumo energético;
  • estimar nota final a partir de variables académicas.

Un punto importante: en contextos reales, un modelo lineal muchas veces no será el más preciso, pero sí uno de los más interpretables. Por eso suele ser el primer modelo de referencia o baseline.

5 Supuestos del modelo lineal

Para que la inferencia clásica del modelo lineal sea válida, se suelen asumir las siguientes condiciones:

  1. Linealidad: la relación media entre \(Y\) y los predictores está bien representada por la forma lineal.
  2. Independencia de los errores.
  3. Homoscedasticidad: la varianza del error es constante.
  4. Normalidad de los errores: importante sobre todo para contrastes e intervalos.
  5. Ausencia de multicolinealidad fuerte entre predictores.

En Data Mining, cuando el objetivo es puramente predictivo, a veces no exigimos todos los supuestos con el mismo rigor. Sin embargo, siguen siendo esenciales para interpretar el modelo correctamente.

6 Conjunto de datos de trabajo

En este documento se presentan el principal enfoque de los modelos linales aplicados sobre una base de datos sobre venta de edificios.

Nuestro objetivo inicial será modelizar Price (Valor monetario) como variable respuesta.

Mostrar código
# Cargamos las librerías necesarias.
# Se incluyen paquetes para:
# - manipulación y visualización
# - clustering particional y jerárquico
# - métricas de validación
# - representación gráfica de dendrogramas
list.of.packages <- c(
  "dplyr", "fpc", "reshape2", "tidyr", "ggplot2", "stats", 
  "cluster", "factoextra", "colorspace", "patchwork", 
  "tidyverse", "ggpubr", "NbClust", "HDclassif", "clustMixType", 
  "clusterSim", "pracma", "DataVisualizations", "entropy",
  "clevr", "dendextend", "ggdendro", "gridExtra", "idealista18",
  "GGally", "ggplot2", "caret")

new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[, "Package"])]
if (length(new.packages) > 0) {
  install.packages(new.packages)
}

invisible(lapply(list.of.packages, require, character.only = TRUE))
rm(list.of.packages, new.packages)
Mostrar código
# Cargamos la base de datos directamente desde GitHub
data(Barcelona_Sale)

BCN <- Barcelona_Sale |>
  dplyr::select(PRICE, CONSTRUCTEDAREA, ROOMNUMBER, BATHNUMBER, HASTERRACE, HASLIFT, HASAIRCONDITIONING, AMENITYID, HASPARKINGSPACE, ISPARKINGSPACEINCLUDEDINPRICE, PARKINGSPACEPRICE, HASNORTHORIENTATION, HASSOUTHORIENTATION, HASEASTORIENTATION, HASWESTORIENTATION, HASBOXROOM, HASWARDROBE, HASSWIMMINGPOOL, HASDOORMAN, HASGARDEN, ISDUPLEX, ISSTUDIO, ISINTOPFLOOR, BUILTTYPEID_1, BUILTTYPEID_2, BUILTTYPEID_3, DISTANCE_TO_CITY_CENTER, DISTANCE_TO_METRO, DISTANCE_TO_DIAGONAL, CADCONSTRUCTIONYEAR) |>
  data.frame()

Las variables a utilizar son las siguientes:

  • **PRICE: Precio del inmueble
  • CONSTRUCTEDAREA: metros cuadrados construidos (\(m^{2}\))
  • ROOMNUMBER: número de habitaciones
  • BATHNUMBER: número de baños
  • HASTERRACE: Indicador de si tiene (1) o no (0) terraza
  • HASLIFT: Indicador de si tiene (1) o no (0) ascensor
  • HASAIRCONDITIONING: Indicador de si tiene (1) o no (0) aire acondicionado
  • AMENITYID: Indica las comodidades incluidas (sin muebles ni utensilios de cocina (1), utensilios de cocina sin muebles (2), utensilios y muebles (3))
  • HASPARKINGSPACE: Si tiene disponible el parking (1) o no
  • ISPARKINGSPACEINCLUDEDINPRICE: Si está incluido en el precio el parking (1) o no (0)
  • PARKINGSPACEPRICE: Precio del parking
  • HASNORTHORIENTATION: Tiene orientación norte (1) o no (0)
  • HASSOUTHORIENTATION: Tiene orientación sud (1) o no (0)
  • HASEASTORIENTATION: Tiene orientación este (1) o no (0)
  • HASWESTORIENTATION: Tiene orientación oeste (1) o no (0)
  • HASBOXROOM: Si tiene trastero (1) o no (0)
  • HASWARDROBE: Si tiene guardaropa (1) o no (0)
  • HASSWIMMINGPOOL: Si tiene piscina (1) o no (0)
  • HASDOORMAN: Si existe portero (1) o no (0)
  • HASGARDEN: Tiene jardón (1) o no (0)
  • ISDUPLEX: Si es duplex (1) o no (0)
  • ISSTUDIO: Si es un estudio (1) o no (0)
  • ISINTOPFLOOR: Si es ático (1) o no (0)
  • BUILTTYPEID_1: Si es un piso de obra nueva (1) o no (0)
  • BUILTTYPEID_2: Si es un piso de segunda mano a restaurar (1) o no (0)
  • BUILTTYPEID_3: Si es un piso de segunda mano en buen estado (1) o no (0)
  • DISTANCE_TO_CITY_CENTER: Distancia en km al centro de la ciudad
  • DISTANCE_TO_METRO: Distancia a la entrada de metro más cercana en km
  • DISTANCE_TO_DIAGONAL: Distancia en km a la avenida diagonal
  • CADCONSTRUCTIONYEAR: Año de construcción del edificio según el catastro

6.0.1 Interpretación

Cada fila representa un comprador de la tienda online y cada columna una variable. La variable Review.Rating será nuestra respuesta.

6.1 Estructura del dataset

Mostrar código
str(dades)
'data.frame':   61486 obs. of  30 variables:
 $ PRICE                        : num  323000 217000 114000 378000 434000 298000 228000 888000 291000 786000 ...
 $ CONSTRUCTEDAREA              : int  84 84 81 79 111 93 58 152 80 150 ...
 $ ROOMNUMBER                   : int  4 3 2 2 4 2 3 4 3 3 ...
 $ BATHNUMBER                   : int  1 2 1 1 2 2 1 2 2 2 ...
 $ HASTERRACE                   : chr  "sí" "no" "no" "no" ...
 $ HASLIFT                      : chr  "sí" "sí" "sí" "sí" ...
 $ HASAIRCONDITIONING           : chr  "sí" "sí" "sí" "no" ...
 $ AMENITYID                    : chr  "amueblado" "amueblado" "amueblado" "amueblado" ...
 $ HASPARKINGSPACE              : chr  "no" "no" "no" "no" ...
 $ ISPARKINGSPACEINCLUDEDINPRICE: chr  "no" "no" "no" "no" ...
 $ PARKINGSPACEPRICE            : num  1 1 1 1 1 1 1 1 1 1 ...
 $ HASNORTHORIENTATION          : chr  "no" "no" "no" "no" ...
 $ HASSOUTHORIENTATION          : chr  "no" "no" "no" "no" ...
 $ HASEASTORIENTATION           : chr  "no" "no" "no" "no" ...
 $ HASWESTORIENTATION           : chr  "no" "no" "no" "no" ...
 $ HASBOXROOM                   : chr  "no" "no" "sí" "no" ...
 $ HASWARDROBE                  : chr  "no" "no" "no" "no" ...
 $ HASSWIMMINGPOOL              : chr  "no" "no" "no" "no" ...
 $ HASDOORMAN                   : chr  "no" "no" "no" "no" ...
 $ HASGARDEN                    : chr  "no" "sí" "no" "no" ...
 $ ISDUPLEX                     : chr  "no" "sí" "no" "no" ...
 $ ISSTUDIO                     : chr  "no" "no" "no" "no" ...
 $ ISINTOPFLOOR                 : chr  "no" "no" "no" "no" ...
 $ BUILTTYPEID_1                : chr  "no" "no" "no" "no" ...
 $ BUILTTYPEID_2                : chr  "no" "no" "sí" "no" ...
 $ BUILTTYPEID_3                : chr  "sí" "sí" "no" "sí" ...
 $ DISTANCE_TO_CITY_CENTER      : num  1.88 2.12 4.13 2.24 2.33 ...
 $ DISTANCE_TO_METRO            : num  0.354 0.284 0.262 0.159 0.102 ...
 $ DISTANCE_TO_DIAGONAL         : num  1.475 1.194 2.505 0.796 1.2 ...
 $ CADCONSTRUCTIONYEAR          : int  1972 1930 1940 2016 1970 1997 1930 1940 1966 1940 ...
Mostrar código
summary(dades)
     PRICE         CONSTRUCTEDAREA    ROOMNUMBER       BATHNUMBER    
 Min.   :  37000   Min.   : 21.00   Min.   : 0.000   Min.   : 0.000  
 1st Qu.: 230000   1st Qu.: 66.00   1st Qu.: 2.000   1st Qu.: 1.000  
 Median : 325000   Median : 82.00   Median : 3.000   Median : 1.000  
 Mean   : 395771   Mean   : 95.46   Mean   : 2.864   Mean   : 1.519  
 3rd Qu.: 462000   3rd Qu.:108.00   3rd Qu.: 3.000   3rd Qu.: 2.000  
 Max.   :4866000   Max.   :959.00   Max.   :40.000   Max.   :12.000  
  HASTERRACE          HASLIFT          HASAIRCONDITIONING  AMENITYID        
 Length:61486       Length:61486       Length:61486       Length:61486      
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
 HASPARKINGSPACE    ISPARKINGSPACEINCLUDEDINPRICE PARKINGSPACEPRICE 
 Length:61486       Length:61486                  Min.   :     1.0  
 Class :character   Class :character              1st Qu.:     1.0  
 Mode  :character   Mode  :character              Median :     1.0  
                                                  Mean   :   620.4  
                                                  3rd Qu.:     1.0  
                                                  Max.   :425001.0  
 HASNORTHORIENTATION HASSOUTHORIENTATION HASEASTORIENTATION HASWESTORIENTATION
 Length:61486        Length:61486        Length:61486       Length:61486      
 Class :character    Class :character    Class :character   Class :character  
 Mode  :character    Mode  :character    Mode  :character   Mode  :character  
                                                                              
                                                                              
                                                                              
  HASBOXROOM        HASWARDROBE        HASSWIMMINGPOOL     HASDOORMAN       
 Length:61486       Length:61486       Length:61486       Length:61486      
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
  HASGARDEN           ISDUPLEX           ISSTUDIO         ISINTOPFLOOR      
 Length:61486       Length:61486       Length:61486       Length:61486      
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
 BUILTTYPEID_1      BUILTTYPEID_2      BUILTTYPEID_3     
 Length:61486       Length:61486       Length:61486      
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
 DISTANCE_TO_CITY_CENTER DISTANCE_TO_METRO   DISTANCE_TO_DIAGONAL
 Min.   :0.05457         Min.   :0.0007362   Min.   :0.002235    
 1st Qu.:1.56297         1st Qu.:0.1551987   1st Qu.:0.900254    
 Median :2.61598         Median :0.2463591   Median :1.646425    
 Mean   :2.80364         Mean   :0.2656222   Mean   :1.769907    
 3rd Qu.:3.77766         3rd Qu.:0.3462516   3rd Qu.:2.383208    
 Max.   :9.05757         Max.   :4.0996294   Max.   :7.244329    
 CADCONSTRUCTIONYEAR
 Min.   :1588       
 1st Qu.:1932       
 Median :1963       
 Mean   :1952       
 3rd Qu.:1974       
 Max.   :2018       

6.1.1 Interpretación

  • str() nos muestra tipos de variables.
  • summary() proporciona un resumen descriptivo inicial.
  • Antes de modelizar, debemos entender rangos, escalas y posibles outliers.

6.2 Conversión de variables categóricas

Este paso es crucial. Si una variable categórica se deja como numérica, el modelo podría interpretar una relación cuantitativa inexistente. En Data Mining, una mala codificación de variables suele producir interpretaciones erróneas.

Mostrar código
tipos <- sapply(dades, class)
varCat <- names(tipos)[which(tipos %in% c("character", "factor"))] 
varNum <- names(tipos)[which(tipos %in% c("integer", "numeric"))] 
for (var in varCat) {
  dades[, var] <- as.factor(as.character(dades[, var]))
}

7 Análisis exploratorio previo

Antes de ajustar un modelo, conviene explorar relaciones entre variables.

7.1 Matriz de dispersión

Mostrar código
GGally::ggpairs(dades, columns = varNum)

7.1.1 Interpretación

La matriz de dispersión permite detectar:

  • relaciones aproximadamente lineales;
  • asociaciones fuertes entre predictores;
  • posibles observaciones atípicas;
  • estructuras no lineales.

7.2 Correlaciones entre variables numéricas

Mostrar código
cor(dades[, varNum])
                              PRICE CONSTRUCTEDAREA  ROOMNUMBER  BATHNUMBER
PRICE                    1.00000000      0.87760541  0.49353066  0.71481973
CONSTRUCTEDAREA          0.87760541      1.00000000  0.58335263  0.69995790
ROOMNUMBER               0.49353066      0.58335263  1.00000000  0.51527930
BATHNUMBER               0.71481973      0.69995790  0.51527930  1.00000000
PARKINGSPACEPRICE        0.05236988      0.04559892  0.04402086  0.06768343
DISTANCE_TO_CITY_CENTER -0.21523770     -0.07828199  0.05002041 -0.10958942
DISTANCE_TO_METRO        0.06235053      0.04867803  0.01448854  0.05330928
DISTANCE_TO_DIAGONAL    -0.39766441     -0.25309989 -0.14339508 -0.27109797
CADCONSTRUCTIONYEAR      0.04651750      0.08232589  0.16495746  0.11458356
                        PARKINGSPACEPRICE DISTANCE_TO_CITY_CENTER
PRICE                          0.05236988             -0.21523770
CONSTRUCTEDAREA                0.04559892             -0.07828199
ROOMNUMBER                     0.04402086              0.05002041
BATHNUMBER                     0.06768343             -0.10958942
PARKINGSPACEPRICE              1.00000000              0.02240448
DISTANCE_TO_CITY_CENTER        0.02240448              1.00000000
DISTANCE_TO_METRO              0.01120724              0.12170284
DISTANCE_TO_DIAGONAL          -0.01819045              0.64443761
CADCONSTRUCTIONYEAR            0.08829998              0.45708297
                        DISTANCE_TO_METRO DISTANCE_TO_DIAGONAL
PRICE                          0.06235053          -0.39766441
CONSTRUCTEDAREA                0.04867803          -0.25309989
ROOMNUMBER                     0.01448854          -0.14339508
BATHNUMBER                     0.05330928          -0.27109797
PARKINGSPACEPRICE              0.01120724          -0.01819045
DISTANCE_TO_CITY_CENTER        0.12170284           0.64443761
DISTANCE_TO_METRO              1.00000000           0.05254929
DISTANCE_TO_DIAGONAL           0.05254929           1.00000000
CADCONSTRUCTIONYEAR            0.09854106           0.08579109
                        CADCONSTRUCTIONYEAR
PRICE                            0.04651750
CONSTRUCTEDAREA                  0.08232589
ROOMNUMBER                       0.16495746
BATHNUMBER                       0.11458356
PARKINGSPACEPRICE                0.08829998
DISTANCE_TO_CITY_CENTER          0.45708297
DISTANCE_TO_METRO                0.09854106
DISTANCE_TO_DIAGONAL             0.08579109
CADCONSTRUCTIONYEAR              1.00000000

7.2.1 Interpretación

Si dos predictores están muy correlacionados entre sí, puede aparecer multicolinealidad. Esto no siempre empeora la predicción, pero sí puede dificultar mucho la interpretación de coeficientes individuales.

7.3 Relación entre PRICE y wt

7.3.1 Interpretación

Visualmente parece existir una relación positiva: a mayor precio del inmueble, mayor número de metros cuadrados (CONSTRUCTEDAREA). Esto hace de CONSTRUCTEDAREA un buen candidato para un primer modelo simple.

8 Regresión lineal simple

8.1 Ajuste del modelo

Comenzamos con un único predictor:

\[ mpg_i = \beta_0 + \beta_1 CONSTRUCTEDAREA_i + \varepsilon_i \]

Mostrar código
modelo_simple <- lm(PRICE ~ CONSTRUCTEDAREA, data = dades)
summary(modelo_simple)

Call:
lm(formula = PRICE ~ CONSTRUCTEDAREA, data = dades)

Residuals:
     Min       1Q   Median       3Q      Max 
-2523454   -70311    -4159    64080  1177062 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)     -52857.29    1128.29  -46.85   <2e-16 ***
CONSTRUCTEDAREA   4699.63      10.35  453.94   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 135000 on 61484 degrees of freedom
Multiple R-squared:  0.7702,    Adjusted R-squared:  0.7702 
F-statistic: 2.061e+05 on 1 and 61484 DF,  p-value: < 2.2e-16

8.1.1 Interpretación de la salida

La función summary() ofrece los elementos clave:

  • Estimate: estimación de los coeficientes;
  • Std. Error: error estándar de cada coeficiente;
  • t value y Pr(>|t|): contraste individual de significación;
  • Residual standard error: dispersión típica de los errores;
  • Multiple R-squared: proporción de variabilidad explicada;
  • F-statistic: contraste global del modelo.

8.2 Ecuación estimada

Mostrar código
coef(modelo_simple)
    (Intercept) CONSTRUCTEDAREA 
     -52857.291        4699.629 

8.2.1 Interpretación

Si obtenemos una ecuación estimada del tipo:

\[ \widehat{PRICE} = -52.857,29 - 4.699,63\,CONSTRUCTEDAREA \]

la interpretación es:

  • el intercepto representa el valor esperado de mpg cuando wt = 0;
  • la pendiente indica cuánto cambia mpg por cada unidad adicional de peso.

La pendiente del modelo es 4.699,63€, por lo tanto por cada 1\(m^2\) adicional, el precio aumenta en 4.699,63€.

8.3 Recta ajustada sobre el gráfico

Mostrar código
grafico +
  geom_smooth(method = "lm")

8.3.1 Interpretación

La recta representa la media estimada de PRICE para cada valor de CONSTRUCTEDAREA. Los puntos alejados de la recta presentan residuos grandes.

9 Residuos: qué son y por qué importan

El residuo de una observación es:

\[ e_i = y_i - \hat{y}_i \]

Es decir, la diferencia entre el valor observado y el predicho.

9.1 Extracción de valores ajustados y residuos

Mostrar código
head(data.frame(
  observado = dades$PRICE,
  ajustado = fitted(modelo_simple),
  residuo = residuals(modelo_simple)
))

9.1.1 Interpretación

  • Residuo positivo: el modelo predijo menos de lo observado.
  • Residuo negativo: el modelo predijo más de lo observado.
  • Analizar residuos permite detectar patrones problemáticos.

9.2 Gráficos diagnósticos básicos

Aunque el modelo sea significativo se debe validar, someter a contraste los supuestos estadísticos que subyacen al modelo.

Para hacerlo, es necesario los residuos del modelo y el cálculo de la diferencia entre los valores observados y los estimados:

\[ e_i = y_i - \hat{y}_i = y_{i} - (\hat{\beta}_{0} + \hat{\beta}_{1}x_{1i} + ... + \hat{\beta}_{p}x_{pi}), i = 1, ..., N \]

Lo anterior carece de validez si no se satisfacen las hipótesis del modelo siguientes:

  • Los residuos han de tener varianza constante (homocedasticidad)

\[ V(e) = \sigma^{2} = 0 \]

  • Los residuos han de seguir la distribución de probabilidad normal.

  • Las observaciones tienen que ser independientes.

  • La relación entre la variable respuesta y las explicativas se suponen lineal.

  • Las variables explicativas son linealmente independientes: ninguna puede ser explicada como combinación lineal de las otras. En caso contrario, se tendría el conocido problema de la multicolinealidad y debería quitarse del modelo la variable explicada por el resto.

A continuación se realiza un análisis de residuos.

Mostrar código
library("ggfortify")
autoplot(modelo_simple) +
  theme_minimal()

9.2.1 Interpretación

Los cuatro gráficos diagnósticos clásicos permiten comprobar:

  1. Residuals vs Fitted: linealidad y homoscedasticidad.
  • Nube aleatoria horizontal → ✔ Linealidad OK + homocedasticidad
  • Forma curva (U, ∩, S) → ❌ No linealidad
  • Forma de embudo (se abre o cierra) → ❌ Heterocedasticidad
  • Grupos/segmentos → ❌ Variables omitidas / modelo mal especificado

Para poderlo identificar, se ha de mirar que la linea azul sea una linia recta

También podemos realizar una prueba de hipótesis para detectar si existe o no homocedasticidad. En este caso, el test se trata del de Breusch-Pagan.

Hipótesis

  • \(H_0\): La varianza de los residuos es constante (Homocedasticidad)
  • \(H_1\): La varianza de los residuos depende de las variables explicativas (Heterocedasticidad)

Decisión

  • Si p-value > 0.05 \(\rightarrow\) No rechazamos \(H_0\) \(\rightarrow\) Los resiudos pueden considerarse homocedasticos.

  • Si p-value < 0.05 \(\rightarrow\) Rechazamos \(H_0\) \(\rightarrow\) Los resiudos pueden considerarse heterocedasticos.

Mostrar código
lmtest::bgtest(modelo_simple)

    Breusch-Godfrey test for serial correlation of order up to 1

data:  modelo_simple
LM test = 4533.1, df = 1, p-value < 2.2e-16

Viendo el modelo, podemos decir que nuestro modelo tiene problemas de heterocedasticidad.

  1. Normal Q-Q: aproximación a normalidad de residuos.
  • Puntos sobre la recta → ✔ Normalidad OK
  • Desviación en extremos (colas) → ❌ Outliers / colas pesadas
  • Forma en S → ❌ No normalidad
  • Muchos puntos alejados de la línea → ❌ Mala distribución de residuos

También se puede realizar contrastes de hipótesis cómo el test de normalidad de Shapiro-Wilk para muestras de máximo 5000 observaciones (\(n = 5000\)).

Mostrar código
shapiro.test(sample(modelo_simple$residuals, 5000))

    Shapiro-Wilk normality test

data:  sample(modelo_simple$residuals, 5000)
W = 0.9092, p-value < 2.2e-16

Cómo el p-valor es inferior a 0.05 tenemos evidéncias para no aceptar la hipótesis nula, nuestros residuos NO se distribuyen de manera normal.

  1. Scale-Location: varianza constante.
  • Línea horizontal + dispersión uniforme → ✔ Homocedasticidad
  • Tendencia creciente (↑) → ❌ Varianza aumenta (heterocedasticidad)
  • Tendencia decreciente (↓) → ❌ Varianza disminuye
  • Forma de embudo → ❌ Heterocedasticidad
  1. Residuals vs Leverage: observaciones influyentes.
  • Todos los puntos dentro de Cook → ✔ Sin influencia grave
  • Punto con alto leverage (muy a la derecha) → ⚠ Potencialmente problemático
  • Alto leverage + residuo grande → ❌ Observación influyente
  • Puntos fuera de líneas de Cook → ❌ Muy influyentes (revisar/eliminar)

En docencia es importante remarcar que estos gráficos no se leen como “verdadero/falso”, sino como señales para juzgar si el modelo es razonable.

10 Bondad de ajuste

10.1 Suma de cuadrados

La variabilidad total se descompone como:

\[ SST = SSR + SSE \]

donde:

  • \(SST\): suma total de cuadrados;
  • \(SSR\): variabilidad explicada por el modelo;
  • \(SSE\): variabilidad residual.

10.2 Coeficiente de determinación \(R^2\)

\[ R^2 = 1 - \frac{SSE}{SST} \]

Representa la proporción de variabilidad de la respuesta explicada por el modelo.

Mostrar código
summary(modelo_simple)$r.squared
[1] 0.7701913
Mostrar código
summary(modelo_simple)$adj.r.squared
[1] 0.7701875

10.2.1 Interpretación

  • Un \(R^2\) alto indica mejor ajuste dentro de la muestra.
  • No implica causalidad.
  • No garantiza buena predicción fuera de muestra.
  • En modelos múltiples, conviene mirar también el \(R^2\) ajustado, que penaliza por número de variables.

11 Inferencia sobre coeficientes

Cada coeficiente se suele contrastar mediante:

\[ H_0: \beta_j = 0 \quad \text{frente a} \quad H_1: \beta_j \neq 0 \]

Mostrar código
confint(modelo_simple)
                     2.5 %    97.5 %
(Intercept)     -55068.737 -50645.84
CONSTRUCTEDAREA   4679.337   4719.92

11.0.1 Interpretación

Los intervalos de confianza aportan más información que el simple valor-p:

  • si el intervalo de un coeficiente no contiene el 0, hay evidencia de efecto;
  • además, el intervalo permite valorar la magnitud plausible del efecto.

12 Predicción con el modelo simple

12.1 Predicción puntual

Mostrar código
nuevo_inmueble <- data.frame(CONSTRUCTEDAREA = 188)
predict(modelo_simple, newdata = nuevo_inmueble)
       1 
830672.9 

12.1.1 Interpretación

El modelo proporciona el valor esperado de PRICE para un inmueble con 188 \(m^{2}\).

12.2 Intervalo de confianza e intervalo de predicción

Mostrar código
predict(modelo_simple, newdata = nuevo_inmueble, interval = "confidence")
       fit      lwr      upr
1 830672.9 828513.1 832832.6
Mostrar código
predict(modelo_simple, newdata = nuevo_inmueble, interval = "prediction")
       fit      lwr     upr
1 830672.9 566114.9 1095231

12.2.1 Interpretación

  • El intervalo de confianza se refiere a la media esperada.
  • El intervalo de predicción se refiere a una nueva observación individual.

El segundo es más ancho porque incorpora la variabilidad individual adicional.

13 Regresión lineal múltiple

En la práctica rara vez basta con una sola variable. Extendemos el modelo a varios predictores:

\[ mpg_i = \beta_0 + \beta_1 wt_i + \beta_2 hp_i + \beta_3 qsec_i + \varepsilon_i \]

13.1 Ajuste del modelo múltiple

Mostrar código
modelo_multiple <- lm(PRICE ~ CONSTRUCTEDAREA + ROOMNUMBER + BATHNUMBER, data = dades)
summary(modelo_multiple)

Call:
lm(formula = PRICE ~ CONSTRUCTEDAREA + ROOMNUMBER + BATHNUMBER, 
    data = dades)

Residuals:
     Min       1Q   Median       3Q      Max 
-2296963   -64592    -1537    59581  1341081 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)     -78293.66    1496.09  -52.33   <2e-16 ***
CONSTRUCTEDAREA   4105.76      14.79  277.61   <2e-16 ***
ROOMNUMBER      -15409.58     572.13  -26.93   <2e-16 ***
BATHNUMBER       83137.59    1035.75   80.27   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 128300 on 61482 degrees of freedom
Multiple R-squared:  0.7925,    Adjusted R-squared:  0.7924 
F-statistic: 7.825e+04 on 3 and 61482 DF,  p-value: < 2.2e-16

13.1.1 Interpretación

Ahora cada coeficiente se interpreta manteniendo constantes las demás variables.

Por ejemplo, el coeficiente de PRICE representa el cambio esperado en CONSTRUCTEDAREA por unidad de peso a igualdad de número de habitaciones (ROOMNUMBER) y número de baños (BATHNUMBER).

Este matiz es absolutamente esencial en regresión múltiple.

13.2 11.2 Comparación entre modelo simple y múltiple

Mostrar código
summary(modelo_simple)$r.squared
[1] 0.7701913
Mostrar código
summary(modelo_multiple)$r.squared
[1] 0.7924552
Mostrar código
summary(modelo_multiple)$adj.r.squared
[1] 0.792445

13.2.1 Interpretación

Al añadir variables, \(R^2\) no disminuye. Por eso conviene observar también el \(R^2\) ajustado y, si el objetivo es predicción, evaluar el rendimiento fuera de muestra.

14 Interpretación de coeficientes en presencia de varias variables

Supongamos un modelo:

\[ \widehat{Y} = \hat\beta_0 + \hat\beta_1 X_1 + \hat\beta_2 X_2 \]

La interpretación correcta de \(\hat\beta_1\) no es “el efecto aislado de \(X_1\) en cualquier circunstancia”, sino el cambio esperado en la respuesta cuando \(X_1\) aumenta una unidad y \(X_2\) se mantiene constante.

Esto explica por qué un coeficiente puede cambiar mucho al añadir o quitar variables: el contexto del modelo también cambia.

15 Variables cualitativas en modelos lineales

Los modelos lineales también admiten variables categóricas mediante codificación dummy.

15.1 Modelo con si dispone terraza o no (HASTERRACE)

Mostrar código
modelo_factor <- lm(PRICE ~ CONSTRUCTEDAREA + ROOMNUMBER + BATHNUMBER + HASTERRACE, data = dades)
summary(modelo_factor)

Call:
lm(formula = PRICE ~ CONSTRUCTEDAREA + ROOMNUMBER + BATHNUMBER + 
    HASTERRACE, data = dades)

Residuals:
     Min       1Q   Median       3Q      Max 
-2263504   -64251     -917    59494  1344100 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)     -80579.07    1498.06  -53.79   <2e-16 ***
CONSTRUCTEDAREA   4071.15      14.88  273.51   <2e-16 ***
ROOMNUMBER      -15012.59     571.16  -26.28   <2e-16 ***
BATHNUMBER       81749.32    1036.21   78.89   <2e-16 ***
HASTERRACEsí     19885.16    1134.37   17.53   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 128000 on 61481 degrees of freedom
Multiple R-squared:  0.7935,    Adjusted R-squared:  0.7935 
F-statistic: 5.906e+04 on 4 and 61481 DF,  p-value: < 2.2e-16

15.1.1 Interpretación

Al tratar HASTERRACE como factor, R crea automáticamente una categoría de referencia.

Si la referencia es no, entonces el coeficiente asociado a indica cuánto cambia el PRICE esperado para inmuebles con terraza respecto a sin terraza, manteniendo constante el peso.

15.2 Medias ajustadas por grupo

Mostrar código
aggregate(PRICE ~ HASTERRACE, data = dades, mean)

15.2.1 Interpretación

Comparar medias por grupo ayuda a contextualizar el efecto categórico, aunque el modelo lineal ajusta esa diferencia junto a otras variables incluidas.

16 Interacciones

A veces el efecto de una variable depende del nivel de otra. Esto se representa con una interacción.

16.1 Ajuste de un modelo con interacción

Mostrar código
modelo_interaccion <- lm(PRICE ~ CONSTRUCTEDAREA * HASTERRACE + ROOMNUMBER + BATHNUMBER, data = dades)
summary(modelo_interaccion)

Call:
lm(formula = PRICE ~ CONSTRUCTEDAREA * HASTERRACE + ROOMNUMBER + 
    BATHNUMBER, data = dades)

Residuals:
     Min       1Q   Median       3Q      Max 
-2271617   -64282    -1112    59385  1315334 

Coefficients:
                              Estimate Std. Error t value Pr(>|t|)    
(Intercept)                  -74958.34    1720.74 -43.562  < 2e-16 ***
CONSTRUCTEDAREA                4002.81      18.10 221.157  < 2e-16 ***
HASTERRACEsí                   6488.62    2316.55   2.801   0.0051 ** 
ROOMNUMBER                   -14751.96     572.31 -25.776  < 2e-16 ***
BATHNUMBER                    81447.98    1036.85  78.554  < 2e-16 ***
CONSTRUCTEDAREA:HASTERRACEsí    134.46      20.27   6.632 3.34e-11 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 127900 on 61480 degrees of freedom
Multiple R-squared:  0.7936,    Adjusted R-squared:  0.7936 
F-statistic: 4.729e+04 on 5 and 61480 DF,  p-value: < 2.2e-16

16.1.1 Interpretación

El término CONSTRUCTEDAREA * HASTERRACE equivale a incluir:

  • efecto principal de CONSTRUCTEDAREA;
  • efecto principal de HASTERRACE;
  • interacción CONSTRUCTEDAREA:HASTERRACE.

Si la interacción es relevante, significa que la pendiente de CONSTRUCTEDAREA no es la misma para inmuebles con terraza que sin ella.

17 Visualización de la interacción

Mostrar código
plot(PRICE ~ CONSTRUCTEDAREA, data = dades,
     col = c("red", "blue")[dades$HASTERRACE],
     pch = 19,
     xlab = "metros cuadrados",
     ylab = "Precio",
     main = "Interacción entre metros cuadrados y disponibilidad de terraza")
legend("topright", legend = levels(dades$HASTERRACE), col = c("red", "blue"), pch = 19)

abline(lm(PRICE ~ CONSTRUCTEDAREA, data = dades, subset = HASTERRACE == "no"), col = "red", lwd = 2)
abline(lm(PRICE ~ CONSTRUCTEDAREA, data = dades, subset = HASTERRACE == "sí"), col = "blue", lwd = 2)

17.0.1 Interpretación

Si las rectas tienen pendientes claramente distintas, la interacción es plausible. En términos sustantivos: el impacto de los metros cuadrados sobre el precio depende de si dispone o no terrazas.

18 Multicolinealidad

La multicolinealidad aparece cuando varios predictores aportan información redundante.

18.1 Detección mediante correlaciones

Mostrar código
cor(dades[, varNum])
                              PRICE CONSTRUCTEDAREA  ROOMNUMBER  BATHNUMBER
PRICE                    1.00000000      0.87760541  0.49353066  0.71481973
CONSTRUCTEDAREA          0.87760541      1.00000000  0.58335263  0.69995790
ROOMNUMBER               0.49353066      0.58335263  1.00000000  0.51527930
BATHNUMBER               0.71481973      0.69995790  0.51527930  1.00000000
PARKINGSPACEPRICE        0.05236988      0.04559892  0.04402086  0.06768343
DISTANCE_TO_CITY_CENTER -0.21523770     -0.07828199  0.05002041 -0.10958942
DISTANCE_TO_METRO        0.06235053      0.04867803  0.01448854  0.05330928
DISTANCE_TO_DIAGONAL    -0.39766441     -0.25309989 -0.14339508 -0.27109797
CADCONSTRUCTIONYEAR      0.04651750      0.08232589  0.16495746  0.11458356
                        PARKINGSPACEPRICE DISTANCE_TO_CITY_CENTER
PRICE                          0.05236988             -0.21523770
CONSTRUCTEDAREA                0.04559892             -0.07828199
ROOMNUMBER                     0.04402086              0.05002041
BATHNUMBER                     0.06768343             -0.10958942
PARKINGSPACEPRICE              1.00000000              0.02240448
DISTANCE_TO_CITY_CENTER        0.02240448              1.00000000
DISTANCE_TO_METRO              0.01120724              0.12170284
DISTANCE_TO_DIAGONAL          -0.01819045              0.64443761
CADCONSTRUCTIONYEAR            0.08829998              0.45708297
                        DISTANCE_TO_METRO DISTANCE_TO_DIAGONAL
PRICE                          0.06235053          -0.39766441
CONSTRUCTEDAREA                0.04867803          -0.25309989
ROOMNUMBER                     0.01448854          -0.14339508
BATHNUMBER                     0.05330928          -0.27109797
PARKINGSPACEPRICE              0.01120724          -0.01819045
DISTANCE_TO_CITY_CENTER        0.12170284           0.64443761
DISTANCE_TO_METRO              1.00000000           0.05254929
DISTANCE_TO_DIAGONAL           0.05254929           1.00000000
CADCONSTRUCTIONYEAR            0.09854106           0.08579109
                        CADCONSTRUCTIONYEAR
PRICE                            0.04651750
CONSTRUCTEDAREA                  0.08232589
ROOMNUMBER                       0.16495746
BATHNUMBER                       0.11458356
PARKINGSPACEPRICE                0.08829998
DISTANCE_TO_CITY_CENTER          0.45708297
DISTANCE_TO_METRO                0.09854106
DISTANCE_TO_DIAGONAL             0.08579109
CADCONSTRUCTIONYEAR              1.00000000

18.2 Factor de inflación de la varianza (VIF)

Este estadístico indica el incremenot de la varianza estimada del coeficiente de regresión de una determinada variable explicatiava como consecuencia de la colinealidad con las demás.

Mostrar código
if (!require(car)) install.packages("car")
library(car)

car::vif(modelo_multiple)
CONSTRUCTEDAREA      ROOMNUMBER      BATHNUMBER 
       2.259641        1.569190        2.029558 

18.2.1 Interpretación

Un VIF alto indica que un coeficiente está siendo estimado con poca estabilidad por culpa de la colinealidad. Regla práctica habitual:

  • VIF cercano a 1: sin problema importante;
  • VIF entre 5 y 10: posible preocupación;
  • VIF superior a 10: problema serio.

En Data Mining, la multicolinealidad no siempre destruye la predicción, pero sí puede volver poco fiables las interpretaciones individuales.

19 Selección de variables

En contextos con muchos predictores, interesa decidir qué variables dejar en el modelo.

19.1 Modelo completo

Mostrar código
modelo_completo <- lm(PRICE ~ ., data = dades)
summary(modelo_completo)

Call:
lm(formula = PRICE ~ ., data = dades)

Residuals:
     Min       1Q   Median       3Q      Max 
-2076174   -51527    -1670    48687  1404864 

Coefficients: (2 not defined because of singularities)
                                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)                      4.733e+05  2.970e+04  15.934  < 2e-16 ***
CONSTRUCTEDAREA                  3.856e+03  1.366e+01 282.191  < 2e-16 ***
ROOMNUMBER                      -1.175e+04  5.779e+02 -20.327  < 2e-16 ***
BATHNUMBER                       5.650e+04  9.647e+02  58.563  < 2e-16 ***
HASTERRACEsí                     1.156e+04  1.046e+03  11.044  < 2e-16 ***
HASLIFTsí                        3.249e+04  1.199e+03  27.096  < 2e-16 ***
HASAIRCONDITIONINGsí             1.746e+04  1.020e+03  17.120  < 2e-16 ***
AMENITYIDno amueblado            1.281e+04  2.309e+03   5.549 2.89e-08 ***
AMENITYIDobjetos cocina          1.780e+04  2.019e+03   8.818  < 2e-16 ***
HASPARKINGSPACEsí                6.372e+04  1.908e+03  33.404  < 2e-16 ***
ISPARKINGSPACEINCLUDEDINPRICEsí         NA         NA      NA       NA    
PARKINGSPACEPRICE                1.983e-01  9.522e-02   2.083  0.03730 *  
HASNORTHORIENTATIONsí           -5.633e+03  1.388e+03  -4.059 4.94e-05 ***
HASSOUTHORIENTATIONsí           -3.298e+03  1.026e+03  -3.214  0.00131 ** 
HASEASTORIENTATIONsí            -2.087e+03  1.102e+03  -1.895  0.05814 .  
HASWESTORIENTATIONsí            -1.439e+03  1.283e+03  -1.121  0.26209    
HASBOXROOMsí                     4.515e+03  1.514e+03   2.982  0.00287 ** 
HASWARDROBEsí                    2.769e+03  1.101e+03   2.515  0.01190 *  
HASSWIMMINGPOOLsí                6.323e+04  3.203e+03  19.740  < 2e-16 ***
HASDOORMANsí                     4.395e+04  1.785e+03  24.626  < 2e-16 ***
HASGARDENsí                     -7.232e+03  2.764e+03  -2.617  0.00888 ** 
ISDUPLEXsí                      -5.365e+04  2.884e+03 -18.600  < 2e-16 ***
ISSTUDIOsí                      -5.769e+04  3.789e+03 -15.228  < 2e-16 ***
ISINTOPFLOORsí                   2.025e+04  3.299e+03   6.138 8.39e-10 ***
BUILTTYPEID_1sí                  3.754e+04  4.331e+03   8.667  < 2e-16 ***
BUILTTYPEID_2sí                 -2.945e+04  1.293e+03 -22.780  < 2e-16 ***
BUILTTYPEID_3sí                         NA         NA      NA       NA    
DISTANCE_TO_CITY_CENTER         -1.109e+04  4.580e+02 -24.213  < 2e-16 ***
DISTANCE_TO_METRO                4.596e+04  2.842e+03  16.174  < 2e-16 ***
DISTANCE_TO_DIAGONAL            -2.809e+04  5.833e+02 -48.164  < 2e-16 ***
CADCONSTRUCTIONYEAR             -2.405e+02  1.556e+01 -15.454  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 113500 on 61457 degrees of freedom
Multiple R-squared:  0.8374,    Adjusted R-squared:  0.8374 
F-statistic: 1.131e+04 on 28 and 61457 DF,  p-value: < 2.2e-16

19.2 Selección paso a paso por AIC

Mostrar código
modelo_step <- step(modelo_completo, trace = 1)
Start:  AIC=1431415
PRICE ~ CONSTRUCTEDAREA + ROOMNUMBER + BATHNUMBER + HASTERRACE + 
    HASLIFT + HASAIRCONDITIONING + AMENITYID + HASPARKINGSPACE + 
    ISPARKINGSPACEINCLUDEDINPRICE + PARKINGSPACEPRICE + HASNORTHORIENTATION + 
    HASSOUTHORIENTATION + HASEASTORIENTATION + HASWESTORIENTATION + 
    HASBOXROOM + HASWARDROBE + HASSWIMMINGPOOL + HASDOORMAN + 
    HASGARDEN + ISDUPLEX + ISSTUDIO + ISINTOPFLOOR + BUILTTYPEID_1 + 
    BUILTTYPEID_2 + BUILTTYPEID_3 + DISTANCE_TO_CITY_CENTER + 
    DISTANCE_TO_METRO + DISTANCE_TO_DIAGONAL + CADCONSTRUCTIONYEAR


Step:  AIC=1431415
PRICE ~ CONSTRUCTEDAREA + ROOMNUMBER + BATHNUMBER + HASTERRACE + 
    HASLIFT + HASAIRCONDITIONING + AMENITYID + HASPARKINGSPACE + 
    ISPARKINGSPACEINCLUDEDINPRICE + PARKINGSPACEPRICE + HASNORTHORIENTATION + 
    HASSOUTHORIENTATION + HASEASTORIENTATION + HASWESTORIENTATION + 
    HASBOXROOM + HASWARDROBE + HASSWIMMINGPOOL + HASDOORMAN + 
    HASGARDEN + ISDUPLEX + ISSTUDIO + ISINTOPFLOOR + BUILTTYPEID_1 + 
    BUILTTYPEID_2 + DISTANCE_TO_CITY_CENTER + DISTANCE_TO_METRO + 
    DISTANCE_TO_DIAGONAL + CADCONSTRUCTIONYEAR


Step:  AIC=1431415
PRICE ~ CONSTRUCTEDAREA + ROOMNUMBER + BATHNUMBER + HASTERRACE + 
    HASLIFT + HASAIRCONDITIONING + AMENITYID + HASPARKINGSPACE + 
    PARKINGSPACEPRICE + HASNORTHORIENTATION + HASSOUTHORIENTATION + 
    HASEASTORIENTATION + HASWESTORIENTATION + HASBOXROOM + HASWARDROBE + 
    HASSWIMMINGPOOL + HASDOORMAN + HASGARDEN + ISDUPLEX + ISSTUDIO + 
    ISINTOPFLOOR + BUILTTYPEID_1 + BUILTTYPEID_2 + DISTANCE_TO_CITY_CENTER + 
    DISTANCE_TO_METRO + DISTANCE_TO_DIAGONAL + CADCONSTRUCTIONYEAR

                          Df  Sum of Sq        RSS     AIC
- HASWESTORIENTATION       1 1.6214e+10 7.9231e+14 1431414
<none>                                  7.9230e+14 1431415
- HASEASTORIENTATION       1 4.6278e+10 7.9234e+14 1431416
- PARKINGSPACEPRICE        1 5.5911e+10 7.9235e+14 1431417
- HASWARDROBE              1 8.1556e+10 7.9238e+14 1431419
- HASGARDEN                1 8.8265e+10 7.9239e+14 1431420
- HASBOXROOM               1 1.1461e+11 7.9241e+14 1431422
- HASSOUTHORIENTATION      1 1.3313e+11 7.9243e+14 1431423
- HASNORTHORIENTATION      1 2.1237e+11 7.9251e+14 1431429
- ISINTOPFLOOR             1 4.8575e+11 7.9278e+14 1431451
- BUILTTYPEID_1            1 9.6848e+11 7.9327e+14 1431488
- AMENITYID                2 1.3397e+12 7.9364e+14 1431515
- HASTERRACE               1 1.5724e+12 7.9387e+14 1431535
- ISSTUDIO                 1 2.9895e+12 7.9529e+14 1431644
- CADCONSTRUCTIONYEAR      1 3.0788e+12 7.9538e+14 1431651
- DISTANCE_TO_METRO        1 3.3723e+12 7.9567e+14 1431674
- HASAIRCONDITIONING       1 3.7783e+12 7.9608e+14 1431705
- ISDUPLEX                 1 4.4601e+12 7.9676e+14 1431758
- HASSWIMMINGPOOL          1 5.0236e+12 7.9732e+14 1431801
- ROOMNUMBER               1 5.3269e+12 7.9763e+14 1431825
- BUILTTYPEID_2            1 6.6900e+12 7.9899e+14 1431930
- DISTANCE_TO_CITY_CENTER  1 7.5579e+12 7.9986e+14 1431997
- HASDOORMAN               1 7.8183e+12 8.0012e+14 1432017
- HASLIFT                  1 9.4655e+12 8.0176e+14 1432143
- HASPARKINGSPACE          1 1.4385e+13 8.0668e+14 1432519
- DISTANCE_TO_DIAGONAL     1 2.9907e+13 8.2221e+14 1433691
- BATHNUMBER               1 4.4215e+13 8.3651e+14 1434752
- CONSTRUCTEDAREA          1 1.0266e+15 1.8189e+15 1482511

Step:  AIC=1431414
PRICE ~ CONSTRUCTEDAREA + ROOMNUMBER + BATHNUMBER + HASTERRACE + 
    HASLIFT + HASAIRCONDITIONING + AMENITYID + HASPARKINGSPACE + 
    PARKINGSPACEPRICE + HASNORTHORIENTATION + HASSOUTHORIENTATION + 
    HASEASTORIENTATION + HASBOXROOM + HASWARDROBE + HASSWIMMINGPOOL + 
    HASDOORMAN + HASGARDEN + ISDUPLEX + ISSTUDIO + ISINTOPFLOOR + 
    BUILTTYPEID_1 + BUILTTYPEID_2 + DISTANCE_TO_CITY_CENTER + 
    DISTANCE_TO_METRO + DISTANCE_TO_DIAGONAL + CADCONSTRUCTIONYEAR

                          Df  Sum of Sq        RSS     AIC
<none>                                  7.9231e+14 1431414
- HASEASTORIENTATION       1 4.3871e+10 7.9236e+14 1431416
- PARKINGSPACEPRICE        1 5.4916e+10 7.9237e+14 1431416
- HASWARDROBE              1 7.8298e+10 7.9239e+14 1431418
- HASGARDEN                1 8.8944e+10 7.9240e+14 1431419
- HASBOXROOM               1 1.1180e+11 7.9243e+14 1431421
- HASSOUTHORIENTATION      1 1.3946e+11 7.9245e+14 1431423
- HASNORTHORIENTATION      1 2.2637e+11 7.9254e+14 1431430
- ISINTOPFLOOR             1 4.8319e+11 7.9280e+14 1431450
- BUILTTYPEID_1            1 9.7740e+11 7.9329e+14 1431488
- AMENITYID                2 1.3428e+12 7.9366e+14 1431514
- HASTERRACE               1 1.5643e+12 7.9388e+14 1431533
- ISSTUDIO                 1 2.9851e+12 7.9530e+14 1431643
- CADCONSTRUCTIONYEAR      1 3.0752e+12 7.9539e+14 1431650
- DISTANCE_TO_METRO        1 3.3685e+12 7.9568e+14 1431673
- HASAIRCONDITIONING       1 3.7660e+12 7.9608e+14 1431704
- ISDUPLEX                 1 4.4673e+12 7.9678e+14 1431758
- HASSWIMMINGPOOL          1 5.0311e+12 7.9735e+14 1431801
- ROOMNUMBER               1 5.3431e+12 7.9766e+14 1431825
- BUILTTYPEID_2            1 6.7164e+12 7.9903e+14 1431931
- DISTANCE_TO_CITY_CENTER  1 7.5565e+12 7.9987e+14 1431996
- HASDOORMAN               1 7.8102e+12 8.0012e+14 1432015
- HASLIFT                  1 9.4552e+12 8.0177e+14 1432142
- HASPARKINGSPACE          1 1.4389e+13 8.0670e+14 1432519
- DISTANCE_TO_DIAGONAL     1 2.9916e+13 8.2223e+14 1433691
- BATHNUMBER               1 4.4246e+13 8.3656e+14 1434753
- CONSTRUCTEDAREA          1 1.0269e+15 1.8193e+15 1482521
Mostrar código
summary(modelo_step)

Call:
lm(formula = PRICE ~ CONSTRUCTEDAREA + ROOMNUMBER + BATHNUMBER + 
    HASTERRACE + HASLIFT + HASAIRCONDITIONING + AMENITYID + HASPARKINGSPACE + 
    PARKINGSPACEPRICE + HASNORTHORIENTATION + HASSOUTHORIENTATION + 
    HASEASTORIENTATION + HASBOXROOM + HASWARDROBE + HASSWIMMINGPOOL + 
    HASDOORMAN + HASGARDEN + ISDUPLEX + ISSTUDIO + ISINTOPFLOOR + 
    BUILTTYPEID_1 + BUILTTYPEID_2 + DISTANCE_TO_CITY_CENTER + 
    DISTANCE_TO_METRO + DISTANCE_TO_DIAGONAL + CADCONSTRUCTIONYEAR, 
    data = dades)

Residuals:
     Min       1Q   Median       3Q      Max 
-2077264   -51574    -1634    48641  1405243 

Coefficients:
                          Estimate Std. Error t value Pr(>|t|)    
(Intercept)              4.729e+05  2.970e+04  15.921  < 2e-16 ***
CONSTRUCTEDAREA          3.856e+03  1.366e+01 282.237  < 2e-16 ***
ROOMNUMBER              -1.176e+04  5.778e+02 -20.358  < 2e-16 ***
BATHNUMBER               5.651e+04  9.647e+02  58.584  < 2e-16 ***
HASTERRACEsí             1.152e+04  1.046e+03  11.015  < 2e-16 ***
HASLIFTsí                3.247e+04  1.199e+03  27.082  < 2e-16 ***
HASAIRCONDITIONINGsí     1.742e+04  1.019e+03  17.091  < 2e-16 ***
AMENITYIDno amueblado    1.287e+04  2.308e+03   5.575 2.49e-08 ***
AMENITYIDobjetos cocina  1.780e+04  2.019e+03   8.817  < 2e-16 ***
HASPARKINGSPACEsí        6.373e+04  1.908e+03  33.408  < 2e-16 ***
PARKINGSPACEPRICE        1.965e-01  9.520e-02   2.064  0.03903 *  
HASNORTHORIENTATIONsí   -5.788e+03  1.381e+03  -4.190 2.79e-05 ***
HASSOUTHORIENTATIONsí   -3.369e+03  1.024e+03  -3.289  0.00101 ** 
HASEASTORIENTATIONsí    -2.030e+03  1.100e+03  -1.845  0.06508 .  
HASBOXROOMsí             4.457e+03  1.514e+03   2.945  0.00323 ** 
HASWARDROBEsí            2.710e+03  1.100e+03   2.464  0.01373 *  
HASSWIMMINGPOOLsí        6.327e+04  3.203e+03  19.755  < 2e-16 ***
HASDOORMANsí             4.392e+04  1.785e+03  24.613  < 2e-16 ***
HASGARDENsí             -7.260e+03  2.764e+03  -2.627  0.00863 ** 
ISDUPLEXsí              -5.369e+04  2.884e+03 -18.615  < 2e-16 ***
ISSTUDIOsí              -5.765e+04  3.788e+03 -15.217  < 2e-16 ***
ISINTOPFLOORsí           2.020e+04  3.299e+03   6.122 9.29e-10 ***
BUILTTYPEID_1sí          3.769e+04  4.329e+03   8.707  < 2e-16 ***
BUILTTYPEID_2sí         -2.949e+04  1.292e+03 -22.825  < 2e-16 ***
DISTANCE_TO_CITY_CENTER -1.109e+04  4.580e+02 -24.210  < 2e-16 ***
DISTANCE_TO_METRO        4.593e+04  2.842e+03  16.164  < 2e-16 ***
DISTANCE_TO_DIAGONAL    -2.810e+04  5.833e+02 -48.172  < 2e-16 ***
CADCONSTRUCTIONYEAR     -2.403e+02  1.556e+01 -15.445  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 113500 on 61458 degrees of freedom
Multiple R-squared:  0.8374,    Adjusted R-squared:  0.8374 
F-statistic: 1.173e+04 on 27 and 61458 DF,  p-value: < 2.2e-16

19.2.1 Interpretación

El procedimiento step() busca un compromiso entre ajuste y complejidad usando el criterio AIC. Debe usarse con prudencia:

  • puede ser útil como herramienta exploratoria;
  • no sustituye criterio sustantivo;
  • puede ser inestable en muestras pequeñas.

En docencia conviene remarcar que “selección automática” no significa “verdad científica”.

20 Comparación formal entre modelos anidados

Podemos comparar modelos anidados mediante ANOVA.

Mostrar código
anova(modelo_simple, modelo_multiple)

20.0.1 Interpretación

Este contraste evalúa si el modelo más complejo explica una reducción significativa del error respecto al modelo más simple. Si la mejora es estadísticamente relevante, hay evidencia a favor del modelo ampliado.

21 Evaluación predictiva: train/test

En Data Mining interesa mucho evaluar fuera de muestra.

21.1 Partición entrenamiento/prueba

Mostrar código
set.seed(1994)

trainIndex <- caret::createDataPartition(dades$PRICE, p = .8, 
                                         list = FALSE, 
                                         times = 1)

train <- dades[ trainIndex,]
test  <- dades[-trainIndex,]

modelo_train <- lm(modelo_step$call$formula, data = train)
pred_test <- predict(modelo_train, newdata = test)

(rmse <- sqrt(mean((test$PRICE - pred_test)^2)))
[1] 111194
Mostrar código
(mae  <- mean(abs(test$PRICE - pred_test)))
[1] 72640

21.1.1 Interpretación

  • RMSE penaliza más los errores grandes.
  • MAE es más robusto e interpretable como error medio absoluto.

Estas métricas son más relevantes para predicción que el \(R^2\) de entrenamiento.

22 Validación cruzada

Con muestras pequeñas, una sola partición train/test puede ser inestable. Una alternativa mejor es la validación cruzada.

Mostrar código
set.seed(1994)
control <- trainControl(method = "cv", number = 5)

modelo_cv <- train(modelo_step$call$formula, data = dades,
  method = "lm", trControl = control)

modelo_cv
Linear Regression 

61486 samples
   26 predictor

No pre-processing
Resampling: Cross-Validated (5 fold) 
Summary of sample sizes: 49189, 49189, 49189, 49188, 49189 
Resampling results:

  RMSE      Rsquared   MAE     
  113612.6  0.8371971  73371.73

Tuning parameter 'intercept' was held constant at a value of TRUE

22.0.1 Interpretación

La validación cruzada estima el rendimiento promedio repitiendo ajustes sobre diferentes subconjuntos. Esto reduce la dependencia de una única partición aleatoria.

23 Transformaciones y no linealidad

No siempre la relación es estrictamente lineal. A veces puede mejorar con transformaciones o términos polinómicos.

23.1 Término cuadrático

Mostrar código
modelo_cuadratico <- lm(PRICE ~ CONSTRUCTEDAREA + I(CONSTRUCTEDAREA^2), data = dades)
summary(modelo_cuadratico)

Call:
lm(formula = PRICE ~ CONSTRUCTEDAREA + I(CONSTRUCTEDAREA^2), 
    data = dades)

Residuals:
     Min       1Q   Median       3Q      Max 
-2041953   -70562    -2711    67244  1678661 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)          -8.809e+04  1.689e+03  -52.16   <2e-16 ***
CONSTRUCTEDAREA       5.248e+03  2.220e+01  236.45   <2e-16 ***
I(CONSTRUCTEDAREA^2) -1.442e+00  5.171e-02  -27.89   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 134100 on 61483 degrees of freedom
Multiple R-squared:  0.7731,    Adjusted R-squared:  0.7731 
F-statistic: 1.047e+05 on 2 and 61483 DF,  p-value: < 2.2e-16

23.1.1 Interpretación

El término I(CONSTRUCTEDAREA^2) permite capturar curvatura. El modelo sigue siendo lineal en parámetros. Si el coeficiente cuadrático es relevante, la relación media entre CONSTRUCTEDAREA y PRICE no es una recta pura.

23.2 Tranformación de Box-Cox

A veces hay variables que no cumplen la normalidad pedida. Es por ello que va bien realizar transformaciones logarítimicas de ellas pasando de modelos lineales a modelos log-lineales o modelos log-log.

En nuestro caso, vamos a transformar la variable PRICE. Para ello, se ha de introducir el log(PRICE) en el modelo.

Mostrar código
modelo_logNormal <- lm(log(PRICE) ~ CONSTRUCTEDAREA + I(CONSTRUCTEDAREA^2), data = dades)
summary(modelo_cuadratico)

Call:
lm(formula = PRICE ~ CONSTRUCTEDAREA + I(CONSTRUCTEDAREA^2), 
    data = dades)

Residuals:
     Min       1Q   Median       3Q      Max 
-2041953   -70562    -2711    67244  1678661 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)          -8.809e+04  1.689e+03  -52.16   <2e-16 ***
CONSTRUCTEDAREA       5.248e+03  2.220e+01  236.45   <2e-16 ***
I(CONSTRUCTEDAREA^2) -1.442e+00  5.171e-02  -27.89   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 134100 on 61483 degrees of freedom
Multiple R-squared:  0.7731,    Adjusted R-squared:  0.7731 
F-statistic: 1.047e+05 on 2 and 61483 DF,  p-value: < 2.2e-16

23.3 Comparación con el modelo lineal simple

Mostrar código
anova(modelo_simple, modelo_cuadratico)

23.3.1 Interpretación

Si el modelo cuadrático mejora significativamente, la linealidad simple podría ser insuficiente.

24 Outliers, leverage e influencia

No todas las observaciones pesan igual. Algunas tienen capacidad de alterar mucho el ajuste.

24.1 Distancia de Cook

Mostrar código
cooks <- cooks.distance(modelo_multiple)
head(cooks, n = 20)
           1            2            3            4            5            6 
1.251305e-06 1.709072e-05 1.848831e-05 3.070021e-06 1.348481e-06 1.579923e-05 
           7            8            9           10           11           12 
5.180684e-07 3.359521e-05 4.078651e-06 9.917551e-06 4.890988e-05 8.059625e-09 
          13           14           15           16           17           18 
7.181431e-05 3.546997e-09 9.857850e-07 5.646318e-09 2.473805e-06 9.441805e-07 
          19           20 
2.154346e-07 1.650767e-07 

24.2 Visualización de observaciones influyentes

Mostrar código
# Crear dataframe
df_cooks <- data.frame(
  index = 1:length(cooks),
  cooks = cooks
)

# Umbral típico
threshold <- 4 / nrow(dades)

ggplot(df_cooks, aes(x = index, y = cooks)) +
  geom_segment(aes(xend = index, yend = 0), alpha = 0.6) +
  geom_hline(yintercept = threshold, color = "red", linetype = "dashed") +
  labs(
    title = "Distancia de Cook",
    x = "Observación",
    y = "Cook's Distance"
  ) +
  theme_minimal()

24.2.1 Interpretación

Observaciones con distancia de Cook elevada merecen revisión. No significa que deban eliminarse automáticamente, sino que tienen gran influencia y conviene entender por qué.

Mostrar código
ggplot(df_cooks, aes(x = index, y = cooks)) +
  geom_segment(aes(xend = index, yend = 0), alpha = 0.6) +
  
  # Puntos influyentes
  geom_point(data = subset(df_cooks, cooks > threshold),
             aes(x = index, y = cooks),
             color = "red", size = 2) +
  
  geom_hline(yintercept = threshold, color = "red", linetype = "dashed") +
  
  labs(
    title = "Detección de observaciones influyentes (Cook's Distance)",
    subtitle = "Puntos en rojo superan el umbral 4/n",
    x = "Observación",
    y = "Cook's Distance"
  ) +
  theme_minimal()

Mostrar código
df_cooks_sorted <- df_cooks[order(-df_cooks$cooks), ]

ggplot(df_cooks_sorted[1:50, ], aes(x = reorder(index, -cooks), y = cooks)) +
  geom_col() +
  geom_hline(yintercept = threshold, color = "red", linetype = "dashed") +
  labs(
    title = "Top 50 observaciones más influyentes",
    x = "Observación",
    y = "Cook's Distance"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle=45))

25 Lectura crítica de un modelo lineal

Cuando se termine un ajuste, no se debería limitar a copiar la salida de summary(). Debería responder, como mínimo, a estas preguntas:

  1. ¿Cuál es la variable respuesta?
  2. ¿Qué predictores se han incluido y por qué?
  3. ¿Cómo se interpreta cada coeficiente?
  4. ¿El signo de los coeficientes tiene sentido sustantivo?
  5. ¿Qué capacidad explicativa tiene el modelo?
  6. ¿Se cumplen razonablemente los supuestos?
  7. ¿Sirve más para explicar o para predecir?
  8. ¿Existen observaciones influyentes o problemas de colinealidad?

26 Errores habituales de los estudiantes

26.1 Confundir asociación con causalidad

Un coeficiente significativo no demuestra causalidad. Solo indica asociación condicionada al modelo ajustado.

26.2 Interpretar el intercepto de forma mecánica

A veces el valor X = 0 carece de sentido real. En ese caso, el intercepto existe matemáticamente, pero su interpretación sustantiva puede ser irrelevante.

26.3 Creer que un valor-p pequeño implica “modelo bueno”

La significación de coeficientes no garantiza buen ajuste ni buena predicción.

26.4 Elegir el modelo solo por \(R^2\)

Un modelo con mucho sobreajuste puede tener alto \(R^2\) en entrenamiento y mal rendimiento fuera de muestra.

26.5 Ignorar el tipo de variable

Tratar categorías como numéricas o viceversa puede invalidar la interpretación.

27 Bibliografia

Aquesta web està creada por Dante Conti y Sergi Ramírez, (c) 2026