Trabajo final — Regresión lineal múltiple

NASA Airfoil Self-Noise

Author

Miguel Turizo · Carlos Garay · Angel Mendoza · Valentina Puentes

Introducción

Este informe analiza el nivel de presión sonora SSPL registrado en la base NASA Airfoil Self-Noise. Se estudia su relación con frecuencia (f), ángulo de ataque (alpha), longitud de cuerda (c), velocidad del flujo (U_infinity) y espesor de desplazamiento (delta). El menú lateral permite ir directamente a cada apartado. Todos los bloques de código se muestran en el informe.

Datos y preparación

La información se importa desde la hoja Base de datos de NASA.xlsx. Guarda el Excel y este archivo R Markdown en la misma carpeta antes de usar Knit.

# TRABAJO FINAL - REGRESION LINEAL MULTIPLE
# NASA Airfoil Self-Noise
# Integrantes: Miguel Turizo, Carlos Garay, Angel Mendoza, Valentina Puentes

library(readxl)
library(nortest)
library(lmtest)
library(car)

# Si NASA.xlsx esta en otra carpeta, sustituir solo esta ruta.
NASA <- read_excel("NASA.xlsx", sheet = "Base de datos")

SSPL       <- NASA$SSPL
f          <- NASA$f
alpha      <- NASA$alpha
c          <- NASA$c
U_infinity <- NASA$U_infinity
delta      <- NASA$delta

n <- length(SSPL)
k <- 5

Exploracion

Se revisan resumen, valores faltantes, correlaciones y relaciones gráficas entre variables.

## Exploracion
summary(NASA)
       f             alpha              c            U_infinity   
 Min.   :  200   Min.   : 0.000   Min.   :0.0254   Min.   :31.70  
 1st Qu.:  800   1st Qu.: 2.000   1st Qu.:0.0508   1st Qu.:39.60  
 Median : 1600   Median : 5.400   Median :0.1016   Median :39.60  
 Mean   : 2886   Mean   : 6.782   Mean   :0.1365   Mean   :50.86  
 3rd Qu.: 4000   3rd Qu.: 9.900   3rd Qu.:0.2286   3rd Qu.:71.30  
 Max.   :20000   Max.   :22.200   Max.   :0.3048   Max.   :71.30  
     delta                SSPL      
 Min.   :0.0004007   Min.   :103.4  
 1st Qu.:0.0025351   1st Qu.:120.2  
 Median :0.0049574   Median :125.7  
 Mean   :0.0111399   Mean   :124.8  
 3rd Qu.:0.0155759   3rd Qu.:130.0  
 Max.   :0.0584113   Max.   :141.0  
colSums(is.na(NASA))
         f      alpha          c U_infinity      delta       SSPL 
         0          0          0          0          0          0 
round(cor(NASA), 3)
                f  alpha      c U_infinity  delta   SSPL
f           1.000 -0.273 -0.004      0.134 -0.230 -0.391
alpha      -0.273  1.000 -0.505      0.059  0.753 -0.156
c          -0.004 -0.505  1.000      0.004 -0.221 -0.236
U_infinity  0.134  0.059  0.004      1.000 -0.004  0.125
delta      -0.230  0.753 -0.221     -0.004  1.000 -0.313
SSPL       -0.391 -0.156 -0.236      0.125 -0.313  1.000
pairs(NASA, pch = 20, cex = 0.4)

1. Modelo y estimacion de parametros

Se estima por mínimos cuadrados el modelo lineal completo con las cinco regresoras originales.

## 1. Modelo y estimacion de parametros
# SSPL = b0 + b1*f + b2*alpha + b3*c + b4*U_infinity + b5*delta + e
modelo <- lm(SSPL ~ f + alpha + c + U_infinity + delta, data = NASA)
summary(modelo)

Call:
lm(formula = SSPL ~ f + alpha + c + U_infinity + delta, data = NASA)

Residuals:
    Min      1Q  Median      3Q     Max 
-17.480  -2.882  -0.209   3.152  16.064 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  1.328e+02  5.447e-01  243.87   <2e-16 ***
f           -1.282e-03  4.211e-05  -30.45   <2e-16 ***
alpha       -4.219e-01  3.890e-02  -10.85   <2e-16 ***
c           -3.569e+01  1.630e+00  -21.89   <2e-16 ***
U_infinity   9.985e-02  8.132e-03   12.28   <2e-16 ***
delta       -1.473e+02  1.501e+01   -9.81   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 4.809 on 1497 degrees of freedom
Multiple R-squared:  0.5157,    Adjusted R-squared:  0.5141 
F-statistic: 318.8 on 5 and 1497 DF,  p-value: < 2.2e-16

2. Inferencia sobre el modelo completo

Se contrasta si todas las pendientes son cero frente a que al menos una es distinta de cero.

## 2. Inferencia sobre el modelo completo
# H0: b1 = b2 = b3 = b4 = b5 = 0; H1: al menos uno es distinto de 0.
modelo_nulo <- lm(SSPL ~ 1, data = NASA)
anova(modelo_nulo, modelo)
Analysis of Variance Table

Model 1: SSPL ~ 1
Model 2: SSPL ~ f + alpha + c + U_infinity + delta
  Res.Df   RSS Df Sum of Sq      F    Pr(>F)    
1   1502 71482                                  
2   1497 34618  5     36864 318.82 < 2.2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
qf(0.05, k, n - k - 1, lower.tail = FALSE)
[1] 2.220076

3. Inferencia para cada parametro

Se examinan los estadísticos t y los valores p de cada coeficiente.

## 3. Inferencia para cada parametro
# H0: bj = 0; H1: bj es distinto de 0.
summary(modelo)$coefficients
                 Estimate   Std. Error    t value      Pr(>|t|)
(Intercept)  1.328338e+02 5.447007e-01 243.865682  0.000000e+00
f           -1.282207e-03 4.210547e-05 -30.452267 6.421817e-159
alpha       -4.219117e-01 3.889609e-02 -10.847149  1.923376e-26
c           -3.568800e+01 1.630432e+00 -21.888679  2.286839e-92
U_infinity   9.985404e-02 8.132259e-03  12.278758  4.340636e-33
delta       -1.473005e+02 1.501467e+01  -9.810441  4.617244e-22
t_teorico <- qt(0.025, df = n - k - 1, lower.tail = FALSE)
t_teorico
[1] 1.96155
confint(modelo, level = 0.95)
                    2.5 %        97.5 %
(Intercept)  1.317653e+02  1.339023e+02
f           -1.364799e-03 -1.199615e-03
alpha       -4.982083e-01 -3.456151e-01
c           -3.888617e+01 -3.248983e+01
U_infinity   8.390221e-02  1.158059e-01
delta       -1.767525e+02 -1.178485e+02

4. Normalidad de los residuales

El gráfico Q-Q y las pruebas formales examinan la distribución de los errores.

## 4. Normalidad de los residuales
residuales <- residuals(modelo)
qqnorm(residuales, main = "Q-Q de residuales")
qqline(residuales, col = "red")

hist(residuales, breaks = 30, col = "steelblue",
     main = "Histograma de residuales", xlab = "Residuales")

lillie.test(residuales)

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  residuales
D = 0.027418, p-value = 0.01026
ad.test(residuales)

    Anderson-Darling normality test

data:  residuales
A = 1.3911, p-value = 0.001339
shapiro.test(residuales)

    Shapiro-Wilk normality test

data:  residuales
W = 0.99563, p-value = 0.0002465

5. Varianza constante

El gráfico de residuos y la prueba de Breusch-Pagan evalúan la homocedasticidad.

## 5. Varianza constante
ajustados <- fitted(modelo)
plot(ajustados, residuales, pch = 20,
     main = "Residuales vs ajustados",
     xlab = "Valores ajustados", ylab = "Residuales")
abline(h = 0, col = "red")

bptest(modelo)

    studentized Breusch-Pagan test

data:  modelo
BP = 91.141, df = 5, p-value < 2.2e-16
bptest(modelo, studentize = FALSE)

    Breusch-Pagan test

data:  modelo
BP = 116.32, df = 5, p-value < 2.2e-16
qchisq(0.05, k, lower.tail = FALSE)
[1] 11.0705

6. Independencia

Se observa el orden de las mediciones y se aplica Durbin-Watson con cautela: el orden experimental no es una serie temporal.

## 6. Independencia
plot(seq_len(n), residuales, pch = 20,
     main = "Residuales segun el orden",
     xlab = "Observacion", ylab = "Residuales")
abline(h = 0, col = "red")

set.seed(123)
durbinWatsonTest(modelo, alternative = "two.sided")
 lag Autocorrelation D-W Statistic p-value
   1        0.775644     0.4474251       0
 Alternative hypothesis: rho != 0
# El orden de filas corresponde al experimento; no implica una serie temporal.

7. Multicolinealidad

El VIF mide cuánto se relaciona cada regresora con las demás.

## 7. Multicolinealidad
vif(modelo)
         f      alpha          c U_infinity      delta 
  1.144444   3.441658   1.510754   1.041698   2.532127 

7.1. Observaciones influyentes

La distancia de Cook y los residuos estandarizados señalan observaciones que conviene revisar.

## 7.1. Observaciones influyentes
cook <- cooks.distance(modelo)
plot(cook, type = "h", main = "Distancia de Cook",
     xlab = "Observacion", ylab = "Distancia de Cook")
abline(h = 4 / n, col = "red")

sum(cook > 4 / n)
[1] 114
sum(abs(rstandard(modelo)) > 3)
[1] 13

8. Seleccion del modelo: todas las regresiones posibles

Se forman logf_c = log(f) - media(log(f)), logf_c2 = logf_c² y logdelta = log(delta). Son transformaciones de variables medidas, no datos nuevos. Se comparan 63 subconjuntos; luego se excluyen los que incluyen el cuadrado sin el término lineal. R², R² ajustado, Cp, AIC, BIC y PRESS permiten comparar los modelos.

## 8. Seleccion del modelo: todas las regresiones posibles
# Estos tres terminos vienen de f y delta, que son positivos en NASA.xlsx.
# Centrar log(f) = restarle su media; el cuadrado permite curvatura.
logf_c   <- log(f) - mean(log(f))
logf_c2  <- logf_c^2
logdelta <- log(delta)

datos2 <- data.frame(SSPL, logf_c, logf_c2, alpha, c, U_infinity, logdelta)
vars   <- names(datos2)[-1]
full   <- lm(SSPL ~ ., data = datos2)

SST   <- sum((SSPL - mean(SSPL))^2)       # suma de cuadrados total
MSE_k <- summary(full)$sigma^2            # CME del modelo completo
press <- function(m) sum((residuals(m) / (1 - hatvalues(m)))^2)

tabla <- NULL
for (r in 1:length(vars)) {
  for (cmb in combn(vars, r, simplify = FALSE)) {
    m   <- lm(reformulate(cmb, "SSPL"), data = datos2)
    p   <- length(coef(m))                # parametros, incluido el intercepto
    SSE <- sum(residuals(m)^2)
    tabla <- rbind(tabla, data.frame(
      variables = paste(cmb, collapse = " + "), p = p,
      R2_p   = 1 - SSE / SST,                         # R2
      R2aj_p = 1 - ((n - 1) / (n - p)) * SSE / SST,   # R2 ajustado
      Cp     = SSE / MSE_k - (n - 2 * p),             # Cp de Mallows
      AIC_p  = n * log(SSE / n) + 2 * p,
      BIC_p  = n * log(SSE / n) + p * log(n),
      PRESS  = press(m)))
  }
}
nrow(tabla)                                   # 63 modelos
[1] 63
# Jerarquia: si esta logf_c2 debe estar logf_c.
tabla <- tabla[vapply(strsplit(tabla$variables, " + ", fixed = TRUE),
                      function(x) !("logf_c2" %in% x) || ("logf_c" %in% x),
                      logical(1)), ]
tabla <- tabla[order(tabla$BIC_p), ]
head(tabla, 10)
                                              variables p      R2_p    R2aj_p
60         logf_c + logf_c2 + c + U_infinity + logdelta 6 0.5368891 0.5353423
63 logf_c + logf_c2 + alpha + c + U_infinity + logdelta 7 0.5386730 0.5368227
57            logf_c + logf_c2 + alpha + c + U_infinity 6 0.5143835 0.5127616
59     logf_c + logf_c2 + alpha + U_infinity + logdelta 6 0.5018928 0.5002292
46                      logf_c + logf_c2 + c + logdelta 5 0.4942210 0.4928705
58              logf_c + logf_c2 + alpha + c + logdelta 6 0.4942471 0.4925579
44                  logf_c + logf_c2 + alpha + logdelta 5 0.4680206 0.4666001
51                   logf_c + c + U_infinity + logdelta 5 0.4672206 0.4657980
61           logf_c + alpha + c + U_infinity + logdelta 6 0.4694556 0.4676835
47             logf_c + logf_c2 + U_infinity + logdelta 5 0.4597238 0.4582811
          Cp    AIC_p    BIC_p    PRESS
60  10.78467 4659.575 4691.466 33420.42
63   7.00000 4655.775 4692.981 33360.73
57  83.76628 4730.897 4762.788 35033.49
59 124.27128 4769.067 4800.958 35974.25
46 147.14965 4790.040 4816.616 36448.49
58 149.06501 4791.962 4823.853 36517.40
44 232.11276 4865.948 4892.525 38364.67
51 234.70696 4868.207 4894.783 38374.35
61 229.45947 4863.889 4895.780 38296.73
47 259.01801 4889.209 4915.785 38927.54
tabla[which.max(tabla$R2aj_p), ]              # mayor R2 ajustado
                                              variables p     R2_p    R2aj_p Cp
63 logf_c + logf_c2 + alpha + c + U_infinity + logdelta 7 0.538673 0.5368227  7
      AIC_p    BIC_p    PRESS
63 4655.775 4692.981 33360.73
tabla[which.min(abs(tabla$Cp - tabla$p)), ]   # Cp mas cercano a p
                                              variables p     R2_p    R2aj_p Cp
63 logf_c + logf_c2 + alpha + c + U_infinity + logdelta 7 0.538673 0.5368227  7
      AIC_p    BIC_p    PRESS
63 4655.775 4692.981 33360.73
tabla[which.min(tabla$AIC_p), ]               # menor AIC
                                              variables p     R2_p    R2aj_p Cp
63 logf_c + logf_c2 + alpha + c + U_infinity + logdelta 7 0.538673 0.5368227  7
      AIC_p    BIC_p    PRESS
63 4655.775 4692.981 33360.73
tabla[which.min(tabla$BIC_p), ]               # menor BIC
                                      variables p      R2_p    R2aj_p       Cp
60 logf_c + logf_c2 + c + U_infinity + logdelta 6 0.5368891 0.5353423 10.78467
      AIC_p    BIC_p    PRESS
60 4659.575 4691.466 33420.42
tabla[which.min(tabla$PRESS), ]               # menor PRESS
                                              variables p     R2_p    R2aj_p Cp
63 logf_c + logf_c2 + alpha + c + U_infinity + logdelta 7 0.538673 0.5368227  7
      AIC_p    BIC_p    PRESS
63 4655.775 4692.981 33360.73

9. Metodos paso a paso

Se muestran selección hacia adelante y eliminación hacia atrás. El modelo final se decide con la tabla jerárquica del punto 8.

## 9. Metodos paso a paso
# Usan las mismas seis columnas candidatas. El modelo final se elige de la
# tabla anterior, donde si se respeta la jerarquia del termino cuadratico.
nulo <- lm(SSPL ~ 1, data = datos2)
modelo_forward <- step(nulo, scope = formula(full),
                       direction = "forward", trace = 0)
modelo_backward <- step(full, direction = "backward", trace = 0)
formula(modelo_forward)
SSPL ~ logf_c + logdelta + c + logf_c2 + U_infinity + alpha
formula(modelo_backward)
SSPL ~ logf_c + logf_c2 + alpha + c + U_infinity + logdelta

10. Modelo elegido y conclusion

Se selecciona el menor BIC entre los subconjuntos válidos y se repiten los diagnósticos principales. Un BIC menor no garantiza que los supuestos se cumplan.

## 10. Modelo elegido y conclusion
# Menor BIC entre los subconjuntos validos de la seccion 8.
mejor <- tabla$variables[which.min(tabla$BIC_p)]
modelo_final <- lm(as.formula(paste("SSPL ~", mejor)), data = datos2)
summary(modelo_final)

Call:
lm(formula = as.formula(paste("SSPL ~", mejor)), data = datos2)

Residuals:
     Min       1Q   Median       3Q      Max 
-19.5973  -2.6729  -0.0638   3.0977  14.2376 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) 108.347173   0.728268  148.77   <2e-16 ***
logf_c       -3.727571   0.121081  -30.79   <2e-16 ***
logf_c2      -1.445308   0.096311  -15.01   <2e-16 ***
c           -20.547492   1.301006  -15.79   <2e-16 ***
U_infinity    0.092342   0.007863   11.74   <2e-16 ***
logdelta     -3.153082   0.107910  -29.22   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 4.703 on 1497 degrees of freedom
Multiple R-squared:  0.5369,    Adjusted R-squared:  0.5353 
F-statistic: 347.1 on 5 and 1497 DF,  p-value: < 2.2e-16
formula(modelo_final)
SSPL ~ logf_c + logf_c2 + c + U_infinity + logdelta
# El modelo final debe volver a revisarse: seleccionar variables no garantiza
# normalidad, homocedasticidad ni independencia de los errores.
res_final <- residuals(modelo_final)
qqnorm(res_final, main = "Q-Q del modelo final")
qqline(res_final, col = "red")

plot(fitted(modelo_final), res_final, pch = 20,
     main = "Residuales vs ajustados: modelo final",
     xlab = "Valores ajustados", ylab = "Residuales")
abline(h = 0, col = "red")

print(bptest(modelo_final))

    studentized Breusch-Pagan test

data:  modelo_final
BP = 331.4, df = 5, p-value < 2.2e-16
print(durbinWatsonTest(modelo_final, alternative = "two.sided"))
 lag Autocorrelation D-W Statistic p-value
   1       0.7879007      0.422193       0
 Alternative hypothesis: rho != 0
if (length(coef(modelo_final)) > 2) print(vif(modelo_final))
    logf_c    logf_c2          c U_infinity   logdelta 
  1.171879   1.004477   1.005930   1.018346   1.161666 
cat("Modelo final:", deparse(formula(modelo_final)), "\n")
Modelo final: SSPL ~ logf_c + logf_c2 + c + U_infinity + logdelta 
cat("R2 ajustado:", summary(modelo_final)$adj.r.squared, "\n")
R2 ajustado: 0.5353423 
cat("Conclusiones: interpretar las asociaciones con cautela si fallan",
    "los supuestos; el orden experimental no demuestra dependencia temporal.\n")
Conclusiones: interpretar las asociaciones con cautela si fallan los supuestos; el orden experimental no demuestra dependencia temporal.

Cierre

Interpreta los coeficientes y la selección únicamente después de revisar las salidas que genera el código. Si los diagnósticos señalan problemas, presenta las limitaciones antes de sacar conclusiones sobre la relación entre las variables. El informe es autocontenido una vez tejido en HTML.