2.1.4
Πολυωνυμική Παλινδρόμηση
Σύνοψη
- Η πολυωνυμική παλινδρόμηση επεκτείνει τα χαρακτηριστικά με δυνάμεις ώστε ένα γραμμικό μοντέλο να μπορεί να προσαρμοστεί σε μη γραμμικές σχέσεις.
- Το μοντέλο παραμένει γραμμικός συνδυασμός συντελεστών, διατηρώντας λύσεις κλειστής μορφής και ερμηνευσιμότητα.
- Υψηλότεροι βαθμοί αυξάνουν την εκφραστικότητα αλλά προκαλούν επίσης υπερπροσαρμογή, καθιστώντας σημαντικές την κανονικοποίηση και τη διασταυρωμένη επικύρωση.
- Η τυποποίηση των χαρακτηριστικών και η ρύθμιση του βαθμού μαζί με την ισχύ ποινής οδηγούν σε σταθερές προβλέψεις.
Εισαγωγή #
Αυτή η μέθοδος πρέπει να ερμηνεύεται μέσα από τις υποθέσεις της, τις συνθήκες των δεδομένων και τον τρόπο με τον οποίο οι επιλογές παραμέτρων επηρεάζουν τη γενίκευση.
Αναλυτική Επεξήγηση #
Μαθηματική Διατύπωση #
Δεδομένου \(\mathbf{x} = (x_1, \dots, x_m)\), κατασκευάζουμε ένα πολυωνυμικό διάνυσμα χαρακτηριστικών \(\phi(\mathbf{x})\) μέχρι βαθμό \(d\) και εφαρμόζουμε γραμμική παλινδρόμηση. Για \(m = 2\) και \(d = 2\),
$$ \phi(\mathbf{x}) = (1, x_1, x_2, x_1^2, x_1 x_2, x_2^2), $$και το μοντέλο γίνεται
$$ y = \mathbf{w}^\top \phi(\mathbf{x}). $$Καθώς το \(d\) αυξάνεται, ο αριθμός των όρων αυξάνεται ραγδαία, οπότε στην πράξη ξεκινάμε με βαθμό 2 ή 3 και τον συνδυάζουμε με κανονικοποίηση (π.χ., Ridge) όταν χρειάζεται.
Πειράματα σε Python #
Παρακάτω προσθέτουμε πολυωνυμικά χαρακτηριστικά τρίτου βαθμού και προσαρμόζουμε μια καμπύλη σε δεδομένα που δημιουργήθηκαν από κυβική συνάρτηση με θόρυβο.
from __future__ import annotations
import japanize_matplotlib
import matplotlib.pyplot as plt
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
def compare_polynomial_regression(
n_samples: int = 200,
degree: int = 3,
noise_scale: float = 2.0,
label_observations: str = "observations",
label_true_curve: str = "true curve",
label_linear: str = "linear regression",
label_poly_template: str = "degree-{degree} polynomial",
) -> tuple[float, float]:
"""Fit linear vs. polynomial regression to a cubic trend and plot the results.
Args:
n_samples: Number of synthetic samples generated along the curve.
degree: Polynomial degree used in the feature expansion.
noise_scale: Standard deviation of the Gaussian noise added to targets.
Returns:
A tuple containing the mean-squared errors of (linear, polynomial) models.
"""
japanize_matplotlib.japanize()
rng = np.random.default_rng(seed=42)
x: np.ndarray = np.linspace(-3.0, 3.0, n_samples, dtype=float)
y_true: np.ndarray = 0.5 * x**3 - 1.2 * x**2 + 2.0 * x + 1.5
y_noisy: np.ndarray = y_true + rng.normal(scale=noise_scale, size=x.shape)
X: np.ndarray = x[:, np.newaxis]
linear_model = LinearRegression()
linear_model.fit(X, y_noisy)
poly_model = make_pipeline(
PolynomialFeatures(degree=degree, include_bias=False),
LinearRegression(),
)
poly_model.fit(X, y_noisy)
grid: np.ndarray = np.linspace(-3.5, 3.5, 300, dtype=float)[:, np.newaxis]
linear_pred: np.ndarray = linear_model.predict(grid)
poly_pred: np.ndarray = poly_model.predict(grid)
true_curve: np.ndarray = (
0.5 * grid.ravel()**3 - 1.2 * grid.ravel()**2 + 2.0 * grid.ravel() + 1.5
)
linear_mse: float = float(mean_squared_error(y_noisy, linear_model.predict(X)))
poly_mse: float = float(mean_squared_error(y_noisy, poly_model.predict(X)))
fig, ax = plt.subplots(figsize=(10, 5))
ax.scatter(
X,
y_noisy,
s=20,
color="#ff7f0e",
alpha=0.6,
label=label_observations,
)
ax.plot(
grid,
true_curve,
color="#2ca02c",
linewidth=2,
label=label_true_curve,
)
ax.plot(
grid,
linear_pred,
color="#1f77b4",
linestyle="--",
linewidth=2,
label=label_linear,
)
ax.plot(
grid,
poly_pred,
color="#d62728",
linewidth=2,
label=label_poly_template.format(degree=degree),
)
ax.set_xlabel("input $x$")
ax.set_ylabel("output $y$")
ax.legend()
fig.tight_layout()
plt.show()
return linear_mse, poly_mse
degree = 3
linear_mse, poly_mse = compare_polynomial_regression(degree=degree)
print(f"Linear regression MSE: {linear_mse:.3f}")
print(f"Degree-{degree} polynomial regression MSE: {poly_mse:.3f}")

Ανάγνωση των αποτελεσμάτων #
- Η απλή γραμμική παλινδρόμηση χάνει την καμπυλότητα, ειδικά κοντά στο κέντρο, ενώ το κυβικό πολυώνυμο ακολουθεί στενά την πραγματική καμπύλη.
- Η αύξηση του βαθμού βελτιώνει την προσαρμογή στα δεδομένα εκπαίδευσης αλλά μπορεί να κάνει την εξωγραμμική πρόβλεψη ασταθή.
- Ο συνδυασμός πολυωνυμικών χαρακτηριστικών με κανονικοποιημένη παλινδρόμηση (π.χ., Ridge) μέσω pipeline βοηθά στον περιορισμό της υπερπροσαρμογής.
Αναφορές #
- Bishop, C. M. (2006). Pattern Recognition and Machine Learning. Springer.
- Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning. Springer.