Regresión polinomial

Nivel
Scikit Learn
Scikit Learn
Actualizado: 18/04/2026

¿Por qué regresión polinomial?

La regresión lineal asume que la relación entre las características y el objetivo es lineal. Sin embargo, muchos problemas del mundo real presentan relaciones curvilíneas que una recta no puede capturar adecuadamente.

La regresión polinomial extiende el modelo lineal añadiendo potencias de las características originales (x², x³, etc.) como nuevas variables. Aunque el modelo sigue siendo lineal en sus parámetros, puede representar relaciones no lineales entre los datos.

Por ejemplo, si tienes una variable x, la regresión polinomial de grado 2 genera las características [1, x, x²] y ajusta un modelo: y = w₀ + w₁·x + w₂·x².

PolynomialFeatures en Scikit-learn

El transformador PolynomialFeatures del módulo sklearn.preprocessing genera automáticamente las potencias y los productos cruzados de las características de entrada:

from sklearn.preprocessing import PolynomialFeatures
import numpy as np

# Datos de ejemplo con 2 características
X = np.array([[2, 3],
              [4, 1]])

# Grado 2: genera 1, x1, x2, x1², x1·x2, x2²
poly = PolynomialFeatures(degree=2, include_bias=True)
X_poly = poly.fit_transform(X)

print("Características originales:", X.shape)
print("Características polinomiales:", X_poly.shape)
print("Nombres:", poly.get_feature_names_out(['x1', 'x2']))
print(X_poly)

Con 2 características y grado 2 se generan 6 características nuevas.

Ejemplo básico: ajuste de curva sinusoidal

from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
import numpy as np

# Generar datos con relación no lineal
np.random.seed(42)
X = np.linspace(-3, 3, 100).reshape(-1, 1)
y = 0.5 * X.ravel()**3 - 2 * X.ravel()**2 + X.ravel() + np.random.normal(0, 1, 100)

# Regresión lineal estándar (grado 1)
lin_reg = LinearRegression()
lin_reg.fit(X, y)
r2_lineal = r2_score(y, lin_reg.predict(X))

# Regresión polinomial grado 3
poly = PolynomialFeatures(degree=3, include_bias=False)
X_poly = poly.fit_transform(X)
poly_reg = LinearRegression()
poly_reg.fit(X_poly, y)
r2_poly = r2_score(y, poly_reg.predict(X_poly))

print(f"R² lineal (grado 1): {r2_lineal:.4f}")
print(f"R² polinomial (grado 3): {r2_poly:.4f}")

Pipeline: PolynomialFeatures + LinearRegressión

La práctica recomendada es encadenar PolynomialFeatures con LinearRegressión usando un Pipeline. Esto evita la fuga de información y facilita la búsqueda de hiperparámetros:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score, mean_squared_error
import numpy as np

# Datos de entrenamiento
np.random.seed(42)
X = np.linspace(0, 10, 200).reshape(-1, 1)
y = 2 * X.ravel()**2 - 5 * X.ravel() + 3 + np.random.normal(0, 5, 200)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Pipeline con grado 2
pipeline = Pipeline([
    ('poly', PolynomialFeatures(degree=2, include_bias=False)),
    ('reg', LinearRegression())
])

pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)

print(f"R²: {r2_score(y_test, y_pred):.4f}")
print(f"MSE: {mean_squared_error(y_test, y_pred):.4f}")

Efecto del grado: sobreajuste

Aumentar el grado del polinomio permite ajustar mejor los datos de entrenamiento, pero puede llevar al sobreajuste. Hay que evaluar el rendimiento en datos de prueba:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
import numpy as np

np.random.seed(42)
X = np.linspace(0, 5, 100).reshape(-1, 1)
y = np.sin(X.ravel()) + np.random.normal(0, 0.1, 100)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

print(f"{'Grado':>6} {'R² Train':>10} {'R² Test':>10}")
for grado in [1, 2, 3, 5, 8, 12]:
    pipeline = Pipeline([
        ('poly', PolynomialFeatures(degree=grado)),
        ('reg', LinearRegression())
    ])
    pipeline.fit(X_train, y_train)
    r2_train = r2_score(y_train, pipeline.predict(X_train))
    r2_test = r2_score(y_test, pipeline.predict(X_test))
    print(f"{grado:>6}  {r2_train:>10.4f}  {r2_test:>10.4f}")

Para grados altos, el R² de entrenamiento se acerca a 1.0 pero el de prueba empeora: señal clara de sobreajuste.

Búsqueda del grado óptimo con validación cruzada

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
import numpy as np

np.random.seed(42)
X = np.linspace(0, 5, 150).reshape(-1, 1)
y = np.sin(X.ravel()) + np.random.normal(0, 0.15, 150)

print(f"{'Grado':>6} {'CV R² (media)':>15} {'CV R² (std)':>12}")
for grado in [1, 2, 3, 4, 5, 6]:
    pipeline = Pipeline([
        ('poly', PolynomialFeatures(degree=grado)),
        ('reg', LinearRegression())
    ])
    scores = cross_val_score(pipeline, X, y, cv=5, scoring='r2')
    print(f"{grado:>6}  {scores.mean():>15.4f}  {scores.std():>12.4f}")

El grado con mayor R² en validación cruzada y menor desviación estándar es el más adecuado.

Combinación con Ridge para reducir sobreajuste

Al usar grados altos, combinar PolynomialFeatures con Ridge reduce el sobreajuste:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
import numpy as np

np.random.seed(42)
X = np.linspace(0, 5, 100).reshape(-1, 1)
y = np.sin(X.ravel()) + np.random.normal(0, 0.1, 100)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

pipeline_ridge = Pipeline([
    ('poly', PolynomialFeatures(degree=10)),
    ('scaler', StandardScaler()),
    ('ridge', Ridge(alpha=1.0))
])

pipeline_ridge.fit(X_train, y_train)
print(f"R² Test (grado 10 + Ridge): {r2_score(y_test, pipeline_ridge.predict(X_test)):.4f}")

Resumen

| Técnica | Cuándo usarla | |---------|---------------| | Regresión lineal (grado 1) | Relación claramente lineal | | Regresión polinomial (grado 2-4) | Relación curvilínea moderada | | Regresión polinomial + Ridge | Grados altos con riesgo de sobreajuste | | Validación cruzada para elegir grado | Siempre que no haya conocimiento previo del grado óptimo |

La regresión polinomial es una herramienta potente para modelar relaciones no lineales sin necesidad de cambiar el algoritmo de aprendizaje, simplemente transformando las características de entrada.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Scikit Learn es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Scikit Learn

Explora más contenido relacionado con Scikit Learn y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Entender cuándo la regresión lineal es insuficiente y se necesita un modelo polinomial. Usar PolynomialFeatures para generar características de orden superior. Combinar PolynomialFeatures con LinearRegressión en un Pipeline. Detectar sobreajuste al aumentar el grado polinomial. Evaluar modelos polinomiales con métricas de regresión y validación cruzada.