Una guía sobre regresión lineal y polinómica, con implementación en R y ejemplos de ingeniería.
A diferencia de la interpolación, que busca una función que pase exactamente por cada punto de datos, el ajuste de curvas o regresión busca una función que represente la tendencia general de los datos. No se requiere que la curva pase por todos los puntos.
Esto es fundamental en ingeniería y ciencias experimentales, donde los datos casi siempre contienen "ruido" o errores de medición. El objetivo es encontrar el modelo matemático "más simple" que mejor se ajuste a la tendencia subyacente de los datos.
El método de mínimos cuadrados es la técnica más común para lograr esto. Funciona minimizando la suma de los cuadrados de las distancias verticales (residuos) entre los datos reales y los valores predichos por la función de ajuste.
El objetivo es minimizar el error total, definido como la Suma de los Cuadrados de los Residuos (SCR):
$$ SCR = \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 $$donde $y_i$ es el valor real y $\hat{y}_i$ es el valor predicho por nuestro modelo.
Para el caso más simple, una línea recta $\hat{y} = a_0 + a_1x$, minimizamos $SCR = \sum (y_i - (a_0 + a_1x_i))^2$. Para encontrar los coeficientes $a_0$ y $a_1$ que minimizan esta expresión, tomamos las derivadas parciales con respecto a cada coeficiente y las igualamos a cero. Esto nos lleva al siguiente sistema de ecuaciones normales:
Podemos extender esta idea a un polinomio de grado $m$: $\hat{y} = a_0 + a_1x + a_2x^2 + \dots + a_mx^m$. El sistema de ecuaciones normales se vuelve más grande. Es mucho más eficiente representarlo en forma matricial:
Donde:
Podemos resolver para el vector de coeficientes $\mathbf{A}$ calculando: $\mathbf{A} = (\mathbf{X}^T \mathbf{X})^{-1} \mathbf{X}^T \mathbf{Y}$.
La siguiente función en R implementa la regresión polinómica por mínimos cuadrados para un grado arbitrario.
#' Ajuste Polinómico por Mínimos Cuadrados
#'
#' @param x_vals Vector con los valores de x.
#' @param y_vals Vector con los valores de y.
#' @param degree Grado del polinomio a ajustar.
#' @return Una lista que contiene los coeficientes y una función del polinomio.
least_squares_poly <- function(x_vals, y_vals, degree) {
n_points <- length(x_vals)
# Construir la matriz de diseño X
X_matrix <- matrix(0, nrow = n_points, ncol = degree + 1)
for (j in 0:degree) {
X_matrix[, j + 1] <- x_vals^j
}
# Resolver el sistema de ecuaciones normales: A = (X'X)^-1 * X'Y
XtX <- t(X_matrix) %*% X_matrix
XtY <- t(X_matrix) %*% y_vals
coefs <- solve(XtX, XtY)
# Crear la función del polinomio
poly_func <- function(x) {
terms <- sapply(0:degree, function(d) coefs[d + 1] * x^d)
return(sum(terms))
}
return(list(coefficients = as.vector(coefs), polynomial = poly_func))
}
Problema: Se tienen los siguientes datos de un proceso, extraídos del archivo minimos_cuad.html
. Se necesita encontrar un modelo matemático que describa la relación entre X e Y.
# Datos del problema proporcionado
X <- c(0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0)
Y <- c(10.5, 5.4844, 0.0, -3.6094, -4.5, -2.9531, 0.0, 2.9531, 4.5, 3.6094, 0.0)
datos <- data.frame(X, Y)
# Intento 1: Ajuste lineal (Grado 1), como sugería el comentario del archivo original
fit_lineal <- least_squares_poly(X, Y, degree = 1)
print("Coeficientes del ajuste lineal (a0, a1):")
print(fit_lineal$coefficients)
# Intento 2: Ajuste cuadrático (Grado 2), observando la forma de los datos
fit_cuadratico <- least_squares_poly(X, Y, degree = 2)
print("Coeficientes del ajuste cuadrático (a0, a1, a2):")
print(fit_cuadratico$coefficients)
# Intento 3: Ajuste cúbico (Grado 3)
fit_cubico <- least_squares_poly(X, Y, degree = 3)
print("Coeficientes del ajuste cúbico (a0, a1, a2, a3):")
print(fit_cubico$coefficients)
# Graficar los resultados para comparar
library(ggplot2)
# Crear puntos para las curvas de ajuste
x_range <- seq(0, 5, length.out = 100)
y_lineal <- sapply(x_range, fit_lineal$polynomial)
y_cuadratico <- sapply(x_range, fit_cuadratico$polynomial)
y_cubico <- sapply(x_range, fit_cubico$polynomial)
ggplot(datos, aes(x = X, y = Y)) +
geom_point(color = "black", size = 3, shape = 21, fill = "gray") +
geom_line(data = data.frame(x=x_range, y=y_lineal), aes(x=x, y=y, color = "Lineal (Grado 1)"), size=1) +
geom_line(data = data.frame(x=x_range, y=y_cuadratico), aes(x=x, y=y, color = "Cuadrático (Grado 2)"), size=1) +
geom_line(data = data.frame(x=x_range, y=y_cubico), aes(x=x, y=y, color = "Cúbico (Grado 3)"), size=1.2) +
labs(title = "Comparación de Ajustes por Mínimos Cuadrados",
subtitle = "Datos del archivo proporcionado",
x = "Variable Independiente X", y = "Variable Dependiente Y",
color = "Modelo de Ajuste") +
scale_color_manual(values = c("Lineal (Grado 1)" = "orange", "Cuadrático (Grado 2)" = "red", "Cúbico (Grado 3)" = "blue")) +
theme_minimal()
El ajuste lineal claramente no es adecuado para estos datos. Sin embargo, tanto el ajuste cuadrático (parábola) como el cúbico siguen la tendencia de los puntos de manera mucho más precisa. El modelo cúbico parece ser el mejor, capturando la inflexión en la curva que el modelo cuadrático no puede. La elección final del modelo dependería del conocimiento del fenómeno físico subyacente y del principio de parsimonia (elegir el modelo más simple que explique bien los datos).
Problema: Un ingeniero está calibrando un nuevo sensor de presión. Para ello, aplica presiones conocidas (en psi) y registra el voltaje de salida (en mV) del sensor. El objetivo es encontrar una ecuación lineal que relacione la presión con el voltaje para poder usar el sensor en mediciones futuras.
# Datos de calibración del sensor
presion_psi <- c(0, 10, 20, 30, 40, 50)
voltaje_mV <- c(4.9, 15.2, 24.8, 35.1, 45.3, 54.9)
calibracion_data <- data.frame(P = presion_psi, V = voltaje_mV)
# Realizar un ajuste lineal (degree=1)
fit_sensor <- least_squares_poly(presion_psi, voltaje_mV, degree = 1)
a0 <- fit_sensor$coefficients[1]
a1 <- fit_sensor$coefficients[2]
print(paste0("Ecuación de calibración: V = ", round(a0,3), " + ", round(a1,3), " * P"))
# Graficar
ggplot(calibracion_data, aes(x = P, y = V)) +
geom_point(size = 3, color = "darkblue") +
geom_abline(intercept = a0, slope = a1, color = "red", size = 1) +
labs(title = "Calibración de Sensor de Presión",
x = "Presión (psi)", y = "Voltaje de Salida (mV)") +
theme_bw()
[1] "Ecuación de calibración: V = 5.013 + 1.002 * P"
Este resultado proporciona una ecuación simple y robusta que el ingeniero puede programar en un microcontrolador para convertir directamente las lecturas de voltaje del sensor a valores de presión con alta confianza.