Introducción
Acerca de la Regresión Polinomial
La expansión polinomial es una técnica en el procesamiento de datos y modelado que consiste en crear nuevas características combinando las características de entrada originales mediante polinomios. Este proceso aumenta la dimensionalidad de las características para resolver problemas de subajuste en los modelos.
Por ejemplo, si la característica original es x, podemos crear nuevas características como \(x^2\), \(x^3\), entre otras. De esta manera, expandimos el espacio de características unidimensional a uno de mayor dimensión.
El propósito principal de la expansión es capturar relaciones no lineales más complejas en los datos. Al introducir términos de orden superior, el modelo puede ajustarse mejor a los patrones no lineales de los datos.
Por ejemplo, para una relación parabólica simple \(y = a*x^2 + b*x + c\), si solo usamos la característica original x para una regresión lineal, es posible que no se ajusten bien los datos. Sin embargo, al expandir creando la característica \(x^2\), el modelo de regresión polinomial puede capturar con precisión esta relación parabólica.
No obstante, una expansión excesiva puede provocar sobreajuste, donde el modelo funciona muy bien con los datos de entrenamiento pero generaliza mal con nuevos datos. Por lo tanto, al usar la expansión polinomial, es crucial seleccionar cuidadosamente el grado del polinomio y las combinaciones de características, combinando técnicas como la validación cruzada para elegir la complejidad adeucada del modelo.
En este caso, generaremos aleatoriamente una ecuación cuadrática con ruido y varios conjuntos de datos aleatorios. Utilizaremos operaciones de matriz con numpy, entrenaremos el modelo con la biblioteca sklearn y visualizaremos los datos y el modelo con matplotlib.
Código Clave
La biblioteca sklearn proporciona herramientas convenientes para la expansión polinomial. El siguiente ejemplo de código utiliza la clase PolynomialFeatures para expandir las características originales:
- degree: límite de dimensionalidad después de la expansión
- interaction_only: si solo se deben generar términos de interacción:
- Cuando interaction_only=False (valor predeterminado), PolynomialFeatures genera todas las combinaciones polinomiales posibles, incluyendo monomios de todos los órdenes y términos de interacción. Por ejemplo, para dos características \(x_1\) y \(x_2\), si degree=2, el conjunto de características generado incluirá \([1, x_1, x_2, x_1 * x_2, x_2^2]\)
- Cuando interaction_only=True, PolynomialFeatures solo genera términos de interacción y términos de orden cero. Esto significa que no generará términos de orden superior individuales de ninguna característica, solo términos de interacción entre diferentes características. Continuando con el ejemplo anterior, si degree=2 y interaction_only=True, el conjunto de características generado solo incluirá \([1, x_1 * x_2]\)
from sklearn.preprocessing import PolynomialFeatures
# Expandimos X polinomialmente. En este ejemplo, X originalmente solo tiene X^1 (unidimensional)
# Después de la expansión, X contendrá [X^0, X^1, X^2] (tridimensional)
poly = PolynomialFeatures(degree=2, interaction_only=False)
X = X.reshape(-1, 1) # Convertimos a un array 2D con una columna
X_expandido = poly.fit_transform(X)
Código Completo
import matplotlib.pyplot as plt
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
# Número de muestras y características
n_muestras, n_caracteristicas = 100, 1
# Función objetivo y su derivada
funcion_objetivo = lambda x : (x - 4.2) ** 2 - 3.8 * x + 8
derivada = lambda x : 2 * (x - 4.2) - 3.8
# Generamos datos de entrada
X_valores = np.linspace(0, 12, n_muestras)
# El valor objetivo y se genera añadiendo ruido a f(x)
y_valores = funcion_objetivo(X_valores) + np.random.randn(n_muestras)
# Realizamos la expansión polinomial de X
transformador_polinomial = PolynomialFeatures(degree=2, interaction_only=False)
X_valores = X_valores.reshape(-1, 1)
X_expandido = transformador_polinomial.fit_transform(X_valores)
# Dividimos los datos: 80% para entrenamiento, 20% para prueba
punto_corte = int(0.8 * n_muestras)
X_entreno, y_entreno = X_expandido[:punto_corte], y_valores[:punto_corte]
X_prueba, y_prueba = X_expandido[punto_corte:], y_valores[punto_corte:]
# Creamos y entrenamos el modelo
modelo_regresion = LinearRegression(fit_intercept=True)
modelo_regresion.fit(X_entreno, y_entreno)
# Configuramos para no notación científica en impresiones
np.set_printoptions(suppress=True)
print("Coeficientes (W):", modelo_regresion.coef_)
print("Intercepción (b):", modelo_regresion.intercept_)
print("Puntuación del modelo expandido (cuanto más cerca de 1, mejor el ajuste):", modelo_regresion.score(X_prueba, y_prueba))
# Visualización
plt.scatter(X_valores, y_valores)
# Curva de la función original
plt.plot(X_valores, funcion_objetivo(X_valores), 'green', label="Función Original")
# Curva ajustada por el modelo
predicciones = modelo_regresion.predict(X_expandido)
plt.plot(X_expandido[:, 1], predicciones, 'red', label="Ajuste del Modelo")
# Añadimos título y etiquetas de ejes
plt.title('Caso de Ajuste con Regresión Polinomial')
plt.xlabel('x')
plt.ylabel('y')
# Añadimos leyenda
plt.legend()
plt.show()